citro3d/source/lightenv.c

286 lines
7.3 KiB
C
Raw Permalink Normal View History

2017-02-09 04:30:25 +01:00
#include "internal.h"
static void C3Di_LightEnvMtlBlend(C3D_LightEnv* env)
{
int i;
C3D_Material* mtl = &env->material;
u32 color = 0;
for (i = 0; i < 3; i ++)
{
int v = 255*(mtl->emission[i] + mtl->ambient[i]*env->ambient[i]);
if (v < 0) v = 0;
else if (v > 255) v = 255;
color |= v << (i*10);
}
env->conf.ambient = color;
}
2015-09-15 23:02:35 +02:00
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_LightEnvSelectLayer(C3D_LightEnv* env)
{
static const u8 layer_enabled[] =
{
BIT(GPU_LUT_D0) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA),
BIT(GPU_LUT_FR) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA),
BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_DA),
BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_FR) | BIT(GPU_LUT_DA),
0xFF &~ BIT(GPU_LUT_FR),
0xFF &~ BIT(GPU_LUT_D1),
0xFF &~ (BIT(GPU_LUT_RB) | BIT(GPU_LUT_RG)),
};
u32 reg = ~env->conf.config[1];
if (reg & (0xFF<< 8)) reg |= GPU_LC1_LUTBIT(GPU_LUT_SP);
if (reg & (0xFF<<24)) reg |= GPU_LC1_LUTBIT(GPU_LUT_DA);
reg = (reg >> 16) & 0xFF;
int i = 7;
if (!(env->flags & C3DF_LightEnv_IsCP_Any))
for (i = 0; i < 7; i ++)
if ((layer_enabled[i] & reg) == reg) // Check if the layer supports all LUTs we need
break;
env->conf.config[0] = (env->conf.config[0] &~ (0xF<<4)) | (GPU_LIGHT_ENV_LAYER_CONFIG(i)<<4);
}
void C3Di_LightEnvUpdate(C3D_LightEnv* env)
{
int i;
C3D_LightEnvConf* conf = &env->conf;
if (env->flags & C3DF_LightEnv_LCDirty)
{
conf->numLights = 0;
conf->permutation = 0;
for (i = 0; i < 8; i ++)
{
C3D_Light* light = env->lights[i];
if (!light) continue;
if (!(light->flags & C3DF_Light_Enabled)) continue;
conf->permutation |= GPU_LIGHTPERM(conf->numLights++, i);
}
if (conf->numLights > 0) conf->numLights --;
env->flags &= ~C3DF_LightEnv_LCDirty;
env->flags |= C3DF_LightEnv_Dirty;
}
if (env->flags & C3DF_LightEnv_MtlDirty)
{
C3Di_LightEnvMtlBlend(env);
env->flags &= ~C3DF_LightEnv_MtlDirty;
env->flags |= C3DF_LightEnv_Dirty;
}
if (env->flags & C3DF_LightEnv_Dirty)
{
C3Di_LightEnvSelectLayer(env);
GPUCMD_AddWrite(GPUREG_LIGHTING_AMBIENT, conf->ambient);
GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_NUM_LIGHTS, (u32*)&conf->numLights, 3);
GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_LUTINPUT_ABS, (u32*)&conf->lutInput, 3);
GPUCMD_AddWrite(GPUREG_LIGHTING_LIGHT_PERMUTATION, conf->permutation);
env->flags &= ~C3DF_LightEnv_Dirty;
}
if (env->flags & C3DF_LightEnv_LutDirtyAll)
{
2016-03-25 23:42:15 +01:00
for (i = 0; i < 6; i ++)
{
2015-09-15 23:02:35 +02:00
static const u8 lutIds[] = { 0, 1, 3, 4, 5, 6 };
if (!(env->flags & C3DF_LightEnv_LutDirty(i))) continue;
2015-09-15 23:02:35 +02:00
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_COMMON, (u32)lutIds[i], 0), env->luts[i]);
}
env->flags &= ~C3DF_LightEnv_LutDirtyAll;
}
for (i = 0; i < 8; i ++)
{
C3D_Light* light = env->lights[i];
if (!light) continue;
if (light->flags & C3DF_Light_MatDirty)
{
C3Di_LightMtlBlend(light);
light->flags &= ~C3DF_Light_MatDirty;
light->flags |= C3DF_Light_Dirty;
}
if (light->flags & C3DF_Light_Dirty)
{
GPUCMD_AddIncrementalWrites(GPUREG_LIGHT0_SPECULAR0 + i*0x10, (u32*)&light->conf, 12);
light->flags &= ~C3DF_Light_Dirty;
}
if (light->flags & C3DF_Light_SPDirty)
{
2015-09-15 23:02:35 +02:00
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_SP, i, 0), light->lut_SP);
light->flags &= ~C3DF_Light_SPDirty;
}
if (light->flags & C3DF_Light_DADirty)
{
2015-09-15 23:02:35 +02:00
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_DA, i, 0), light->lut_DA);
light->flags &= ~C3DF_Light_DADirty;
}
}
}
void C3Di_LightEnvDirty(C3D_LightEnv* env)
{
env->flags |= C3DF_LightEnv_Dirty;
int i;
2015-11-09 00:08:51 +01:00
for (i = 0; i < 6; i ++)
if (env->luts[i])
env->flags |= C3DF_LightEnv_LutDirty(i);
for (i = 0; i < 8; i ++)
{
C3D_Light* light = env->lights[i];
if (!light) continue;
light->flags |= C3DF_Light_Dirty;
if (light->lut_SP)
light->flags |= C3DF_Light_SPDirty;
if (light->lut_DA)
light->flags |= C3DF_Light_DADirty;
}
}
void C3D_LightEnvInit(C3D_LightEnv* env)
{
memset(env, 0, sizeof(*env));
env->flags = C3DF_LightEnv_Dirty;
env->ambient[0] = env->ambient[1] = env->ambient[2] = 1.0f;
env->conf.config[0] = (4<<8) | BIT(27) | BIT(31);
env->conf.config[1] = ~0;
2017-03-30 23:42:29 +02:00
env->conf.lutInput.select = GPU_LIGHTLUTINPUT(GPU_LUT_SP, GPU_LUTINPUT_SP);
env->conf.lutInput.abs = 0x2222222;
}
void C3D_LightEnvBind(C3D_LightEnv* env)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
if (ctx->lightEnv == env)
return;
ctx->flags |= C3DiF_LightEnv;
ctx->lightEnv = env;
}
void C3D_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl)
{
int i;
memcpy(&env->material, mtl, sizeof(*mtl));
env->flags |= C3DF_LightEnv_MtlDirty;
for (i = 0; i < 8; i ++)
{
C3D_Light* light = env->lights[i];
if (light) light->flags |= C3DF_Light_MatDirty;
}
}
void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b)
{
env->ambient[0] = b;
env->ambient[1] = g;
env->ambient[2] = r;
env->flags |= C3DF_LightEnv_MtlDirty;
}
2015-09-15 23:02:35 +02:00
void C3D_LightEnvLut(C3D_LightEnv* env, GPU_LIGHTLUTID lutId, GPU_LIGHTLUTINPUT input, bool negative, C3D_LightLut* lut)
2015-09-15 23:02:35 +02:00
{
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->conf.config[1] |= GPU_LC1_LUTBIT(lutId);
2015-09-15 23:02:35 +02:00
env->luts[id] = NULL;
}
2015-09-15 23:02:35 +02:00
}
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 (negative)
2015-09-15 23:02:35 +02:00
env->conf.lutInput.abs |= absbit;
env->flags |= C3DF_LightEnv_Dirty;
if (input == GPU_LUTINPUT_CP)
env->flags |= C3DF_LightEnv_IsCP(lutId);
else
env->flags &= ~C3DF_LightEnv_IsCP(lutId);
2015-09-15 23:02:35 +02:00
}
void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector)
{
env->conf.config[0] &= ~(3<<2);
env->conf.config[0] |= (selector&3)<<2;
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode)
{
env->conf.config[0] &= ~(3<<28);
env->conf.config[0] |= (mode&3)<<28;
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit)
{
env->conf.config[0] &= ~(3<<22);
env->conf.config[0] |= (texUnit&3)<<22;
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvBumpNormalZ(C3D_LightEnv *env, bool usez) {
if (usez)
env->conf.config[0] |= BIT(30);
else
env->conf.config[0] &= ~BIT(30);
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode)
{
mode &= 0xF<<16;
if (mode & (GPU_SHADOW_PRIMARY | GPU_SHADOW_SECONDARY | GPU_SHADOW_ALPHA))
mode |= BIT(0);
env->conf.config[0] &= ~((0xF<<16) | BIT(0));
env->conf.config[0] |= mode;
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit)
{
env->conf.config[0] &= ~(3<<24);
env->conf.config[0] |= (texUnit&3)<<24;
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp)
{
if (clamp)
env->conf.config[0] |= BIT(27);
else
env->conf.config[0] &= ~BIT(27);
env->flags |= C3DF_LightEnv_Dirty;
}