Add fragment light LUT support
This commit is contained in:
parent
a0345263df
commit
0922a64ed3
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "lightlut.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Material
|
||||
@ -42,8 +43,8 @@ enum
|
||||
C3DF_LightEnv_MtlDirty = BIT(1),
|
||||
C3DF_LightEnv_LCDirty = BIT(2),
|
||||
|
||||
#define C3DF_LightEnv_LutDirty(n) BIT(27+(n))
|
||||
#define C3DF_LightEnv_LutDirtyAll (0x1F<<27)
|
||||
#define C3DF_LightEnv_LutDirty(n) BIT(26+(n))
|
||||
#define C3DF_LightEnv_LutDirtyAll (0x3F<<26)
|
||||
};
|
||||
|
||||
struct C3D_LightEnv_t
|
||||
@ -51,7 +52,7 @@ struct C3D_LightEnv_t
|
||||
void (* Update)(C3D_LightEnv* env);
|
||||
void (* Dirty)(C3D_LightEnv* env);
|
||||
u32 flags;
|
||||
void* luts[5];
|
||||
C3D_LightLut* luts[6];
|
||||
float ambient[3];
|
||||
C3D_Light* lights[8];
|
||||
C3D_LightEnvConf conf;
|
||||
@ -63,6 +64,7 @@ void C3D_LightEnvBind(C3D_LightEnv* env);
|
||||
|
||||
void C3D_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl);
|
||||
void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b);
|
||||
void C3D_LightEnvLut(C3D_LightEnv* env, int lutId, int input, bool abs, C3D_LightLut* lut);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Light
|
||||
@ -100,7 +102,7 @@ struct C3D_Light_t
|
||||
{
|
||||
u16 flags, id;
|
||||
C3D_LightEnv* parent;
|
||||
void *lut_SP, *lut_DA;
|
||||
C3D_LightLut *lut_SP, *lut_DA;
|
||||
float color[3];
|
||||
C3D_LightConf conf;
|
||||
};
|
||||
@ -114,5 +116,7 @@ void C3D_LightPosition(C3D_Light* light, C3D_FVec* pos);
|
||||
void C3D_LightShadowEnable(C3D_Light* light, bool enable);
|
||||
void C3D_LightSpotEnable(C3D_Light* light, bool enable);
|
||||
void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z);
|
||||
void C3D_LightSpotLut(C3D_Light* light, C3D_LightLut* lut);
|
||||
void C3D_LightDistAttnEnable(C3D_Light* light, bool enable);
|
||||
void C3D_LightDistAttn(C3D_Light* light, float bias, float scale);
|
||||
void C3D_LightDistAttnLut(C3D_Light* light, C3D_LightLut* lut);
|
||||
|
15
include/c3d/lightlut.h
Normal file
15
include/c3d/lightlut.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <math.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 data[256];
|
||||
} C3D_LightLut;
|
||||
|
||||
typedef float (* C3D_LightLutFunc)(float x, float param);
|
||||
|
||||
void LightLut_FromArray(C3D_LightLut* lut, float* data);
|
||||
void LightLut_FromFunc(C3D_LightLut* lut, C3D_LightLutFunc func, float param, bool negative);
|
||||
|
||||
#define LightLut_Phong(lut, shininess) LightLut_FromFunc((lut), powf, (shininess), false)
|
@ -120,6 +120,15 @@ void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z)
|
||||
light->flags |= C3DF_Light_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightSpotLut(C3D_Light* light, C3D_LightLut* lut)
|
||||
{
|
||||
bool hasLut = lut != NULL;
|
||||
C3Di_EnableCommon(light, hasLut, GPU_LC1_SPOTBIT(light->id));
|
||||
light->lut_SP = lut;
|
||||
if (hasLut)
|
||||
light->flags |= C3DF_Light_SPDirty;
|
||||
}
|
||||
|
||||
void C3D_LightDistAttnEnable(C3D_Light* light, bool enable)
|
||||
{
|
||||
C3Di_EnableCommon(light, enable, GPU_LC1_ATTNBIT(light->id));
|
||||
@ -132,3 +141,12 @@ void C3D_LightDistAttn(C3D_Light* light, float bias, float scale)
|
||||
light->conf.distAttnScale = f32tof20(scale);
|
||||
light->flags |= C3DF_Light_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightDistAttnLut(C3D_Light* light, C3D_LightLut* lut)
|
||||
{
|
||||
bool hasLut = lut != NULL;
|
||||
C3Di_EnableCommon(light, hasLut, GPU_LC1_ATTNBIT(light->id));
|
||||
light->lut_DA = lut;
|
||||
if (hasLut)
|
||||
light->flags |= C3DF_Light_DADirty;
|
||||
}
|
||||
|
@ -16,6 +16,14 @@ static void C3Di_LightEnvMtlBlend(C3D_LightEnv* env)
|
||||
env->conf.ambient = color;
|
||||
}
|
||||
|
||||
static void C3Di_LightLutUpload(u32 config, C3D_LightLut* lut)
|
||||
{
|
||||
int i;
|
||||
GPUCMD_AddWrite(GPUREG_LIGHTING_LUT_INDEX, config);
|
||||
for (i = 0; i < 256; i += 8)
|
||||
GPUCMD_AddWrites(GPUREG_LIGHTING_LUT_DATA0, &lut->data[i], 8);
|
||||
}
|
||||
|
||||
static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
||||
{
|
||||
int i;
|
||||
@ -57,8 +65,9 @@ static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
||||
{
|
||||
for (i = 0; i < 5; i ++)
|
||||
{
|
||||
static const u8 lutIds[] = { 0, 1, 3, 4, 5, 6 };
|
||||
if (!(env->flags & C3DF_LightEnv_LutDirty(i))) continue;
|
||||
// TODO: Upload LUT
|
||||
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_COMMON, (u32)lutIds[i], 0), env->luts[i]);
|
||||
}
|
||||
|
||||
env->flags &= ~C3DF_LightEnv_LutDirtyAll;
|
||||
@ -84,13 +93,13 @@ static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
||||
|
||||
if (light->flags & C3DF_Light_SPDirty)
|
||||
{
|
||||
// TODO: Upload LUT
|
||||
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_SP, i, 0), light->lut_SP);
|
||||
light->flags &= ~C3DF_Light_SPDirty;
|
||||
}
|
||||
|
||||
if (light->flags & C3DF_Light_DADirty)
|
||||
{
|
||||
// TODO: Upload LUT
|
||||
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_DA, i, 0), light->lut_DA);
|
||||
light->flags &= ~C3DF_Light_DADirty;
|
||||
}
|
||||
}
|
||||
@ -161,3 +170,29 @@ void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b)
|
||||
env->ambient[2] = r;
|
||||
env->flags |= C3DF_LightEnv_MtlDirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvLut(C3D_LightEnv* env, int lutId, int input, bool abs, C3D_LightLut* lut)
|
||||
{
|
||||
static const s8 ids[] = { 0, 1, -1, 2, 3, 4, 5, -1 };
|
||||
int id = ids[lutId];
|
||||
if (id >= 0)
|
||||
{
|
||||
env->luts[id] = lut;
|
||||
if (lut)
|
||||
{
|
||||
env->conf.config[1] &= ~GPU_LC1_LUTBIT(lutId);
|
||||
env->flags |= C3DF_LightEnv_LutDirty(id);
|
||||
} else
|
||||
env->luts[id] = NULL;
|
||||
}
|
||||
|
||||
env->conf.lutInput.select &= ~GPU_LIGHTLUTINPUT(lutId, 0xF);
|
||||
env->conf.lutInput.select |= GPU_LIGHTLUTINPUT(lutId, input);
|
||||
|
||||
u32 absbit = 1 << (lutId*4 + 1);
|
||||
env->conf.lutInput.abs &= ~absbit;
|
||||
if (!abs)
|
||||
env->conf.lutInput.abs |= absbit;
|
||||
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
46
source/lightlut.c
Normal file
46
source/lightlut.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
void LightLut_FromArray(C3D_LightLut* lut, float* data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i ++)
|
||||
{
|
||||
float in = data[i], diff = data[i+256];
|
||||
|
||||
u32 val = 0;
|
||||
if (in > 0.0)
|
||||
{
|
||||
in *= 0x1000;
|
||||
val = (in < 0x1000) ? (u32)in : 0xFFF;
|
||||
}
|
||||
|
||||
u32 val2 = 0;
|
||||
if (diff != 0.0)
|
||||
{
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = -diff;
|
||||
val2 = 0x800;
|
||||
}
|
||||
diff *= 0x800;
|
||||
val2 |= (diff < 0x800) ? (u32)diff : 0x7FF;
|
||||
}
|
||||
|
||||
lut->data[i] = val | (val2 << 12);
|
||||
}
|
||||
}
|
||||
|
||||
void LightLut_FromFunc(C3D_LightLut* lut, C3D_LightLutFunc func, float param, bool negative)
|
||||
{
|
||||
int i;
|
||||
float data[512];
|
||||
memset(data, 0, sizeof(data));
|
||||
int start = negative ? (-127) : 0;
|
||||
for (i = start; i < 128; i ++)
|
||||
{
|
||||
data[i & 0xFF] = func((float)i / 127.0f, param);
|
||||
if (i != start) data[(i & 0xFF) + 255] = data[i & 0xFF] - data[(i-1) & 0xFF];
|
||||
}
|
||||
LightLut_FromArray(lut, data);
|
||||
}
|
Loading…
Reference in New Issue
Block a user