citro3d/source/light.c
2017-02-09 19:45:33 +01:00

156 lines
3.8 KiB
C

#include "internal.h"
void C3Di_LightMtlBlend(C3D_Light* light)
{
int i;
C3D_Material* mtl = &light->parent->material;
C3D_LightMatConf* conf = &light->conf.material;
memset(conf, 0, sizeof(*conf));
for (i = 0; i < 3; i ++)
{
conf->specular0 |= ((u32)(255*(mtl->specular0[i]*light->color[i]))) << (i*10);
conf->specular1 |= ((u32)(255*(mtl->specular1[i]*light->color[i]))) << (i*10);
conf->diffuse |= ((u32)(255*(mtl->diffuse[i] *light->color[i]))) << (i*10);
conf->ambient |= ((u32)(255*(mtl->ambient[i] *light->color[i]))) << (i*10);
}
}
int C3D_LightInit(C3D_Light* light, C3D_LightEnv* env)
{
int i;
memset(light, 0, sizeof(*light));
for (i = 0; i < 8; i ++)
if (!env->lights[i])
break;
if (i == 8) return -1;
env->lights[i] = light;
light->flags = C3DF_Light_Enabled | C3DF_Light_Dirty | C3DF_Light_MatDirty;
light->id = i;
light->parent = env;
env->flags |= C3DF_LightEnv_LCDirty;
return i;
}
void C3D_LightEnable(C3D_Light* light, bool enable)
{
if ((light->flags & C3DF_Light_Enabled) == (enable?C3DF_Light_Enabled:0))
return;
if (enable)
light->flags |= C3DF_Light_Enabled;
else
light->flags &= ~C3DF_Light_Enabled;
light->parent->flags |= C3DF_LightEnv_LCDirty;
}
void C3D_LightTwoSideDiffuse(C3D_Light* light, bool enable)
{
if (enable)
light->conf.config |= BIT(1);
else
light->conf.config &= ~BIT(1);
light->flags |= C3DF_Light_Dirty;
}
void C3D_LightGeoFactor(C3D_Light* light, int id, bool enable)
{
id = 2 + (id&1);
if (enable)
light->conf.config |= BIT(id);
else
light->conf.config &= ~BIT(id);
light->flags |= C3DF_Light_Dirty;
}
void C3D_LightColor(C3D_Light* light, float r, float g, float b)
{
light->color[0] = b;
light->color[1] = g;
light->color[2] = r;
light->flags |= C3DF_Light_MatDirty;
}
void C3D_LightPosition(C3D_Light* light, C3D_FVec* pos)
{
// Enable/disable positional light depending on W coordinate
light->conf.config &= ~BIT(0);
light->conf.config |= (pos->w == 0.0f);
light->conf.position[0] = f32tof16(pos->x);
light->conf.position[1] = f32tof16(pos->y);
light->conf.position[2] = f32tof16(pos->z);
light->flags |= C3DF_Light_Dirty;
}
static void C3Di_EnableCommon(C3D_Light* light, bool enable, u32 bit)
{
C3D_LightEnv* env = light->parent;
u32* var = &env->conf.config[1];
if (enable == !(*var & bit))
return;
if (!enable)
*var |= bit;
else
*var &= ~bit;
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightShadowEnable(C3D_Light* light, bool enable)
{
C3Di_EnableCommon(light, enable, GPU_LC1_SHADOWBIT(light->id));
}
void C3D_LightSpotEnable(C3D_Light* light, bool enable)
{
C3Di_EnableCommon(light, enable, GPU_LC1_SPOTBIT(light->id));
}
static inline u16 floattofix2_11(float x)
{
return (u16)((s32)(x * (1U<<11)) & 0x1FFF);
}
void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z)
{
C3Di_EnableCommon(light, true, GPU_LC1_SPOTBIT(light->id));
C3D_FVec vec = FVec3_New(-x, -y, -z);
vec = FVec3_Normalize(vec);
light->conf.spotDir[0] = floattofix2_11(vec.x);
light->conf.spotDir[1] = floattofix2_11(vec.y);
light->conf.spotDir[2] = floattofix2_11(vec.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));
}
void C3D_LightDistAttn(C3D_Light* light, C3D_LightLutDA* lut)
{
bool hasLut = lut != NULL;
C3Di_EnableCommon(light, hasLut, GPU_LC1_ATTNBIT(light->id));
if (!hasLut) return;
light->conf.distAttnBias = f32tof20(lut->bias);
light->conf.distAttnScale = f32tof20(lut->scale);
light->lut_DA = &lut->lut;
light->flags |= C3DF_Light_Dirty | C3DF_Light_DADirty;
}