Add support for procedural textures (Texture Unit 3)
This commit is contained in:
parent
33c6a10be5
commit
1739f88e40
125
include/c3d/proctex.h
Normal file
125
include/c3d/proctex.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 color[256];
|
||||||
|
u32 diff[256];
|
||||||
|
} C3D_ProcTexColorLut;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 proctex0;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 uClamp : 3;
|
||||||
|
u32 vClamp : 3;
|
||||||
|
u32 rgbFunc : 4;
|
||||||
|
u32 alphaFunc : 4;
|
||||||
|
bool alphaSeparate : 1;
|
||||||
|
bool enableNoise : 1;
|
||||||
|
u32 uShift : 2;
|
||||||
|
u32 vShift : 2;
|
||||||
|
u32 lodBiasLow : 8;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 proctex1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 uNoiseAmpl;
|
||||||
|
u16 uNoisePhase;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 proctex2;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 vNoiseAmpl;
|
||||||
|
u16 vNoisePhase;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 proctex3;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 uNoiseFreq;
|
||||||
|
u16 vNoiseFreq;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 proctex4;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 minFilter : 3;
|
||||||
|
u32 unknown1 : 8;
|
||||||
|
u32 width : 8;
|
||||||
|
u32 lodBiasHigh : 8;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 proctex5;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 offset : 8;
|
||||||
|
u32 unknown2 : 24;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} C3D_ProcTex;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
C3D_ProcTex_U = BIT(0),
|
||||||
|
C3D_ProcTex_V = BIT(1),
|
||||||
|
C3D_ProcTex_UV = C3D_ProcTex_U | C3D_ProcTex_V,
|
||||||
|
};
|
||||||
|
|
||||||
|
void C3D_ProcTexInit(C3D_ProcTex* pt, int offset, int length);
|
||||||
|
void C3D_ProcTexNoiseCoefs(C3D_ProcTex* pt, int mode, float amplitude, float frequency, float phase);
|
||||||
|
void C3D_ProcTexLodBias(C3D_ProcTex* pt, float bias);
|
||||||
|
void C3D_ProcTexBind(int texCoordId, C3D_ProcTex* pt);
|
||||||
|
|
||||||
|
// GPU_LUT_NOISE, GPU_LUT_RGBMAP, GPU_LUT_ALPHAMAP
|
||||||
|
typedef u32 C3D_ProcTexLut[128];
|
||||||
|
void C3D_ProcTexLutBind(GPU_PROCTEX_LUTID id, C3D_ProcTexLut* lut);
|
||||||
|
void ProcTexLut_FromArray(C3D_ProcTexLut* lut, const float in[129]);
|
||||||
|
|
||||||
|
void C3D_ProcTexColorLutBind(C3D_ProcTexColorLut* lut);
|
||||||
|
void ProcTexColorLut_Write(C3D_ProcTexColorLut* out, const u32* in, int offset, int length);
|
||||||
|
|
||||||
|
static inline void C3D_ProcTexClamp(C3D_ProcTex* pt, GPU_PROCTEX_CLAMP u, GPU_PROCTEX_CLAMP v)
|
||||||
|
{
|
||||||
|
pt->uClamp = u;
|
||||||
|
pt->vClamp = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void C3D_ProcTexCombiner(C3D_ProcTex* pt, bool separate, GPU_PROCTEX_MAPFUNC rgb, GPU_PROCTEX_MAPFUNC alpha)
|
||||||
|
{
|
||||||
|
pt->alphaSeparate = separate;
|
||||||
|
pt->rgbFunc = rgb;
|
||||||
|
if (separate)
|
||||||
|
pt->alphaFunc = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void C3D_ProcTexNoiseEnable(C3D_ProcTex* pt, bool enable)
|
||||||
|
{
|
||||||
|
pt->enableNoise = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void C3D_ProcTexShift(C3D_ProcTex* pt, GPU_PROCTEX_SHIFT u, GPU_PROCTEX_SHIFT v)
|
||||||
|
{
|
||||||
|
pt->uShift = u;
|
||||||
|
pt->vShift = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void C3D_ProcTexFilter(C3D_ProcTex* pt, GPU_PROCTEX_FILTER min)
|
||||||
|
{
|
||||||
|
pt->minFilter = min;
|
||||||
|
}
|
@ -21,6 +21,7 @@ extern "C" {
|
|||||||
#include "c3d/texenv.h"
|
#include "c3d/texenv.h"
|
||||||
#include "c3d/effect.h"
|
#include "c3d/effect.h"
|
||||||
#include "c3d/texture.h"
|
#include "c3d/texture.h"
|
||||||
|
#include "c3d/proctex.h"
|
||||||
#include "c3d/light.h"
|
#include "c3d/light.h"
|
||||||
#include "c3d/lightlut.h"
|
#include "c3d/lightlut.h"
|
||||||
|
|
||||||
|
@ -25,6 +25,16 @@ __attribute__((weak)) void C3Di_LightEnvDirty(C3D_LightEnv* env)
|
|||||||
(void)env;
|
(void)env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void C3Di_ProcTexUpdate(C3D_Context* ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void C3Di_ProcTexDirty(C3D_Context* ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
|
static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
|
||||||
{
|
{
|
||||||
C3D_Context* ctx = C3Di_GetContext();
|
C3D_Context* ctx = C3Di_GetContext();
|
||||||
@ -50,6 +60,7 @@ static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
|
|||||||
C3D_LightEnv* env = ctx->lightEnv;
|
C3D_LightEnv* env = ctx->lightEnv;
|
||||||
if (env)
|
if (env)
|
||||||
C3Di_LightEnvDirty(env);
|
C3Di_LightEnvDirty(env);
|
||||||
|
C3Di_ProcTexDirty(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -209,6 +220,9 @@ void C3Di_UpdateContext(void)
|
|||||||
ctx->texConfig &= ~BIT(16); // Remove clear-texture-cache flag
|
ctx->texConfig &= ~BIT(16); // Remove clear-texture-cache flag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->flags & (C3DiF_ProcTex | C3DiF_ProcTexColorLut | C3DiF_ProcTexLutAll))
|
||||||
|
C3Di_ProcTexUpdate(ctx);
|
||||||
|
|
||||||
if (ctx->flags & C3DiF_TexEnvBuf)
|
if (ctx->flags & C3DiF_TexEnvBuf)
|
||||||
{
|
{
|
||||||
ctx->flags &= ~C3DiF_TexEnvBuf;
|
ctx->flags &= ~C3DiF_TexEnvBuf;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <c3d/attribs.h>
|
#include <c3d/attribs.h>
|
||||||
#include <c3d/buffers.h>
|
#include <c3d/buffers.h>
|
||||||
|
#include <c3d/proctex.h>
|
||||||
#include <c3d/light.h>
|
#include <c3d/light.h>
|
||||||
#include <c3d/framebuffer.h>
|
#include <c3d/framebuffer.h>
|
||||||
#include <c3d/texenv.h>
|
#include <c3d/texenv.h>
|
||||||
@ -45,6 +46,10 @@ typedef struct
|
|||||||
|
|
||||||
u32 texEnvBuf, texEnvBufClr;
|
u32 texEnvBuf, texEnvBufClr;
|
||||||
|
|
||||||
|
C3D_ProcTex* procTex;
|
||||||
|
C3D_ProcTexLut* procTexLut[3];
|
||||||
|
C3D_ProcTexColorLut* procTexColorLut;
|
||||||
|
|
||||||
C3D_FrameBuf fb;
|
C3D_FrameBuf fb;
|
||||||
u32 viewport[5];
|
u32 viewport[5];
|
||||||
u32 scissor[3];
|
u32 scissor[3];
|
||||||
@ -70,7 +75,11 @@ enum
|
|||||||
C3DiF_GshCode = BIT(12),
|
C3DiF_GshCode = BIT(12),
|
||||||
C3DiF_CmdBuffer = BIT(13),
|
C3DiF_CmdBuffer = BIT(13),
|
||||||
C3DiF_TexStatus = BIT(14),
|
C3DiF_TexStatus = BIT(14),
|
||||||
|
C3DiF_ProcTex = BIT(15),
|
||||||
|
C3DiF_ProcTexColorLut = BIT(16),
|
||||||
|
|
||||||
|
#define C3DiF_ProcTexLut(n) BIT(20+(n))
|
||||||
|
C3DiF_ProcTexLutAll = 7 << 20,
|
||||||
#define C3DiF_Tex(n) BIT(23+(n))
|
#define C3DiF_Tex(n) BIT(23+(n))
|
||||||
C3DiF_TexAll = 7 << 23,
|
C3DiF_TexAll = 7 << 23,
|
||||||
#define C3DiF_TexEnv(n) BIT(26+(n))
|
#define C3DiF_TexEnv(n) BIT(26+(n))
|
||||||
|
191
source/proctex.c
Normal file
191
source/proctex.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
void C3D_ProcTexInit(C3D_ProcTex* pt, int offset, int width)
|
||||||
|
{
|
||||||
|
memset(pt, 0, sizeof(*pt));
|
||||||
|
pt->offset = offset;
|
||||||
|
pt->width = width;
|
||||||
|
pt->unknown1 = 0x60;
|
||||||
|
pt->unknown2 = 0xE0C080;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3D_ProcTexNoiseCoefs(C3D_ProcTex* pt, int mode, float amplitude, float frequency, float phase)
|
||||||
|
{
|
||||||
|
u16 f16_ampl = (s32)(amplitude*0x1000);
|
||||||
|
u16 f16_freq = f32tof16(frequency);
|
||||||
|
u16 f16_phase = f32tof16(phase);
|
||||||
|
pt->enableNoise = true;
|
||||||
|
if (mode & C3D_ProcTex_U)
|
||||||
|
{
|
||||||
|
pt->uNoiseAmpl = f16_ampl;
|
||||||
|
pt->uNoiseFreq = f16_freq;
|
||||||
|
pt->uNoisePhase = f16_phase;
|
||||||
|
}
|
||||||
|
if (mode & C3D_ProcTex_V)
|
||||||
|
{
|
||||||
|
pt->vNoiseAmpl = f16_ampl;
|
||||||
|
pt->vNoiseFreq = f16_freq;
|
||||||
|
pt->vNoisePhase = f16_phase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3D_ProcTexLodBias(C3D_ProcTex* pt, float bias)
|
||||||
|
{
|
||||||
|
u32 f16_bias = f32tof16(bias);
|
||||||
|
pt->lodBiasLow = f16_bias;
|
||||||
|
pt->lodBiasHigh = f16_bias>>8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3D_ProcTexBind(int texCoordId, C3D_ProcTex* pt)
|
||||||
|
{
|
||||||
|
C3D_Context* ctx = C3Di_GetContext();
|
||||||
|
|
||||||
|
if (!(ctx->flags & C3DiF_Active))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx->flags |= C3DiF_TexStatus;
|
||||||
|
ctx->texConfig &= ~(7<<8);
|
||||||
|
ctx->procTex = pt;
|
||||||
|
if (pt)
|
||||||
|
{
|
||||||
|
ctx->flags |= C3DiF_ProcTex;
|
||||||
|
ctx->texConfig |= BIT(10) | ((texCoordId&3)<<8);
|
||||||
|
} else
|
||||||
|
ctx->flags &= ~C3DiF_ProcTex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lutid2idx(GPU_PROCTEX_LUTID id)
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case GPU_LUT_NOISE: return 0;
|
||||||
|
case GPU_LUT_RGBMAP: return 1;
|
||||||
|
case GPU_LUT_ALPHAMAP: return 2;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3D_ProcTexLutBind(GPU_PROCTEX_LUTID id, C3D_ProcTexLut* lut)
|
||||||
|
{
|
||||||
|
C3D_Context* ctx = C3Di_GetContext();
|
||||||
|
|
||||||
|
if (!(ctx->flags & C3DiF_Active))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int idx = lutid2idx(id);
|
||||||
|
if (idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx->procTexLut[idx] = lut;
|
||||||
|
if (lut)
|
||||||
|
ctx->flags |= C3DiF_ProcTexLut(idx);
|
||||||
|
else
|
||||||
|
ctx->flags &= ~C3DiF_ProcTexLut(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float clampLut(float val)
|
||||||
|
{
|
||||||
|
if (val < 0.0f) return 0.0f;
|
||||||
|
if (val > 1.0f) return 1.0f;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcTexLut_FromArray(C3D_ProcTexLut* lut, const float in[129])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 128; i ++)
|
||||||
|
{
|
||||||
|
u32 cur = 0xFFF*clampLut(in[i]);
|
||||||
|
u32 next = 0xFFF*clampLut(in[i+1]);
|
||||||
|
u32 diff = (next-cur)&0xFFF;
|
||||||
|
(*lut)[i] = cur | (diff<<12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3D_ProcTexColorLutBind(C3D_ProcTexColorLut* lut)
|
||||||
|
{
|
||||||
|
C3D_Context* ctx = C3Di_GetContext();
|
||||||
|
|
||||||
|
if (!(ctx->flags & C3DiF_Active))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx->procTexColorLut = lut;
|
||||||
|
if (lut)
|
||||||
|
ctx->flags |= C3DiF_ProcTexColorLut;
|
||||||
|
else
|
||||||
|
ctx->flags &= ~C3DiF_ProcTexColorLut;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 calc_diff(u32 cur, u32 next, int pos)
|
||||||
|
{
|
||||||
|
cur = (cur>>pos)&0xFF;
|
||||||
|
next = (next>>pos)&0xFF;
|
||||||
|
u32 diff = (((s32)next-(s32)cur)>>1)&0xFF;
|
||||||
|
return diff<<pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcTexColorLut_Write(C3D_ProcTexColorLut* out, const u32* in, int offset, int width)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
memcpy(&out->color[offset], in, 4*width);
|
||||||
|
for (i = 0; i < (width-1); i ++)
|
||||||
|
{
|
||||||
|
u32 cur = in[i];
|
||||||
|
u32 next = in[i+1];
|
||||||
|
out->diff[offset+i] =
|
||||||
|
calc_diff(cur,next,0) |
|
||||||
|
calc_diff(cur,next,8) |
|
||||||
|
calc_diff(cur,next,16) |
|
||||||
|
calc_diff(cur,next,24);
|
||||||
|
}
|
||||||
|
out->diff[offset+width-1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3Di_ProcTexUpdate(C3D_Context* ctx)
|
||||||
|
{
|
||||||
|
if (ctx->flags & C3DiF_ProcTex)
|
||||||
|
{
|
||||||
|
ctx->flags &= ~C3DiF_ProcTex;
|
||||||
|
if (ctx->procTex)
|
||||||
|
GPUCMD_AddIncrementalWrites(GPUREG_TEXUNIT3_PROCTEX0, (u32*)ctx->procTex, 6);
|
||||||
|
}
|
||||||
|
if (ctx->flags & C3DiF_ProcTexLutAll)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 3; i ++)
|
||||||
|
{
|
||||||
|
int j = i ? (i+1) : 0;
|
||||||
|
if (!(ctx->flags & C3DiF_ProcTexLut(i)) || !ctx->procTexLut[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GPUCMD_AddWrite(GPUREG_PROCTEX_LUT, j<<8);
|
||||||
|
GPUCMD_AddWrites(GPUREG_PROCTEX_LUT_DATA0, *ctx->procTexLut[i], 128);
|
||||||
|
}
|
||||||
|
ctx->flags &= ~C3DiF_ProcTexLutAll;
|
||||||
|
}
|
||||||
|
if (ctx->flags & C3DiF_ProcTexColorLut)
|
||||||
|
{
|
||||||
|
ctx->flags &= ~C3DiF_ProcTexColorLut;
|
||||||
|
if (ctx->procTexColorLut)
|
||||||
|
{
|
||||||
|
GPUCMD_AddWrite(GPUREG_PROCTEX_LUT, GPU_LUT_COLOR<<8);
|
||||||
|
GPUCMD_AddWrites(GPUREG_PROCTEX_LUT_DATA0, ctx->procTexColorLut->color, 256);
|
||||||
|
GPUCMD_AddWrite(GPUREG_PROCTEX_LUT, GPU_LUT_COLORDIF<<8);
|
||||||
|
GPUCMD_AddWrites(GPUREG_PROCTEX_LUT_DATA0, ctx->procTexColorLut->diff, 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void C3Di_ProcTexDirty(C3D_Context* ctx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!ctx->procTex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx->flags |= C3DiF_ProcTex;
|
||||||
|
if (ctx->procTexColorLut)
|
||||||
|
ctx->flags |= C3DiF_ProcTexColorLut;
|
||||||
|
for (i = 0; i < 3; i ++)
|
||||||
|
if (ctx->procTexLut[i])
|
||||||
|
ctx->flags |= C3DiF_ProcTexLut(i);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user