Add fragment light LUT support

This commit is contained in:
fincs 2015-09-15 23:02:35 +02:00
parent a0345263df
commit 0922a64ed3
5 changed files with 125 additions and 7 deletions

View File

@ -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
View 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)

View File

@ -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;
}

View File

@ -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
View 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);
}