From 35d82d95be3fe6b445a67a832fa8db7efaa5c5d0 Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 8 Apr 2017 12:46:25 +0200 Subject: [PATCH] Add Fog rendering support --- include/c3d/fog.h | 20 ++++++++++++ include/citro3d.h | 1 + source/base.c | 17 +++++++++- source/fog.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ source/internal.h | 4 +++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 include/c3d/fog.h create mode 100644 source/fog.c diff --git a/include/c3d/fog.h b/include/c3d/fog.h new file mode 100644 index 0000000..5c2f113 --- /dev/null +++ b/include/c3d/fog.h @@ -0,0 +1,20 @@ +#pragma once +#include "types.h" +#include + +typedef struct +{ + u32 data[128]; +} C3D_FogLut; + +static inline float FogLut_CalcZ(float depth, float near, float far) +{ + return far*near/(depth*(far-near)+near); +} + +void FogLut_FromArray(C3D_FogLut* lut, const float data[256]); +void FogLut_Exp(C3D_FogLut* lut, float density, float gradient, float near, float far); + +void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip); +void C3D_FogColor(u32 color); +void C3D_FogLutBind(C3D_FogLut* lut); diff --git a/include/citro3d.h b/include/citro3d.h index 227bf21..8574df9 100644 --- a/include/citro3d.h +++ b/include/citro3d.h @@ -24,6 +24,7 @@ extern "C" { #include "c3d/proctex.h" #include "c3d/light.h" #include "c3d/lightlut.h" +#include "c3d/fog.h" #include "c3d/framebuffer.h" #include "c3d/renderbuffer.h" // Deprecated diff --git a/source/base.c b/source/base.c index dfb2c12..c4af435 100644 --- a/source/base.c +++ b/source/base.c @@ -59,6 +59,8 @@ static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param) ctx->fixedAttribDirty |= ctx->fixedAttribEverDirty; C3D_LightEnv* env = ctx->lightEnv; + if (ctx->fogLut) + ctx->flags |= C3DiF_FogLut; if (env) C3Di_LightEnvDirty(env); C3Di_ProcTexDirty(ctx); @@ -115,6 +117,8 @@ bool C3D_Init(size_t cmdBufSize) ctx->texShadow = BIT(0); ctx->texEnvBuf = 0; ctx->texEnvBufClr = 0xFFFFFFFF; + ctx->fogClr = 0; + ctx->fogLut = NULL; for (i = 0; i < 3; i ++) ctx->tex[i] = NULL; @@ -240,8 +244,19 @@ void C3Di_UpdateContext(void) if (ctx->flags & C3DiF_TexEnvBuf) { ctx->flags &= ~C3DiF_TexEnvBuf; - GPUCMD_AddMaskedWrite(GPUREG_TEXENV_UPDATE_BUFFER, 0x2, ctx->texEnvBuf); + GPUCMD_AddMaskedWrite(GPUREG_TEXENV_UPDATE_BUFFER, 0x7, ctx->texEnvBuf); GPUCMD_AddWrite(GPUREG_TEXENV_BUFFER_COLOR, ctx->texEnvBufClr); + GPUCMD_AddWrite(GPUREG_FOG_COLOR, ctx->fogClr); + } + + if (ctx->flags & C3DiF_FogLut) + { + ctx->flags &= ~C3DiF_FogLut; + if (ctx->fogLut) + { + GPUCMD_AddWrite(GPUREG_FOG_LUT_INDEX, 0); + GPUCMD_AddWrites(GPUREG_FOG_LUT_DATA0, ctx->fogLut->data, 128); + } } if (ctx->flags & C3DiF_TexEnvAll) diff --git a/source/fog.c b/source/fog.c new file mode 100644 index 0000000..9cc6262 --- /dev/null +++ b/source/fog.c @@ -0,0 +1,82 @@ +#include "internal.h" + +void FogLut_FromArray(C3D_FogLut* lut, const float data[256]) +{ + int i; + for (i = 0; i < 128; i ++) + { + float in = data[i], diff = data[i+128]; + + u32 val = 0; + if (in > 0.0f) + { + in *= 0x800; + val = (in < 0x800) ? (u32)in : 0x7FF; + } + + u32 val2 = 0; + if (diff != 0.0f) + { + diff *= 0x800; + if (diff < -0x1000) diff = -0x1000; + else if (diff > 0xFFF) diff = 0xFFF; + val2 = (s32)diff & 0x1FFF; + } + + lut->data[i] = val2 | (val << 13); + } +} + +void FogLut_Exp(C3D_FogLut* lut, float density, float gradient, float near, float far) +{ + int i; + float data[256]; + for (i = 0; i <= 128; i ++) + { + float x = FogLut_CalcZ(i/128.0f, near, far); + float val = expf(-powf(density*x, gradient)); + if (i < 128) + data[i] = val; + if (i > 0) + data[i+127] = val-data[i-1]; + } + FogLut_FromArray(lut, data); +} + +void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_TexEnvBuf; + ctx->texEnvBuf &= ~0x100FF; + ctx->texEnvBuf |= (fogMode&7) | ((gasMode&1)<<3) | (zFlip ? BIT(16) : 0); +} + +void C3D_FogColor(u32 color) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + ctx->flags |= C3DiF_TexEnvBuf; + ctx->fogClr = color; +} + +void C3D_FogLutBind(C3D_FogLut* lut) +{ + C3D_Context* ctx = C3Di_GetContext(); + + if (!(ctx->flags & C3DiF_Active)) + return; + + if (lut) + { + ctx->flags |= C3DiF_FogLut; + ctx->fogLut = lut; + } else + ctx->flags &= ~C3DiF_FogLut; +} diff --git a/source/internal.h b/source/internal.h index e9321ac..9cffbaf 100644 --- a/source/internal.h +++ b/source/internal.h @@ -5,6 +5,7 @@ #include #include #include +#include #define C3D_UNUSED __attribute__((unused)) @@ -48,6 +49,8 @@ typedef struct C3D_TexEnv texEnv[6]; u32 texEnvBuf, texEnvBufClr; + u32 fogClr; + C3D_FogLut* fogLut; C3D_ProcTex* procTex; C3D_ProcTexLut* procTexLut[3]; @@ -79,6 +82,7 @@ enum C3DiF_TexStatus = BIT(14), C3DiF_ProcTex = BIT(15), C3DiF_ProcTexColorLut = BIT(16), + C3DiF_FogLut = BIT(17), #define C3DiF_ProcTexLut(n) BIT(20+(n)) C3DiF_ProcTexLutAll = 7 << 20,