Add Fog rendering support

This commit is contained in:
fincs 2017-04-08 12:46:25 +02:00
parent 53111971e0
commit 35d82d95be
5 changed files with 123 additions and 1 deletions

20
include/c3d/fog.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "types.h"
#include <math.h>
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);

View File

@ -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

View File

@ -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)

82
source/fog.c Normal file
View File

@ -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;
}

View File

@ -5,6 +5,7 @@
#include <c3d/light.h>
#include <c3d/framebuffer.h>
#include <c3d/texenv.h>
#include <c3d/fog.h>
#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,