diff --git a/include/c3d/fog.h b/include/c3d/fog.h index 5c2f113..b4e62c2 100644 --- a/include/c3d/fog.h +++ b/include/c3d/fog.h @@ -7,6 +7,12 @@ typedef struct u32 data[128]; } C3D_FogLut; +typedef struct +{ + u32 diff[8]; + u32 color[8]; +} C3D_GasLut; + static inline float FogLut_CalcZ(float depth, float near, float far) { return far*near/(depth*(far-near)+near); @@ -18,3 +24,14 @@ void FogLut_Exp(C3D_FogLut* lut, float density, float gradient, float near, floa void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip); void C3D_FogColor(u32 color); void C3D_FogLutBind(C3D_FogLut* lut); + +void GasLut_FromArray(C3D_GasLut* lut, const u32 data[9]); + +void C3D_GasAttn(float value); +void C3D_GasAccMax(float value); +void C3D_GasDeltaZ(float value); +void C3D_GasLightPlanar(float min, float max, float attn); +void C3D_GasLightView(float min, float max, float attn); +void C3D_GasLightDirection(float dotp); +void C3D_GasLutInput(GPU_GASLUTINPUT input); +void C3D_GasLutBind(C3D_GasLut* lut); diff --git a/source/base.c b/source/base.c index aadd007..b606cb1 100644 --- a/source/base.c +++ b/source/base.c @@ -36,6 +36,11 @@ __attribute__((weak)) void C3Di_ProcTexDirty(C3D_Context* ctx) (void)ctx; } +__attribute__((weak)) void C3Di_GasUpdate(C3D_Context* ctx) +{ + (void)ctx; +} + static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param) { C3D_Context* ctx = C3Di_GetContext(); @@ -51,7 +56,7 @@ static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param) { ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_FrameBuf | C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode - | C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv; + | C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv | C3DiF_Gas; C3Di_DirtyUniforms(GPU_VERTEX_SHADER); C3Di_DirtyUniforms(GPU_GEOMETRY_SHADER); @@ -61,6 +66,8 @@ static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param) C3D_LightEnv* env = ctx->lightEnv; if (ctx->fogLut) ctx->flags |= C3DiF_FogLut; + if (ctx->gasLut) + ctx->flags |= C3DiF_GasLut; if (env) C3Di_LightEnvDirty(env); C3Di_ProcTexDirty(ctx); @@ -233,9 +240,14 @@ void C3Di_UpdateContext(void) if (ctx->flags & C3DiF_TexStatus) { ctx->flags &= ~C3DiF_TexStatus; - GPUCMD_AddWrite(GPUREG_TEXUNIT_CONFIG, ctx->texConfig); + GPUCMD_AddMaskedWrite(GPUREG_TEXUNIT_CONFIG, 0xB, ctx->texConfig); + // Clear texture cache if requested *after* configuring texture units + if (ctx->texConfig & BIT(16)) + { + ctx->texConfig &= ~BIT(16); + GPUCMD_AddMaskedWrite(GPUREG_TEXUNIT_CONFIG, 0x4, BIT(16)); + } GPUCMD_AddWrite(GPUREG_TEXUNIT0_SHADOW, ctx->texShadow); - ctx->texConfig &= ~BIT(16); // Remove clear-texture-cache flag } if (ctx->flags & (C3DiF_ProcTex | C3DiF_ProcTexColorLut | C3DiF_ProcTexLutAll)) @@ -249,7 +261,7 @@ void C3Di_UpdateContext(void) GPUCMD_AddWrite(GPUREG_FOG_COLOR, ctx->fogClr); } - if (ctx->flags & C3DiF_FogLut) + if ((ctx->flags & C3DiF_FogLut) && (ctx->texEnvBuf&7) != GPU_NO_FOG) { ctx->flags &= ~C3DiF_FogLut; if (ctx->fogLut) @@ -259,6 +271,9 @@ void C3Di_UpdateContext(void) } } + if ((ctx->texEnvBuf&7) == GPU_GAS) + C3Di_GasUpdate(ctx); + if (ctx->flags & C3DiF_TexEnvAll) { for (i = 0; i < 6; i ++) diff --git a/source/gas.c b/source/gas.c new file mode 100644 index 0000000..8fea5a4 --- /dev/null +++ b/source/gas.c @@ -0,0 +1,160 @@ +#include "internal.h" + +static inline u32 calc_diff(u32 a, u32 b, int pos) +{ + float fa = ((a>>pos)&0xFF)/255.0f; + float fb = ((b>>pos)&0xFF)/255.0f; + float x = fb-fa; + u32 diff = 0; + if (x < 0) + { + diff = 0x80; + x = -x; + } + diff |= (u32)(x*0x7F); + return diff< 1.0f) x = 1.0f; + return ((u32)x*255)<color[i] = data[i]; + if (i > 0) + lut->diff[i-1] = color_diff(data[i-1], data[i]); + } +} + +void C3D_GasAttn(float value) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasAttn = f32tof16(value); +} + +void C3D_GasAccMax(float value) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasAccMax = f32tof16(1.0f / value); +} + +void C3D_GasDeltaZ(float value) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasDeltaZ = (u32)(value*0x100) & 0xFFFFFF; + ctx->gasDeltaZ |= 2<<24; +} + +void C3D_GasLightPlanar(float min, float max, float attn) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasLightXY = conv_u8(min,0) | conv_u8(max,8) | conv_u8(attn,16); +} + +void C3D_GasLightView(float min, float max, float attn) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasLightZ = conv_u8(min,0) | conv_u8(max,8) | conv_u8(attn,16); +} + +void C3D_GasLightDirection(float dotp) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasLightZColor &= ~0xFF; + ctx->gasLightZColor |= conv_u8(dotp,0); +} + +void C3D_GasLutInput(GPU_GASLUTINPUT input) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_Gas; + ctx->gasLightZColor &= ~0x100; + ctx->gasLightZColor |= (input&1)<<8; +} + +void C3D_GasLutBind(C3D_GasLut* lut) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + if (lut) + { + ctx->flags |= C3DiF_GasLut; + ctx->gasLut = lut; + } else + ctx->flags &= ~C3DiF_GasLut; +} + +void C3Di_GasUpdate(C3D_Context* ctx) +{ + //__builtin_printf("updgasstate %08lX\n", ctx->flags); + //for(;;); + if (ctx->flags & C3DiF_Gas) + { + ctx->flags &= ~C3DiF_Gas; + GPUCMD_AddWrite(GPUREG_GAS_ATTENUATION, ctx->gasAttn); + //GPUCMD_AddWrite(GPUREG_GAS_ACCMAX, ctx->gasAccMax); + GPUCMD_AddWrite(GPUREG_GAS_LIGHT_XY, ctx->gasLightXY); + GPUCMD_AddWrite(GPUREG_GAS_LIGHT_Z, ctx->gasLightZ); + GPUCMD_AddWrite(GPUREG_GAS_LIGHT_Z_COLOR, ctx->gasLightZColor); + GPUCMD_AddWrite(GPUREG_GAS_DELTAZ_DEPTH, ctx->gasDeltaZ); + } + if (ctx->flags & C3DiF_GasLut) + { + ctx->flags &= ~C3DiF_GasLut; + if (ctx->gasLut) + { + GPUCMD_AddWrite(GPUREG_GAS_LUT_INDEX, 0); + GPUCMD_AddWrites(GPUREG_GAS_LUT_DATA, (u32*)ctx->gasLut, 16); + } + } +} diff --git a/source/internal.h b/source/internal.h index 9cffbaf..6ac7231 100644 --- a/source/internal.h +++ b/source/internal.h @@ -52,6 +52,10 @@ typedef struct u32 fogClr; C3D_FogLut* fogLut; + u16 gasAttn, gasAccMax; + u32 gasLightXY, gasLightZ, gasLightZColor, gasDeltaZ; + C3D_GasLut* gasLut; + C3D_ProcTex* procTex; C3D_ProcTexLut* procTexLut[3]; C3D_ProcTexColorLut* procTexColorLut; @@ -83,6 +87,8 @@ enum C3DiF_ProcTex = BIT(15), C3DiF_ProcTexColorLut = BIT(16), C3DiF_FogLut = BIT(17), + C3DiF_Gas = BIT(18), + C3DiF_GasLut = BIT(19), #define C3DiF_ProcTexLut(n) BIT(20+(n)) C3DiF_ProcTexLutAll = 7 << 20, @@ -115,6 +121,7 @@ void C3Di_FrameBufBind(C3D_FrameBuf* fb); void C3Di_TexEnvBind(int id, C3D_TexEnv* env); void C3Di_SetTex(int unit, C3D_Tex* tex); void C3Di_EffectBind(C3D_Effect* effect); +void C3Di_GasUpdate(C3D_Context* ctx); void C3Di_LightMtlBlend(C3D_Light* light);