Add fragment light LUT support
This commit is contained in:
parent
a0345263df
commit
0922a64ed3
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "lightlut.h"
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Material
|
// Material
|
||||||
@ -42,8 +43,8 @@ enum
|
|||||||
C3DF_LightEnv_MtlDirty = BIT(1),
|
C3DF_LightEnv_MtlDirty = BIT(1),
|
||||||
C3DF_LightEnv_LCDirty = BIT(2),
|
C3DF_LightEnv_LCDirty = BIT(2),
|
||||||
|
|
||||||
#define C3DF_LightEnv_LutDirty(n) BIT(27+(n))
|
#define C3DF_LightEnv_LutDirty(n) BIT(26+(n))
|
||||||
#define C3DF_LightEnv_LutDirtyAll (0x1F<<27)
|
#define C3DF_LightEnv_LutDirtyAll (0x3F<<26)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct C3D_LightEnv_t
|
struct C3D_LightEnv_t
|
||||||
@ -51,7 +52,7 @@ struct C3D_LightEnv_t
|
|||||||
void (* Update)(C3D_LightEnv* env);
|
void (* Update)(C3D_LightEnv* env);
|
||||||
void (* Dirty)(C3D_LightEnv* env);
|
void (* Dirty)(C3D_LightEnv* env);
|
||||||
u32 flags;
|
u32 flags;
|
||||||
void* luts[5];
|
C3D_LightLut* luts[6];
|
||||||
float ambient[3];
|
float ambient[3];
|
||||||
C3D_Light* lights[8];
|
C3D_Light* lights[8];
|
||||||
C3D_LightEnvConf conf;
|
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_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl);
|
||||||
void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b);
|
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
|
// Light
|
||||||
@ -100,7 +102,7 @@ struct C3D_Light_t
|
|||||||
{
|
{
|
||||||
u16 flags, id;
|
u16 flags, id;
|
||||||
C3D_LightEnv* parent;
|
C3D_LightEnv* parent;
|
||||||
void *lut_SP, *lut_DA;
|
C3D_LightLut *lut_SP, *lut_DA;
|
||||||
float color[3];
|
float color[3];
|
||||||
C3D_LightConf conf;
|
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_LightShadowEnable(C3D_Light* light, bool enable);
|
||||||
void C3D_LightSpotEnable(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_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_LightDistAttnEnable(C3D_Light* light, bool enable);
|
||||||
void C3D_LightDistAttn(C3D_Light* light, float bias, float scale);
|
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;
|
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)
|
void C3D_LightDistAttnEnable(C3D_Light* light, bool enable)
|
||||||
{
|
{
|
||||||
C3Di_EnableCommon(light, enable, GPU_LC1_ATTNBIT(light->id));
|
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->conf.distAttnScale = f32tof20(scale);
|
||||||
light->flags |= C3DF_Light_Dirty;
|
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;
|
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)
|
static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -57,8 +65,9 @@ static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
|||||||
{
|
{
|
||||||
for (i = 0; i < 5; i ++)
|
for (i = 0; i < 5; i ++)
|
||||||
{
|
{
|
||||||
|
static const u8 lutIds[] = { 0, 1, 3, 4, 5, 6 };
|
||||||
if (!(env->flags & C3DF_LightEnv_LutDirty(i))) continue;
|
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;
|
env->flags &= ~C3DF_LightEnv_LutDirtyAll;
|
||||||
@ -84,13 +93,13 @@ static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
|||||||
|
|
||||||
if (light->flags & C3DF_Light_SPDirty)
|
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;
|
light->flags &= ~C3DF_Light_SPDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light->flags & C3DF_Light_DADirty)
|
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;
|
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->ambient[2] = r;
|
||||||
env->flags |= C3DF_LightEnv_MtlDirty;
|
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