citro3d/source/light.c

136 lines
3.2 KiB
C

#include <string.h>
#include "context.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;
light->conf.config = BIT(0);
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.0);
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 ((*var & bit) ^ 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));
}
void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z)
{
C3Di_EnableCommon(light, true, GPU_LC1_SPOTBIT(light->id));
// TODO
light->flags |= C3DF_Light_Dirty;
}
void C3D_LightDistAttnEnable(C3D_Light* light, bool enable)
{
C3Di_EnableCommon(light, enable, GPU_LC1_ATTNBIT(light->id));
}
void C3D_LightDistAttn(C3D_Light* light, float bias, float scale)
{
C3Di_EnableCommon(light, true, GPU_LC1_ATTNBIT(light->id));
light->conf.distAttnBias = f32tof20(bias);
light->conf.distAttnScale = f32tof20(scale);
light->flags |= C3DF_Light_Dirty;
}