mirror of
https://github.com/ctruLua/ctruLua.git
synced 2025-10-28 16:59:30 +00:00
Updated all the libs, added citro3d, added ctr.swkbd (WIP, untested)
This commit is contained in:
parent
68a44645f7
commit
49c87e5526
97 changed files with 7341 additions and 944 deletions
66
libs/citro3d/source/attribs.c
Normal file
66
libs/citro3d/source/attribs.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#include <c3d/attribs.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
void AttrInfo_Init(C3D_AttrInfo* info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->flags[1] = 0xFFF << 16;
|
||||
}
|
||||
|
||||
int AttrInfo_AddLoader(C3D_AttrInfo* info, int regId, GPU_FORMATS format, int count)
|
||||
{
|
||||
if (info->attrCount == 12) return -1;
|
||||
int id = info->attrCount++;
|
||||
if (regId < 0) regId = id;
|
||||
if (id < 8)
|
||||
info->flags[0] |= GPU_ATTRIBFMT(id, count, format);
|
||||
else
|
||||
info->flags[1] |= GPU_ATTRIBFMT(id-8, count, format);
|
||||
|
||||
info->flags[1] = (info->flags[1] &~ (0xF0000000 | BIT(id+16))) | (id << 28);
|
||||
info->permutation |= regId << (id*4);
|
||||
return id;
|
||||
}
|
||||
|
||||
int AttrInfo_AddFixed(C3D_AttrInfo* info, int regId)
|
||||
{
|
||||
if (info->attrCount == 12) return -1;
|
||||
int id = info->attrCount++;
|
||||
if (regId < 0) regId = id;
|
||||
|
||||
info->flags[1] = (info->flags[1] &~ 0xF0000000) | (id << 28);
|
||||
info->permutation |= regId << (id*4);
|
||||
return id;
|
||||
}
|
||||
|
||||
C3D_AttrInfo* C3D_GetAttrInfo(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return NULL;
|
||||
|
||||
ctx->flags |= C3DiF_AttrInfo;
|
||||
return &ctx->attrInfo;
|
||||
}
|
||||
|
||||
void C3D_SetAttrInfo(C3D_AttrInfo* info)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
if (info != &ctx->attrInfo)
|
||||
memcpy(&ctx->attrInfo, info, sizeof(*info));
|
||||
ctx->flags |= C3DiF_AttrInfo;
|
||||
}
|
||||
|
||||
void C3Di_AttrInfoBind(C3D_AttrInfo* info)
|
||||
{
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_ATTRIBBUFFERS_FORMAT_LOW, (u32*)info->flags, sizeof(info->flags)/sizeof(u32));
|
||||
GPUCMD_AddMaskedWrite(GPUREG_VSH_INPUTBUFFER_CONFIG, 0xB, 0xA0000000 | (info->attrCount - 1));
|
||||
GPUCMD_AddWrite(GPUREG_VSH_NUM_ATTR, info->attrCount - 1);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW, (u32*)&info->permutation, 2);
|
||||
}
|
||||
365
libs/citro3d/source/base.c
Normal file
365
libs/citro3d/source/base.c
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
#include "context.h"
|
||||
|
||||
C3D_Context __C3D_Context;
|
||||
|
||||
static void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex)
|
||||
{
|
||||
u32 reg[4];
|
||||
reg[0] = tex->fmt;
|
||||
reg[1] = osConvertVirtToPhys(tex->data) >> 3;
|
||||
reg[2] = (u32)tex->height | ((u32)tex->width << 16);
|
||||
reg[3] = tex->param;
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case GPU_TEXUNIT0:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, reg[0]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_ADDR1, reg[1]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_DIM, reg[2]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_PARAM, reg[3]);
|
||||
break;
|
||||
case GPU_TEXUNIT1:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, reg[0]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_ADDR, reg[1]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_DIM, reg[2]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_PARAM, reg[3]);
|
||||
break;
|
||||
case GPU_TEXUNIT2:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, reg[0]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_ADDR, reg[1]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_DIM, reg[2]);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_PARAM, reg[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static aptHookCookie hookCookie;
|
||||
|
||||
static void C3Di_AptEventHook(APT_HookType hookType, void* param)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
switch (hookType)
|
||||
{
|
||||
case APTHOOK_ONSUSPEND:
|
||||
{
|
||||
if (ctx->renderQueueWaitDone)
|
||||
ctx->renderQueueWaitDone();
|
||||
break;
|
||||
}
|
||||
case APTHOOK_ONRESTORE:
|
||||
{
|
||||
ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_RenderBuf
|
||||
| C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode
|
||||
| C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv;
|
||||
|
||||
C3Di_DirtyUniforms(GPU_VERTEX_SHADER);
|
||||
C3Di_DirtyUniforms(GPU_GEOMETRY_SHADER);
|
||||
|
||||
ctx->fixedAttribDirty |= ctx->fixedAttribEverDirty;
|
||||
|
||||
C3D_LightEnv* env = ctx->lightEnv;
|
||||
if (env)
|
||||
env->Dirty(env);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool C3D_Init(size_t cmdBufSize)
|
||||
{
|
||||
int i;
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (ctx->flags & C3DiF_Active)
|
||||
return false;
|
||||
|
||||
ctx->cmdBufSize = cmdBufSize/8; // Half of the size of the cmdbuf, in words
|
||||
ctx->cmdBuf = (u32*)linearAlloc(cmdBufSize);
|
||||
ctx->cmdBufUsage = 0;
|
||||
if (!ctx->cmdBuf) return false;
|
||||
|
||||
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
|
||||
|
||||
ctx->flags = C3DiF_Active | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_Effect | C3DiF_TexAll;
|
||||
ctx->renderQueueExit = NULL;
|
||||
|
||||
// TODO: replace with direct struct access
|
||||
C3D_DepthMap(-1.0f, 0.0f);
|
||||
C3D_CullFace(GPU_CULL_BACK_CCW);
|
||||
C3D_StencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
|
||||
C3D_StencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
||||
C3D_BlendingColor(0);
|
||||
C3D_DepthTest(true, GPU_GREATER, GPU_WRITE_ALL);
|
||||
C3D_AlphaTest(false, GPU_ALWAYS, 0x00);
|
||||
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
||||
C3D_FragOpMode(GPU_FRAGOPMODE_GL);
|
||||
|
||||
ctx->texEnvBuf = 0;
|
||||
ctx->texEnvBufClr = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < 3; i ++)
|
||||
ctx->tex[i] = NULL;
|
||||
|
||||
for (i = 0; i < 6; i ++)
|
||||
TexEnv_Init(&ctx->texEnv[i]);
|
||||
|
||||
ctx->fixedAttribDirty = 0;
|
||||
ctx->fixedAttribEverDirty = 0;
|
||||
|
||||
aptHook(&hookCookie, C3Di_AptEventHook, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_SetViewport(u32 x, u32 y, u32 w, u32 h)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
ctx->flags |= C3DiF_Viewport | C3DiF_Scissor;
|
||||
ctx->viewport[0] = f32tof24(w / 2.0f);
|
||||
ctx->viewport[1] = f32tof31(2.0f / w) << 1;
|
||||
ctx->viewport[2] = f32tof24(h / 2.0f);
|
||||
ctx->viewport[3] = f32tof31(2.0f / h) << 1;
|
||||
ctx->viewport[4] = (y << 16) | (x & 0xFFFF);
|
||||
ctx->scissor[0] = GPU_SCISSOR_DISABLE;
|
||||
}
|
||||
|
||||
void C3D_SetScissor(GPU_SCISSORMODE mode, u32 left, u32 top, u32 right, u32 bottom)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
ctx->flags |= C3DiF_Scissor;
|
||||
ctx->scissor[0] = mode;
|
||||
if (mode == GPU_SCISSOR_DISABLE) return;
|
||||
ctx->scissor[1] = (top << 16) | (left & 0xFFFF);
|
||||
ctx->scissor[2] = ((bottom-1) << 16) | ((right-1) & 0xFFFF);
|
||||
}
|
||||
|
||||
void C3Di_UpdateContext(void)
|
||||
{
|
||||
int i;
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (ctx->flags & C3DiF_Program)
|
||||
{
|
||||
shaderProgramConfigure(ctx->program, (ctx->flags & C3DiF_VshCode) != 0, (ctx->flags & C3DiF_GshCode) != 0);
|
||||
ctx->flags &= ~(C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_RenderBuf)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_RenderBuf;
|
||||
if (ctx->flags & C3DiF_DrawUsed)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_DrawUsed;
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 1);
|
||||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 1);
|
||||
}
|
||||
C3Di_RenderBufBind(ctx->rb);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_Viewport)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_Viewport;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VIEWPORT_WIDTH, ctx->viewport, 4);
|
||||
GPUCMD_AddWrite(GPUREG_VIEWPORT_XY, ctx->viewport[4]);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_Scissor)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_Scissor;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, ctx->scissor, 3);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_AttrInfo)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_AttrInfo;
|
||||
C3Di_AttrInfoBind(&ctx->attrInfo);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_BufInfo)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_BufInfo;
|
||||
C3Di_BufInfoBind(&ctx->bufInfo);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_Effect)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_Effect;
|
||||
C3Di_EffectBind(&ctx->effect);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_TexAll)
|
||||
{
|
||||
GPU_TEXUNIT units = 0;
|
||||
|
||||
for (i = 0; i < 3; i ++)
|
||||
{
|
||||
static const u8 parm[] = { GPU_TEXUNIT0, GPU_TEXUNIT1, GPU_TEXUNIT2 };
|
||||
|
||||
if (ctx->tex[i])
|
||||
{
|
||||
units |= parm[i];
|
||||
if (ctx->flags & C3DiF_Tex(i))
|
||||
C3Di_SetTex(parm[i], ctx->tex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->flags &= ~C3DiF_TexAll;
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT_CONFIG, 0x00011000|units); // Enable texture units
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_TexEnvBuf)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_TexEnvBuf;
|
||||
GPUCMD_AddMaskedWrite(GPUREG_TEXENV_UPDATE_BUFFER, 0x2, ctx->texEnvBuf);
|
||||
GPUCMD_AddWrite(GPUREG_TEXENV_BUFFER_COLOR, ctx->texEnvBufClr);
|
||||
}
|
||||
|
||||
if (ctx->flags & C3DiF_TexEnvAll)
|
||||
{
|
||||
for (i = 0; i < 6; i ++)
|
||||
{
|
||||
if (!(ctx->flags & C3DiF_TexEnv(i))) continue;
|
||||
C3Di_TexEnvBind(i, &ctx->texEnv[i]);
|
||||
}
|
||||
ctx->flags &= ~C3DiF_TexEnvAll;
|
||||
}
|
||||
|
||||
C3D_LightEnv* env = ctx->lightEnv;
|
||||
|
||||
if (ctx->flags & C3DiF_LightEnv)
|
||||
{
|
||||
u32 enable = env != NULL;
|
||||
GPUCMD_AddWrite(GPUREG_LIGHTING_ENABLE0, enable);
|
||||
GPUCMD_AddWrite(GPUREG_LIGHTING_ENABLE1, !enable);
|
||||
ctx->flags &= ~C3DiF_LightEnv;
|
||||
}
|
||||
|
||||
if (env)
|
||||
env->Update(env);
|
||||
|
||||
if (ctx->fixedAttribDirty)
|
||||
{
|
||||
for (i = 0; i < 12; i ++)
|
||||
{
|
||||
if (!(ctx->fixedAttribDirty & BIT(i))) continue;
|
||||
C3D_FVec* v = &ctx->fixedAttribs[i];
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_FIXEDATTRIB_INDEX, i);
|
||||
C3D_ImmSendAttrib(v->x, v->y, v->z, v->w);
|
||||
}
|
||||
ctx->fixedAttribDirty = 0;
|
||||
}
|
||||
|
||||
C3D_UpdateUniforms(GPU_VERTEX_SHADER);
|
||||
C3D_UpdateUniforms(GPU_GEOMETRY_SHADER);
|
||||
}
|
||||
|
||||
void C3Di_FinalizeFrame(u32** pBuf, u32* pSize)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (ctx->flags & C3DiF_DrawUsed)
|
||||
{
|
||||
ctx->flags &= ~C3DiF_DrawUsed;
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 1);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 1);
|
||||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 1);
|
||||
}
|
||||
|
||||
GPUCMD_Finalize();
|
||||
GPUCMD_GetBuffer(pBuf, NULL, pSize);
|
||||
ctx->cmdBufUsage = (float)(*pSize) / ctx->cmdBufSize;
|
||||
*pSize *= 4;
|
||||
|
||||
ctx->flags ^= C3DiF_CmdBuffer;
|
||||
u32* buf = ctx->cmdBuf;
|
||||
if (ctx->flags & C3DiF_CmdBuffer)
|
||||
buf += ctx->cmdBufSize;
|
||||
GPUCMD_SetBuffer(buf, ctx->cmdBufSize, 0);
|
||||
}
|
||||
|
||||
void C3D_FlushAsync(void)
|
||||
{
|
||||
if (!(C3Di_GetContext()->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
u32* cmdBuf;
|
||||
u32 cmdBufSize;
|
||||
C3Di_FinalizeFrame(&cmdBuf, &cmdBufSize);
|
||||
|
||||
//take advantage of GX_FlushCacheRegions to flush gsp heap
|
||||
extern u32 __ctru_linear_heap;
|
||||
extern u32 __ctru_linear_heap_size;
|
||||
GX_FlushCacheRegions(cmdBuf, cmdBufSize, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0);
|
||||
GX_ProcessCommandList(cmdBuf, cmdBufSize, 0x0);
|
||||
}
|
||||
|
||||
float C3D_GetCmdBufUsage(void)
|
||||
{
|
||||
return C3Di_GetContext()->cmdBufUsage;
|
||||
}
|
||||
|
||||
void C3D_Fini(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
if (ctx->renderQueueExit)
|
||||
ctx->renderQueueExit();
|
||||
|
||||
aptUnhook(&hookCookie);
|
||||
linearFree(ctx->cmdBuf);
|
||||
ctx->flags = 0;
|
||||
}
|
||||
|
||||
void C3D_BindProgram(shaderProgram_s* program)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
shaderProgram_s* oldProg = ctx->program;
|
||||
shaderInstance_s* newGsh = program->geometryShader;
|
||||
if (oldProg != program)
|
||||
{
|
||||
ctx->program = program;
|
||||
ctx->flags |= C3DiF_Program;
|
||||
|
||||
if (oldProg)
|
||||
{
|
||||
if (oldProg->vertexShader->dvle->dvlp != program->vertexShader->dvle->dvlp)
|
||||
ctx->flags |= C3DiF_VshCode;
|
||||
shaderInstance_s* oldGsh = oldProg->geometryShader;
|
||||
if (newGsh && (!oldGsh || oldGsh->dvle->dvlp != newGsh->dvle->dvlp))
|
||||
ctx->flags |= C3DiF_GshCode;
|
||||
} else
|
||||
ctx->flags |= C3DiF_VshCode | C3DiF_GshCode;
|
||||
}
|
||||
|
||||
C3Di_LoadShaderUniforms(program->vertexShader);
|
||||
if (newGsh)
|
||||
C3Di_LoadShaderUniforms(newGsh);
|
||||
else
|
||||
C3Di_ClearShaderUniforms(GPU_GEOMETRY_SHADER);
|
||||
}
|
||||
|
||||
C3D_FVec* C3D_FixedAttribGetWritePtr(int id)
|
||||
{
|
||||
if (id < 0 || id >= 12)
|
||||
return NULL;
|
||||
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return NULL;
|
||||
|
||||
ctx->fixedAttribDirty |= BIT(id);
|
||||
ctx->fixedAttribEverDirty |= BIT(id);
|
||||
return &ctx->fixedAttribs[id];
|
||||
}
|
||||
55
libs/citro3d/source/buffers.c
Normal file
55
libs/citro3d/source/buffers.c
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#include <c3d/buffers.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
#define BUFFER_BASE_PADDR 0x18000000
|
||||
|
||||
void BufInfo_Init(C3D_BufInfo* info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->base_paddr = BUFFER_BASE_PADDR;
|
||||
}
|
||||
|
||||
int BufInfo_Add(C3D_BufInfo* info, const void* data, ptrdiff_t stride, int attribCount, u64 permutation)
|
||||
{
|
||||
if (info->bufCount == 12) return -1;
|
||||
int id = info->bufCount++;
|
||||
|
||||
u32 pa = osConvertVirtToPhys(data);
|
||||
if (pa < info->base_paddr) return -2;
|
||||
|
||||
C3D_BufCfg* buf = &info->buffers[id];
|
||||
buf->offset = pa - info->base_paddr;
|
||||
buf->flags[0] = permutation & 0xFFFFFFFF;
|
||||
buf->flags[1] = (permutation >> 32) | (stride << 16) | (attribCount << 28);
|
||||
return id;
|
||||
}
|
||||
|
||||
C3D_BufInfo* C3D_GetBufInfo(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return NULL;
|
||||
|
||||
ctx->flags |= C3DiF_BufInfo;
|
||||
return &ctx->bufInfo;
|
||||
}
|
||||
|
||||
void C3D_SetBufInfo(C3D_BufInfo* info)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
if (info != &ctx->bufInfo)
|
||||
memcpy(&ctx->bufInfo, info, sizeof(*info));
|
||||
ctx->flags |= C3DiF_BufInfo;
|
||||
}
|
||||
|
||||
void C3Di_BufInfoBind(C3D_BufInfo* info)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_ATTRIBBUFFERS_LOC, info->base_paddr >> 3);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_ATTRIBBUFFER0_OFFSET, (u32*)info->buffers, sizeof(info->buffers)/sizeof(u32));
|
||||
}
|
||||
100
libs/citro3d/source/context.h
Normal file
100
libs/citro3d/source/context.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#pragma once
|
||||
#include <c3d/base.h>
|
||||
#include <c3d/uniforms.h>
|
||||
#include <c3d/attribs.h>
|
||||
#include <c3d/buffers.h>
|
||||
#include <c3d/texenv.h>
|
||||
#include <c3d/effect.h>
|
||||
#include <c3d/texture.h>
|
||||
#include <c3d/light.h>
|
||||
#include <c3d/renderbuffer.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 fragOpMode;
|
||||
u32 zScale, zOffset;
|
||||
GPU_CULLMODE cullMode;
|
||||
|
||||
u32 alphaTest;
|
||||
u32 stencilMode, stencilOp;
|
||||
u32 depthTest;
|
||||
|
||||
u32 blendClr;
|
||||
u32 alphaBlend;
|
||||
GPU_LOGICOP clrLogicOp;
|
||||
} C3D_Effect;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32* cmdBuf;
|
||||
size_t cmdBufSize;
|
||||
float cmdBufUsage;
|
||||
|
||||
u32 flags;
|
||||
shaderProgram_s* program;
|
||||
|
||||
C3D_AttrInfo attrInfo;
|
||||
C3D_BufInfo bufInfo;
|
||||
C3D_Effect effect;
|
||||
C3D_LightEnv* lightEnv;
|
||||
|
||||
C3D_Tex* tex[3];
|
||||
C3D_TexEnv texEnv[6];
|
||||
|
||||
u32 texEnvBuf, texEnvBufClr;
|
||||
|
||||
C3D_RenderBuf* rb;
|
||||
u32 viewport[5];
|
||||
u32 scissor[3];
|
||||
|
||||
u16 fixedAttribDirty, fixedAttribEverDirty;
|
||||
C3D_FVec fixedAttribs[12];
|
||||
|
||||
void (* renderQueueWaitDone)(void);
|
||||
void (* renderQueueExit)(void);
|
||||
|
||||
} C3D_Context;
|
||||
|
||||
enum
|
||||
{
|
||||
C3DiF_Active = BIT(0),
|
||||
C3DiF_DrawUsed = BIT(1),
|
||||
C3DiF_AttrInfo = BIT(2),
|
||||
C3DiF_BufInfo = BIT(3),
|
||||
C3DiF_Effect = BIT(4),
|
||||
C3DiF_RenderBuf = BIT(5),
|
||||
C3DiF_Viewport = BIT(6),
|
||||
C3DiF_Scissor = BIT(7),
|
||||
C3DiF_Program = BIT(8),
|
||||
C3DiF_TexEnvBuf = BIT(9),
|
||||
C3DiF_LightEnv = BIT(10),
|
||||
C3DiF_VshCode = BIT(11),
|
||||
C3DiF_GshCode = BIT(12),
|
||||
C3DiF_CmdBuffer = BIT(13),
|
||||
|
||||
#define C3DiF_Tex(n) BIT(23+(n))
|
||||
C3DiF_TexAll = 7 << 23,
|
||||
#define C3DiF_TexEnv(n) BIT(26+(n))
|
||||
C3DiF_TexEnvAll = 0x3F << 26,
|
||||
};
|
||||
|
||||
static inline C3D_Context* C3Di_GetContext(void)
|
||||
{
|
||||
extern C3D_Context __C3D_Context;
|
||||
return &__C3D_Context;
|
||||
}
|
||||
|
||||
void C3Di_UpdateContext(void);
|
||||
void C3Di_AttrInfoBind(C3D_AttrInfo* info);
|
||||
void C3Di_BufInfoBind(C3D_BufInfo* info);
|
||||
void C3Di_TexEnvBind(int id, C3D_TexEnv* env);
|
||||
void C3Di_EffectBind(C3D_Effect* effect);
|
||||
void C3Di_RenderBufBind(C3D_RenderBuf* rb);
|
||||
|
||||
void C3Di_LightMtlBlend(C3D_Light* light);
|
||||
|
||||
void C3Di_DirtyUniforms(GPU_SHADER_TYPE type);
|
||||
void C3Di_LoadShaderUniforms(shaderInstance_s* si);
|
||||
void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type);
|
||||
|
||||
void C3Di_FinalizeFrame(u32** pBuf, u32* pSize);
|
||||
31
libs/citro3d/source/drawArrays.c
Normal file
31
libs/citro3d/source/drawArrays.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "context.h"
|
||||
|
||||
void C3D_DrawArrays(GPU_Primitive_t primitive, int first, int size)
|
||||
{
|
||||
C3Di_UpdateContext();
|
||||
|
||||
// Set primitive type
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 2, primitive);
|
||||
// Start a new primitive (breaks off a triangle strip/fan)
|
||||
GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1);
|
||||
// The index buffer is not used, but this command is still required
|
||||
GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000);
|
||||
// Number of vertices
|
||||
GPUCMD_AddWrite(GPUREG_NUMVERTICES, size);
|
||||
// First vertex
|
||||
GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, first);
|
||||
// Enable array drawing mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 1);
|
||||
// Enable drawing mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 0);
|
||||
// Trigger array drawing
|
||||
GPUCMD_AddWrite(GPUREG_DRAWARRAYS, 1);
|
||||
// Go back to configuration mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 1);
|
||||
// Disable array drawing mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 0);
|
||||
// Clear the post-vertex cache
|
||||
GPUCMD_AddWrite(GPUREG_VTX_FUNC, 1);
|
||||
|
||||
C3Di_GetContext()->flags |= C3DiF_DrawUsed;
|
||||
}
|
||||
44
libs/citro3d/source/drawElements.c
Normal file
44
libs/citro3d/source/drawElements.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "context.h"
|
||||
|
||||
void C3D_DrawElements(GPU_Primitive_t primitive, int count, int type, const void* indices)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
u32 pa = osConvertVirtToPhys(indices);
|
||||
u32 base = ctx->bufInfo.base_paddr;
|
||||
if (pa < base) return;
|
||||
|
||||
C3Di_UpdateContext();
|
||||
|
||||
// Set primitive type
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 2, primitive);
|
||||
// Start a new primitive (breaks off a triangle strip/fan)
|
||||
GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1);
|
||||
// Configure the index buffer
|
||||
GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, (pa - base) | (type << 31));
|
||||
// Number of vertices
|
||||
GPUCMD_AddWrite(GPUREG_NUMVERTICES, count);
|
||||
// First vertex
|
||||
GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, 0);
|
||||
// Enable triangle element drawing mode if necessary
|
||||
if (primitive == GPU_TRIANGLES)
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 2, 0x100);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 2, 0x100);
|
||||
}
|
||||
// Enable drawing mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 0);
|
||||
// Trigger element drawing
|
||||
GPUCMD_AddWrite(GPUREG_DRAWELEMENTS, 1);
|
||||
// Go back to configuration mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 1);
|
||||
// Disable triangle element drawing mode if necessary
|
||||
if (primitive == GPU_TRIANGLES)
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 2, 0);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 2, 0);
|
||||
}
|
||||
// Clear the post-vertex cache
|
||||
GPUCMD_AddWrite(GPUREG_VTX_FUNC, 1);
|
||||
|
||||
C3Di_GetContext()->flags |= C3DiF_DrawUsed;
|
||||
}
|
||||
89
libs/citro3d/source/effect.c
Normal file
89
libs/citro3d/source/effect.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include "context.h"
|
||||
|
||||
static inline C3D_Effect* getEffect()
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
ctx->flags |= C3DiF_Effect;
|
||||
return &ctx->effect;
|
||||
}
|
||||
|
||||
void C3D_DepthMap(float zScale, float zOffset)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->zScale = f32tof24(zScale);
|
||||
e->zOffset = f32tof24(zOffset);
|
||||
}
|
||||
|
||||
void C3D_CullFace(GPU_CULLMODE mode)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->cullMode = mode;
|
||||
}
|
||||
|
||||
void C3D_StencilTest(bool enable, GPU_TESTFUNC function, int ref, int inputMask, int writeMask)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->stencilMode = (!!enable) | ((function & 7) << 4) | (writeMask << 8) | (ref << 16) | (inputMask << 24);
|
||||
}
|
||||
|
||||
void C3D_StencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->stencilOp = sfail | (dfail << 4) | (pass << 8);
|
||||
}
|
||||
|
||||
void C3D_BlendingColor(u32 color)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->blendClr = color;
|
||||
}
|
||||
|
||||
void C3D_DepthTest(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->depthTest = (!!enable) | ((function & 7) << 4) | (writemask << 8);
|
||||
}
|
||||
|
||||
void C3D_AlphaTest(bool enable, GPU_TESTFUNC function, int ref)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->alphaTest = (!!enable) | ((function & 7) << 4) | (ref << 8);
|
||||
}
|
||||
|
||||
void C3D_AlphaBlend(GPU_BLENDEQUATION colorEq, GPU_BLENDEQUATION alphaEq, GPU_BLENDFACTOR srcClr, GPU_BLENDFACTOR dstClr, GPU_BLENDFACTOR srcAlpha, GPU_BLENDFACTOR dstAlpha)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->alphaBlend = colorEq | (alphaEq << 8) | (srcClr << 16) | (dstClr << 20) | (srcAlpha << 24) | (dstAlpha << 28);
|
||||
e->fragOpMode &= ~0xFF00;
|
||||
e->fragOpMode |= 0x0100;
|
||||
}
|
||||
|
||||
void C3D_ColorLogicOp(GPU_LOGICOP op)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->fragOpMode &= ~0xFF00;
|
||||
e->clrLogicOp = op;
|
||||
}
|
||||
|
||||
void C3D_FragOpMode(GPU_FRAGOPMODE mode)
|
||||
{
|
||||
C3D_Effect* e = getEffect();
|
||||
e->fragOpMode &= ~0xFF00FF;
|
||||
e->fragOpMode |= 0xE40000 | mode;
|
||||
}
|
||||
|
||||
void C3Di_EffectBind(C3D_Effect* e)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHMAP_ENABLE, 1);
|
||||
GPUCMD_AddWrite(GPUREG_FACECULLING_CONFIG, e->cullMode & 0x3);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_DEPTHMAP_SCALE, (u32*)&e->zScale, 2);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_FRAGOP_ALPHA_TEST, (u32*)&e->alphaTest, 4);
|
||||
GPUCMD_AddWrite(GPUREG_BLEND_COLOR, e->blendClr);
|
||||
GPUCMD_AddWrite(GPUREG_BLEND_FUNC, e->alphaBlend);
|
||||
GPUCMD_AddWrite(GPUREG_LOGIC_OP, e->clrLogicOp);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_COLOR_OPERATION, 7, e->fragOpMode);
|
||||
|
||||
// Disable early depth test?
|
||||
GPUCMD_AddMaskedWrite(GPUREG_EARLYDEPTH_TEST1, 1, 0);
|
||||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_TEST2, 0);
|
||||
}
|
||||
67
libs/citro3d/source/immediate.c
Normal file
67
libs/citro3d/source/immediate.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include "context.h"
|
||||
|
||||
void C3D_ImmDrawBegin(GPU_Primitive_t primitive)
|
||||
{
|
||||
C3Di_UpdateContext();
|
||||
|
||||
// Set primitive type
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 2, primitive);
|
||||
// Start a new primitive (breaks off a triangle strip/fan)
|
||||
GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1);
|
||||
// Not sure if this command is necessary
|
||||
GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000);
|
||||
// Enable vertex submission mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 1);
|
||||
// Enable drawing mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 0);
|
||||
// Begin immediate-mode vertex submission
|
||||
GPUCMD_AddWrite(GPUREG_FIXEDATTRIB_INDEX, 0xF);
|
||||
}
|
||||
|
||||
static inline void write24(u8* p, u32 val)
|
||||
{
|
||||
p[0] = val;
|
||||
p[1] = val>>8;
|
||||
p[2] = val>>16;
|
||||
}
|
||||
|
||||
void C3D_ImmSendAttrib(float x, float y, float z, float w)
|
||||
{
|
||||
union
|
||||
{
|
||||
u32 packed[3];
|
||||
struct
|
||||
{
|
||||
u8 x[3];
|
||||
u8 y[3];
|
||||
u8 z[3];
|
||||
u8 w[3];
|
||||
};
|
||||
} param;
|
||||
|
||||
// Convert the values to float24
|
||||
write24(param.x, f32tof24(x));
|
||||
write24(param.y, f32tof24(y));
|
||||
write24(param.z, f32tof24(z));
|
||||
write24(param.w, f32tof24(w));
|
||||
|
||||
// Reverse the packed words
|
||||
u32 p = param.packed[0];
|
||||
param.packed[0] = param.packed[2];
|
||||
param.packed[2] = p;
|
||||
|
||||
// Send the attribute
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_FIXEDATTRIB_DATA0, param.packed, 3);
|
||||
}
|
||||
|
||||
void C3D_ImmDrawEnd(void)
|
||||
{
|
||||
// Go back to configuration mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 1, 1);
|
||||
// Disable vertex submission mode
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 1, 0);
|
||||
// Clear the post-vertex cache
|
||||
GPUCMD_AddWrite(GPUREG_VTX_FUNC, 1);
|
||||
|
||||
C3Di_GetContext()->flags |= C3DiF_DrawUsed;
|
||||
}
|
||||
157
libs/citro3d/source/light.c
Normal file
157
libs/citro3d/source/light.c
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
#include <string.h>
|
||||
#include "context.h"
|
||||
#include <c3d/maths.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;
|
||||
|
||||
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 (enable == !(*var & 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));
|
||||
}
|
||||
|
||||
static inline u16 floattofix2_11(float x)
|
||||
{
|
||||
return (u16)((s32)(x * (1U<<11)) & 0x1FFF);
|
||||
}
|
||||
|
||||
void C3D_LightSpotDir(C3D_Light* light, float x, float y, float z)
|
||||
{
|
||||
C3Di_EnableCommon(light, true, GPU_LC1_SPOTBIT(light->id));
|
||||
C3D_FVec vec = FVec3_New(-x, -y, -z);
|
||||
vec = FVec3_Normalize(vec);
|
||||
light->conf.spotDir[0] = floattofix2_11(vec.x);
|
||||
light->conf.spotDir[1] = floattofix2_11(vec.y);
|
||||
light->conf.spotDir[2] = floattofix2_11(vec.z);
|
||||
light->flags |= C3DF_Light_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightSpotLut(C3D_Light* light, C3D_LightLut* lut)
|
||||
{
|
||||
bool hasLut = lut != NULL;
|
||||
C3Di_EnableCommon(light, hasLut, GPU_LC1_SPOTBIT(light->id));
|
||||
light->lut_SP = lut;
|
||||
if (hasLut)
|
||||
light->flags |= C3DF_Light_SPDirty;
|
||||
}
|
||||
|
||||
void C3D_LightDistAttnEnable(C3D_Light* light, bool enable)
|
||||
{
|
||||
C3Di_EnableCommon(light, enable, GPU_LC1_ATTNBIT(light->id));
|
||||
}
|
||||
|
||||
void C3D_LightDistAttn(C3D_Light* light, C3D_LightLutDA* lut)
|
||||
{
|
||||
bool hasLut = lut != NULL;
|
||||
C3Di_EnableCommon(light, hasLut, GPU_LC1_ATTNBIT(light->id));
|
||||
if (!hasLut) return;
|
||||
|
||||
light->conf.distAttnBias = f32tof20(lut->bias);
|
||||
light->conf.distAttnScale = f32tof20(lut->scale);
|
||||
light->lut_DA = &lut->lut;
|
||||
light->flags |= C3DF_Light_Dirty | C3DF_Light_DADirty;
|
||||
}
|
||||
270
libs/citro3d/source/lightenv.c
Normal file
270
libs/citro3d/source/lightenv.c
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
static void C3Di_LightEnvMtlBlend(C3D_LightEnv* env)
|
||||
{
|
||||
int i;
|
||||
C3D_Material* mtl = &env->material;
|
||||
u32 color = 0;
|
||||
for (i = 0; i < 3; i ++)
|
||||
{
|
||||
int v = 255*(mtl->emission[i] + mtl->ambient[i]*env->ambient[i]);
|
||||
if (v < 0) v = 0;
|
||||
else if (v > 255) v = 255;
|
||||
color |= v << (i*10);
|
||||
}
|
||||
env->conf.ambient = color;
|
||||
}
|
||||
|
||||
static void C3Di_LightLutUpload(u32 config, C3D_LightLut* lut)
|
||||
{
|
||||
int i;
|
||||
GPUCMD_AddWrite(GPUREG_LIGHTING_LUT_INDEX, config);
|
||||
for (i = 0; i < 256; i += 8)
|
||||
GPUCMD_AddWrites(GPUREG_LIGHTING_LUT_DATA0, &lut->data[i], 8);
|
||||
}
|
||||
|
||||
static void C3Di_LightEnvSelectLayer(C3D_LightEnv* env)
|
||||
{
|
||||
static const u8 layer_enabled[] =
|
||||
{
|
||||
BIT(GPU_LUT_D0) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA),
|
||||
BIT(GPU_LUT_FR) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA),
|
||||
BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_DA),
|
||||
BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_FR) | BIT(GPU_LUT_DA),
|
||||
0xFF &~ BIT(GPU_LUT_FR),
|
||||
0xFF &~ BIT(GPU_LUT_D1),
|
||||
0xFF &~ (BIT(GPU_LUT_RB) | BIT(GPU_LUT_RG)),
|
||||
};
|
||||
|
||||
u32 reg = ~env->conf.config[1];
|
||||
if (reg & (0xFF<< 8)) reg |= GPU_LC1_LUTBIT(GPU_LUT_SP);
|
||||
if (reg & (0xFF<<24)) reg |= GPU_LC1_LUTBIT(GPU_LUT_DA);
|
||||
reg = (reg >> 16) & 0xFF;
|
||||
int i;
|
||||
for (i = 0; i < 7; i ++)
|
||||
if ((layer_enabled[i] & reg) == reg) // Check if the layer supports all LUTs we need
|
||||
break;
|
||||
env->conf.config[0] = (env->conf.config[0] &~ (0xF<<4)) | (GPU_LIGHT_ENV_LAYER_CONFIG(i)<<4);
|
||||
}
|
||||
|
||||
static void C3Di_LightEnvUpdate(C3D_LightEnv* env)
|
||||
{
|
||||
int i;
|
||||
C3D_LightEnvConf* conf = &env->conf;
|
||||
|
||||
if (env->flags & C3DF_LightEnv_LCDirty)
|
||||
{
|
||||
conf->numLights = 0;
|
||||
conf->permutation = 0;
|
||||
for (i = 0; i < 8; i ++)
|
||||
{
|
||||
C3D_Light* light = env->lights[i];
|
||||
if (!light) continue;
|
||||
if (!(light->flags & C3DF_Light_Enabled)) continue;
|
||||
conf->permutation |= GPU_LIGHTPERM(conf->numLights++, i);
|
||||
}
|
||||
if (conf->numLights > 0) conf->numLights --;
|
||||
env->flags &= ~C3DF_LightEnv_LCDirty;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
if (env->flags & C3DF_LightEnv_MtlDirty)
|
||||
{
|
||||
C3Di_LightEnvMtlBlend(env);
|
||||
env->flags &= ~C3DF_LightEnv_MtlDirty;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
if (env->flags & C3DF_LightEnv_Dirty)
|
||||
{
|
||||
C3Di_LightEnvSelectLayer(env);
|
||||
GPUCMD_AddWrite(GPUREG_LIGHTING_AMBIENT, conf->ambient);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_NUM_LIGHTS, (u32*)&conf->numLights, 3);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_LUTINPUT_ABS, (u32*)&conf->lutInput, 3);
|
||||
GPUCMD_AddWrite(GPUREG_LIGHTING_LIGHT_PERMUTATION, conf->permutation);
|
||||
env->flags &= ~C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
if (env->flags & C3DF_LightEnv_LutDirtyAll)
|
||||
{
|
||||
for (i = 0; i < 6; i ++)
|
||||
{
|
||||
static const u8 lutIds[] = { 0, 1, 3, 4, 5, 6 };
|
||||
if (!(env->flags & C3DF_LightEnv_LutDirty(i))) continue;
|
||||
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_COMMON, (u32)lutIds[i], 0), env->luts[i]);
|
||||
}
|
||||
|
||||
env->flags &= ~C3DF_LightEnv_LutDirtyAll;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i ++)
|
||||
{
|
||||
C3D_Light* light = env->lights[i];
|
||||
if (!light) continue;
|
||||
|
||||
if (light->flags & C3DF_Light_MatDirty)
|
||||
{
|
||||
C3Di_LightMtlBlend(light);
|
||||
light->flags &= ~C3DF_Light_MatDirty;
|
||||
light->flags |= C3DF_Light_Dirty;
|
||||
}
|
||||
|
||||
if (light->flags & C3DF_Light_Dirty)
|
||||
{
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_LIGHT0_SPECULAR0 + i*0x10, (u32*)&light->conf, 12);
|
||||
light->flags &= ~C3DF_Light_Dirty;
|
||||
}
|
||||
|
||||
if (light->flags & C3DF_Light_SPDirty)
|
||||
{
|
||||
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_SP, i, 0), light->lut_SP);
|
||||
light->flags &= ~C3DF_Light_SPDirty;
|
||||
}
|
||||
|
||||
if (light->flags & C3DF_Light_DADirty)
|
||||
{
|
||||
C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_DA, i, 0), light->lut_DA);
|
||||
light->flags &= ~C3DF_Light_DADirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void C3Di_LightEnvDirty(C3D_LightEnv* env)
|
||||
{
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
int i;
|
||||
for (i = 0; i < 6; i ++)
|
||||
if (env->luts[i])
|
||||
env->flags |= C3DF_LightEnv_LutDirty(i);
|
||||
for (i = 0; i < 8; i ++)
|
||||
{
|
||||
C3D_Light* light = env->lights[i];
|
||||
if (!light) continue;
|
||||
|
||||
light->flags |= C3DF_Light_Dirty;
|
||||
if (light->lut_SP)
|
||||
light->flags |= C3DF_Light_SPDirty;
|
||||
if (light->lut_DA)
|
||||
light->flags |= C3DF_Light_DADirty;
|
||||
}
|
||||
}
|
||||
|
||||
void C3D_LightEnvInit(C3D_LightEnv* env)
|
||||
{
|
||||
memset(env, 0, sizeof(*env));
|
||||
env->Update = C3Di_LightEnvUpdate;
|
||||
env->Dirty = C3Di_LightEnvDirty;
|
||||
|
||||
env->flags = C3DF_LightEnv_Dirty;
|
||||
env->conf.config[0] = (4<<8) | BIT(27) | BIT(31);
|
||||
env->conf.config[1] = ~0;
|
||||
env->conf.lutInput.abs = 0x2222222;
|
||||
}
|
||||
|
||||
void C3D_LightEnvBind(C3D_LightEnv* env)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
if (ctx->lightEnv == env)
|
||||
return;
|
||||
|
||||
ctx->flags |= C3DiF_LightEnv;
|
||||
ctx->lightEnv = env;
|
||||
}
|
||||
|
||||
void C3D_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl)
|
||||
{
|
||||
int i;
|
||||
memcpy(&env->material, mtl, sizeof(*mtl));
|
||||
env->flags |= C3DF_LightEnv_MtlDirty;
|
||||
for (i = 0; i < 8; i ++)
|
||||
{
|
||||
C3D_Light* light = env->lights[i];
|
||||
if (light) light->flags |= C3DF_Light_MatDirty;
|
||||
}
|
||||
}
|
||||
|
||||
void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b)
|
||||
{
|
||||
env->ambient[0] = b;
|
||||
env->ambient[1] = g;
|
||||
env->ambient[2] = r;
|
||||
env->flags |= C3DF_LightEnv_MtlDirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvLut(C3D_LightEnv* env, int lutId, int input, bool abs, C3D_LightLut* lut)
|
||||
{
|
||||
static const s8 ids[] = { 0, 1, -1, 2, 3, 4, 5, -1 };
|
||||
int id = ids[lutId];
|
||||
if (id >= 0)
|
||||
{
|
||||
env->luts[id] = lut;
|
||||
if (lut)
|
||||
{
|
||||
env->conf.config[1] &= ~GPU_LC1_LUTBIT(lutId);
|
||||
env->flags |= C3DF_LightEnv_LutDirty(id);
|
||||
} else
|
||||
env->luts[id] = NULL;
|
||||
}
|
||||
|
||||
env->conf.lutInput.select &= ~GPU_LIGHTLUTINPUT(lutId, 0xF);
|
||||
env->conf.lutInput.select |= GPU_LIGHTLUTINPUT(lutId, input);
|
||||
|
||||
u32 absbit = 1 << (lutId*4 + 1);
|
||||
env->conf.lutInput.abs &= ~absbit;
|
||||
if (!abs)
|
||||
env->conf.lutInput.abs |= absbit;
|
||||
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector)
|
||||
{
|
||||
env->conf.config[0] &= ~(3<<2);
|
||||
env->conf.config[0] |= (selector&3)<<2;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode)
|
||||
{
|
||||
env->conf.config[0] &= ~(3<<28);
|
||||
env->conf.config[0] |= (mode&3)<<28;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit)
|
||||
{
|
||||
env->conf.config[0] &= ~(3<<22);
|
||||
env->conf.config[0] |= (texUnit&3)<<22;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode)
|
||||
{
|
||||
mode &= 0xF<<16;
|
||||
if (mode & (GPU_SHADOW_PRIMARY | GPU_INVERT_SHADOW | GPU_SHADOW_ALPHA))
|
||||
mode |= BIT(0);
|
||||
env->conf.config[0] &= ~((3<<28) | BIT(0));
|
||||
env->conf.config[0] |= mode;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit)
|
||||
{
|
||||
env->conf.config[0] &= ~(3<<24);
|
||||
env->conf.config[0] |= (texUnit&3)<<24;
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
|
||||
void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp)
|
||||
{
|
||||
if (clamp)
|
||||
env->conf.config[0] |= BIT(27);
|
||||
else
|
||||
env->conf.config[0] &= ~BIT(27);
|
||||
env->flags |= C3DF_LightEnv_Dirty;
|
||||
}
|
||||
66
libs/citro3d/source/lightlut.c
Normal file
66
libs/citro3d/source/lightlut.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
void LightLut_FromArray(C3D_LightLut* lut, float* data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i ++)
|
||||
{
|
||||
float in = data[i], diff = data[i+256];
|
||||
|
||||
u32 val = 0;
|
||||
if (in > 0.0)
|
||||
{
|
||||
in *= 0x1000;
|
||||
val = (in < 0x1000) ? (u32)in : 0xFFF;
|
||||
}
|
||||
|
||||
u32 val2 = 0;
|
||||
if (diff != 0.0)
|
||||
{
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = -diff;
|
||||
val2 = 0x800;
|
||||
}
|
||||
diff *= 0x800;
|
||||
val2 |= (diff < 0x800) ? (u32)diff : 0x7FF;
|
||||
}
|
||||
|
||||
lut->data[i] = val | (val2 << 12);
|
||||
}
|
||||
}
|
||||
|
||||
void LightLut_FromFunc(C3D_LightLut* lut, C3D_LightLutFunc func, float param, bool negative)
|
||||
{
|
||||
int i;
|
||||
float data[512];
|
||||
memset(data, 0, sizeof(data));
|
||||
int start = negative ? (-127) : 0;
|
||||
for (i = start; i < 128; i ++)
|
||||
{
|
||||
data[i & 0xFF] = func((float)i / 127.0f, param);
|
||||
if (i != start) data[(i & 0xFF) + 255] = data[i & 0xFF] - data[(i-1) & 0xFF];
|
||||
}
|
||||
LightLut_FromArray(lut, data);
|
||||
}
|
||||
|
||||
void LightLutDA_Create(C3D_LightLutDA* lut, C3D_LightLutFuncDA func, float from, float to, float arg0, float arg1)
|
||||
{
|
||||
int i;
|
||||
float data[512];
|
||||
data[511] = 0;
|
||||
|
||||
lut->scale = 1.0f / (to-from);
|
||||
lut->bias = -from*lut->scale;
|
||||
|
||||
for (i = 0; i < 256; i ++)
|
||||
{
|
||||
float dist = ((float)i/255 - lut->bias) / lut->scale;
|
||||
data[i] = func(dist, arg0, arg1);
|
||||
if (i > 0)
|
||||
data[i+255] = data[i]-data[i-1];
|
||||
}
|
||||
|
||||
LightLut_FromArray(&lut->lut, data);
|
||||
}
|
||||
2
libs/citro3d/source/maths/.gitignore
vendored
Normal file
2
libs/citro3d/source/maths/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.d
|
||||
*.o
|
||||
34
libs/citro3d/source/maths/mtx_fromquat.c
Normal file
34
libs/citro3d/source/maths/mtx_fromquat.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_FromQuat(C3D_Mtx* m, C3D_FQuat q)
|
||||
{
|
||||
float ii = q.i*q.i;
|
||||
float ij = q.i*q.j;
|
||||
float ik = q.i*q.k;
|
||||
float jj = q.j*q.j;
|
||||
float jk = q.j*q.k;
|
||||
float kk = q.k*q.k;
|
||||
float ri = q.r*q.i;
|
||||
float rj = q.r*q.j;
|
||||
float rk = q.r*q.k;
|
||||
|
||||
m->r[0].x = 1.0f - (2.0f * (jj + kk));
|
||||
m->r[1].x = 2.0f * (ij + rk);
|
||||
m->r[2].x = 2.0f * (ik - rj);
|
||||
m->r[3].x = 0.0f;
|
||||
|
||||
m->r[0].y = 2.0f * (ij - rk);
|
||||
m->r[1].y = 1.0f - (2.0f * (ii + kk));
|
||||
m->r[2].y = 2.0f * (jk + ri);
|
||||
m->r[3].y = 0.0f;
|
||||
|
||||
m->r[0].z = 2.0f * (ik + rj);
|
||||
m->r[1].z = 2.0f * (jk - ri);
|
||||
m->r[2].z = 1.0f - (2.0f * (ii + jj));
|
||||
m->r[3].z = 0.0f;
|
||||
|
||||
m->r[0].w = 0.0f;
|
||||
m->r[1].w = 0.0f;
|
||||
m->r[2].w = 0.0f;
|
||||
m->r[3].w = 1.0f;
|
||||
}
|
||||
10
libs/citro3d/source/maths/mtx_identity.c
Normal file
10
libs/citro3d/source/maths/mtx_identity.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Identity(C3D_Mtx* out)
|
||||
{
|
||||
// http://www.wolframalpha.com/input/?i={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i)
|
||||
out->m[i] = 0.0f;
|
||||
out->r[0].x = out->r[1].y = out->r[2].z = out->r[3].w = 1.0f;
|
||||
}
|
||||
135
libs/citro3d/source/maths/mtx_inverse.c
Normal file
135
libs/citro3d/source/maths/mtx_inverse.c
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#include <float.h>
|
||||
#include <c3d/maths.h>
|
||||
|
||||
float Mtx_Inverse(C3D_Mtx* out)
|
||||
{
|
||||
//Mtx_Inverse can be used to calculate the determinant and the inverse of the matrix.
|
||||
|
||||
C3D_Mtx inv;
|
||||
float det;
|
||||
int i;
|
||||
|
||||
inv.r[0].x = out->r[1].y * out->r[2].z * out->r[3].w -
|
||||
out->r[1].y * out->r[2].w * out->r[3].z -
|
||||
out->r[2].y * out->r[1].z * out->r[3].w +
|
||||
out->r[2].y * out->r[1].w * out->r[3].z +
|
||||
out->r[3].y * out->r[1].z * out->r[2].w -
|
||||
out->r[3].y * out->r[1].w * out->r[2].z;
|
||||
|
||||
inv.r[1].x = -out->r[1].x * out->r[2].z * out->r[3].w +
|
||||
out->r[1].x * out->r[2].w * out->r[3].z +
|
||||
out->r[2].x * out->r[1].z * out->r[3].w -
|
||||
out->r[2].x * out->r[1].w * out->r[3].z -
|
||||
out->r[3].x * out->r[1].z * out->r[2].w +
|
||||
out->r[3].x * out->r[1].w * out->r[2].z;
|
||||
|
||||
inv.r[2].x = out->r[1].x * out->r[2].y * out->r[3].w -
|
||||
out->r[1].x * out->r[2].w * out->r[3].y -
|
||||
out->r[2].x * out->r[1].y * out->r[3].w +
|
||||
out->r[2].x * out->r[1].w * out->r[3].y +
|
||||
out->r[3].x * out->r[1].y * out->r[2].w -
|
||||
out->r[3].x * out->r[1].w * out->r[2].y;
|
||||
|
||||
inv.r[3].x = -out->r[1].x * out->r[2].y * out->r[3].z +
|
||||
out->r[1].x * out->r[2].z * out->r[3].y +
|
||||
out->r[2].x * out->r[1].y * out->r[3].z -
|
||||
out->r[2].x * out->r[1].z * out->r[3].y -
|
||||
out->r[3].x * out->r[1].y * out->r[2].z +
|
||||
out->r[3].x * out->r[1].z * out->r[2].y;
|
||||
|
||||
det = out->r[0].x * inv.r[0].x + out->r[0].y * inv.r[1].x +
|
||||
out->r[0].z * inv.r[2].x + out->r[0].w * inv.r[3].x;
|
||||
|
||||
if (fabsf(det) < FLT_EPSILON)
|
||||
//Returns 0.0f if we find the determinant is less than +/- FLT_EPSILON.
|
||||
return 0.0f;
|
||||
|
||||
inv.r[0].y = -out->r[0].y * out->r[2].z * out->r[3].w +
|
||||
out->r[0].y * out->r[2].w * out->r[3].z +
|
||||
out->r[2].y * out->r[0].z * out->r[3].w -
|
||||
out->r[2].y * out->r[0].w * out->r[3].z -
|
||||
out->r[3].y * out->r[0].z * out->r[2].w +
|
||||
out->r[3].y * out->r[0].w * out->r[2].z;
|
||||
|
||||
inv.r[1].y = out->r[0].x * out->r[2].z * out->r[3].w -
|
||||
out->r[0].x * out->r[2].w * out->r[3].z -
|
||||
out->r[2].x * out->r[0].z * out->r[3].w +
|
||||
out->r[2].x * out->r[0].w * out->r[3].z +
|
||||
out->r[3].x * out->r[0].z * out->r[2].w -
|
||||
out->r[3].x * out->r[0].w * out->r[2].z;
|
||||
|
||||
inv.r[2].y = -out->r[0].x * out->r[2].y * out->r[3].w +
|
||||
out->r[0].x * out->r[2].w * out->r[3].y +
|
||||
out->r[2].x * out->r[0].y * out->r[3].w -
|
||||
out->r[2].x * out->r[0].w * out->r[3].y -
|
||||
out->r[3].x * out->r[0].y * out->r[2].w +
|
||||
out->r[3].x * out->r[0].w * out->r[2].y;
|
||||
|
||||
inv.r[3].y = out->r[0].x * out->r[2].y * out->r[3].z -
|
||||
out->r[0].x * out->r[2].z * out->r[3].y -
|
||||
out->r[2].x * out->r[0].y * out->r[3].z +
|
||||
out->r[2].x * out->r[0].z * out->r[3].y +
|
||||
out->r[3].x * out->r[0].y * out->r[2].z -
|
||||
out->r[3].x * out->r[0].z * out->r[2].y;
|
||||
|
||||
inv.r[0].z = out->r[0].y * out->r[1].z * out->r[3].w -
|
||||
out->r[0].y * out->r[1].w * out->r[3].z -
|
||||
out->r[1].y * out->r[0].z * out->r[3].w +
|
||||
out->r[1].y * out->r[0].w * out->r[3].z +
|
||||
out->r[3].y * out->r[0].z * out->r[1].w -
|
||||
out->r[3].y * out->r[0].w * out->r[1].z;
|
||||
|
||||
inv.r[1].z = -out->r[0].x * out->r[1].z * out->r[3].w +
|
||||
out->r[0].x * out->r[1].w * out->r[3].z +
|
||||
out->r[1].x * out->r[0].z * out->r[3].w -
|
||||
out->r[1].x * out->r[0].w * out->r[3].z -
|
||||
out->r[3].x * out->r[0].z * out->r[1].w +
|
||||
out->r[3].x * out->r[0].w * out->r[1].z;
|
||||
|
||||
inv.r[2].z = out->r[0].x * out->r[1].y * out->r[3].w -
|
||||
out->r[0].x * out->r[1].w * out->r[3].y -
|
||||
out->r[1].x * out->r[0].y * out->r[3].w +
|
||||
out->r[1].x * out->r[0].w * out->r[3].y +
|
||||
out->r[3].x * out->r[0].y * out->r[1].w -
|
||||
out->r[3].x * out->r[0].w * out->r[1].y;
|
||||
|
||||
inv.r[3].z = -out->r[0].x * out->r[1].y * out->r[3].z +
|
||||
out->r[0].x * out->r[1].z * out->r[3].y +
|
||||
out->r[1].x * out->r[0].y * out->r[3].z -
|
||||
out->r[1].x * out->r[0].z * out->r[3].y -
|
||||
out->r[3].x * out->r[0].y * out->r[1].z +
|
||||
out->r[3].x * out->r[0].z * out->r[1].y;
|
||||
|
||||
inv.r[0].w = -out->r[0].y * out->r[1].z * out->r[2].w +
|
||||
out->r[0].y * out->r[1].w * out->r[2].z +
|
||||
out->r[1].y * out->r[0].z * out->r[2].w -
|
||||
out->r[1].y * out->r[0].w * out->r[2].z -
|
||||
out->r[2].y * out->r[0].z * out->r[1].w +
|
||||
out->r[2].y * out->r[0].w * out->r[1].z;
|
||||
|
||||
inv.r[1].w = out->r[0].x * out->r[1].z * out->r[2].w -
|
||||
out->r[0].x * out->r[1].w * out->r[2].z -
|
||||
out->r[1].x * out->r[0].z * out->r[2].w +
|
||||
out->r[1].x * out->r[0].w * out->r[2].z +
|
||||
out->r[2].x * out->r[0].z * out->r[1].w -
|
||||
out->r[2].x * out->r[0].w * out->r[1].z;
|
||||
|
||||
inv.r[2].w = -out->r[0].x * out->r[1].y * out->r[2].w +
|
||||
out->r[0].x * out->r[1].w * out->r[2].y +
|
||||
out->r[1].x * out->r[0].y * out->r[2].w -
|
||||
out->r[1].x * out->r[0].w * out->r[2].y -
|
||||
out->r[2].x * out->r[0].y * out->r[1].w +
|
||||
out->r[2].x * out->r[0].w * out->r[1].y;
|
||||
|
||||
inv.r[3].w = out->r[0].x * out->r[1].y * out->r[2].z -
|
||||
out->r[0].x * out->r[1].z * out->r[2].y -
|
||||
out->r[1].x * out->r[0].y * out->r[2].z +
|
||||
out->r[1].x * out->r[0].z * out->r[2].y +
|
||||
out->r[2].x * out->r[0].y * out->r[1].z -
|
||||
out->r[2].x * out->r[0].z * out->r[1].y;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
out->m[i] = inv.m[i] / det;
|
||||
|
||||
return det;
|
||||
}
|
||||
37
libs/citro3d/source/maths/mtx_lookat.c
Normal file
37
libs/citro3d/source/maths/mtx_lookat.c
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_LookAt(C3D_Mtx* out, C3D_FVec cameraPosition, C3D_FVec cameraTarget, C3D_FVec cameraUpVector, bool isLeftHanded)
|
||||
{
|
||||
//Left-handed and Right-handed Look-At matrix functions are DirectX implementations.
|
||||
//Left-handed: https://msdn.microsoft.com/en-us/library/windows/desktop/bb281710
|
||||
//Right-handed: https://msdn.microsoft.com/en-us/library/windows/desktop/bb281711
|
||||
C3D_FVec xaxis, yaxis, zaxis;
|
||||
|
||||
//Order of operations is crucial.
|
||||
if (isLeftHanded)
|
||||
zaxis = FVec3_Normalize(FVec3_Subtract(cameraTarget, cameraPosition));
|
||||
else
|
||||
zaxis = FVec3_Normalize(FVec3_Subtract(cameraPosition, cameraTarget));
|
||||
xaxis = FVec3_Normalize(FVec3_Cross(cameraUpVector, zaxis));
|
||||
yaxis = FVec3_Cross(zaxis, xaxis);
|
||||
|
||||
out->r[0].x = xaxis.x;
|
||||
out->r[0].y = xaxis.y;
|
||||
out->r[0].z = xaxis.z;
|
||||
out->r[0].w = -FVec3_Dot(xaxis, cameraPosition);
|
||||
|
||||
out->r[1].x = yaxis.x;
|
||||
out->r[1].y = yaxis.y;
|
||||
out->r[1].z = yaxis.z;
|
||||
out->r[1].w = -FVec3_Dot(yaxis, cameraPosition);
|
||||
|
||||
out->r[2].x = zaxis.x;
|
||||
out->r[2].y = zaxis.y;
|
||||
out->r[2].z = zaxis.z;
|
||||
out->r[2].w = -FVec3_Dot(zaxis, cameraPosition);
|
||||
|
||||
out->r[3].x = 0.0f;
|
||||
out->r[3].y = 0.0f;
|
||||
out->r[3].z = 0.0f;
|
||||
out->r[3].w = 1.0f;
|
||||
}
|
||||
19
libs/citro3d/source/maths/mtx_multiply.c
Normal file
19
libs/citro3d/source/maths/mtx_multiply.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Multiply(C3D_Mtx* out, const C3D_Mtx* a, const C3D_Mtx* b)
|
||||
{
|
||||
// if out is a or b, then we need to avoid overwriting them
|
||||
if(out == a || out == b)
|
||||
{
|
||||
C3D_Mtx tmp;
|
||||
Mtx_Multiply(&tmp, a, b);
|
||||
Mtx_Copy(out, &tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
// http://www.wolframalpha.com/input/?i={{a,b,c,d},{e,f,g,h},{i,j,k,l},{m,n,o,p}}{{α,β,γ,δ},{ε,θ,ι,κ},{λ,μ,ν,ξ},{ο,π,ρ,σ}}
|
||||
int i, j;
|
||||
for (j = 0; j < 4; ++j)
|
||||
for (i = 0; i < 4; ++i)
|
||||
out->r[j].c[i] = a->r[j].x*b->r[0].c[i] + a->r[j].y*b->r[1].c[i] + a->r[j].z*b->r[2].c[i] + a->r[j].w*b->r[3].c[i];
|
||||
}
|
||||
11
libs/citro3d/source/maths/mtx_multiplyfvec3.c
Normal file
11
libs/citro3d/source/maths/mtx_multiplyfvec3.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FVec Mtx_MultiplyFVec3(const C3D_Mtx* mtx, C3D_FVec v)
|
||||
{
|
||||
// http://www.wolframalpha.com/input/?i={{a,b,c},{d,e,f},{g,h,i}}{x,y,z}
|
||||
float x = FVec3_Dot(mtx->r[0], v);
|
||||
float y = FVec3_Dot(mtx->r[1], v);
|
||||
float z = FVec3_Dot(mtx->r[2], v);
|
||||
|
||||
return FVec3_New(x, y, z);
|
||||
}
|
||||
12
libs/citro3d/source/maths/mtx_multiplyfvec4.c
Normal file
12
libs/citro3d/source/maths/mtx_multiplyfvec4.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FVec Mtx_MultiplyFVec4(const C3D_Mtx* mtx, C3D_FVec v)
|
||||
{
|
||||
// http://www.wolframalpha.com/input/?i={{a,b,c,d},{e,f,g,h},{i,j,k,l},{m,n,o,p}}{x,y,z,w}
|
||||
float x = FVec4_Dot(mtx->r[0], v);
|
||||
float y = FVec4_Dot(mtx->r[1], v);
|
||||
float z = FVec4_Dot(mtx->r[2], v);
|
||||
float w = FVec4_Dot(mtx->r[3], v);
|
||||
|
||||
return FVec4_New(x, y, z, w);
|
||||
}
|
||||
20
libs/citro3d/source/maths/mtx_ortho.c
Normal file
20
libs/citro3d/source/maths/mtx_ortho.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Ortho(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded)
|
||||
{
|
||||
Mtx_Zeros(mtx);
|
||||
|
||||
// Standard orthogonal projection matrix, with a fixed depth range of [-1,0] (required by PICA)
|
||||
// http://www.wolframalpha.com/input/?i={{1,0,0,0},{0,1,0,0},{0,0,0.5,-0.5},{0,0,0,1}}{{2/(r-l),0,0,(l%2Br)/(l-r)},{0,2/(t-b),0,(b%2Bt)/(b-t)},{0,0,2/(n-f),(n%2Bf)/(n-f)},{0,0,0,1}}
|
||||
|
||||
mtx->r[0].x = 2.0f / (right - left);
|
||||
mtx->r[0].w = (left + right) / (left - right);
|
||||
mtx->r[1].y = 2.0f / (top - bottom);
|
||||
mtx->r[1].w = (bottom + top) / (bottom - top);
|
||||
if (isLeftHanded)
|
||||
mtx->r[2].z = 1.0f / (far - near);
|
||||
else
|
||||
mtx->r[2].z = 1.0f / (near - far);
|
||||
mtx->r[2].w = 0.5f*(near + far) / (near - far) - 0.5f;
|
||||
mtx->r[3].w = 1.0f;
|
||||
}
|
||||
21
libs/citro3d/source/maths/mtx_orthotilt.c
Normal file
21
libs/citro3d/source/maths/mtx_orthotilt.c
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_OrthoTilt(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded)
|
||||
{
|
||||
Mtx_Zeros(mtx);
|
||||
|
||||
// Standard orthogonal projection matrix, with a fixed depth range of [-1,0] (required by PICA) and rotated τ/4 radians counterclockwise around the Z axis (due to 3DS screen orientation)
|
||||
// http://www.wolframalpha.com/input/?i={{0,1,0,0},{-1,0,0,0},{0,0,1,0},{0,0,0,1}}{{1,0,0,0},{0,1,0,0},{0,0,0.5,-0.5},{0,0,0,1}}
|
||||
// http://www.wolframalpha.com/input/?i={{0,1,0,0},{-1,0,0,0},{0,0,0.5,-0.5},{0,0,0,1}}{{2/(r-l),0,0,(l%2Br)/(l-r)},{0,2/(t-b),0,(b%2Bt)/(b-t)},{0,0,2/(n-f),(n%2Bf)/(n-f)},{0,0,0,1}}
|
||||
|
||||
mtx->r[0].y = 2.0f / (top - bottom);
|
||||
mtx->r[0].w = (bottom + top) / (bottom - top);
|
||||
mtx->r[1].x = 2.0f / (left - right);
|
||||
mtx->r[1].w = (left + right) / (right - left);
|
||||
if (isLeftHanded)
|
||||
mtx->r[2].z = 1.0f / (far - near);
|
||||
else
|
||||
mtx->r[2].z = 1.0f / (near - far);
|
||||
mtx->r[2].w = 0.5f*(near + far) / (near - far) - 0.5f;
|
||||
mtx->r[3].w = 1.0f;
|
||||
}
|
||||
26
libs/citro3d/source/maths/mtx_persp.c
Normal file
26
libs/citro3d/source/maths/mtx_persp.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Persp(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bool isLeftHanded)
|
||||
{
|
||||
float fovy_tan = tanf(fovy/2.0f);
|
||||
|
||||
Mtx_Zeros(mtx);
|
||||
|
||||
// Standard perspective projection matrix, with a fixed depth range of [-1,0] (required by PICA)
|
||||
// http://www.wolframalpha.com/input/?i={{1,0,0,0},{0,1,0,0},{0,0,0.5,-0.5},{0,0,0,1}}{{1/(a*tan(v)),0,0,0},{0,1/tan(v),0,0},{0,0,(n%2Bf)/(n-f),(fn)/(n-f)},{0,0,0,-1}}
|
||||
|
||||
mtx->r[0].x = 1.0f / (aspect * fovy_tan);
|
||||
mtx->r[1].y = 1.0f / fovy_tan;
|
||||
mtx->r[2].w = far*near / (near - far);
|
||||
|
||||
if (isLeftHanded)
|
||||
{
|
||||
mtx->r[2].z = 0.5f*(far + near) / (far - near) - 0.5f;
|
||||
mtx->r[3].z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx->r[2].z = 0.5f*(far + near) / (near - far) + 0.5f;
|
||||
mtx->r[3].z = -1.0f;
|
||||
}
|
||||
}
|
||||
28
libs/citro3d/source/maths/mtx_perspstereo.c
Normal file
28
libs/citro3d/source/maths/mtx_perspstereo.c
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_PerspStereo(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded)
|
||||
{
|
||||
float fovy_tan = tanf(fovy/2.0f);
|
||||
float fovy_tan_aspect = fovy_tan*aspect;
|
||||
float shift = iod / (2.0f*screen); // 'near' not in the numerator because it cancels out in mp.r[1].z
|
||||
|
||||
Mtx_Zeros(mtx);
|
||||
|
||||
mtx->r[0].x = 1.0f / fovy_tan_aspect;
|
||||
mtx->r[0].w = -iod / 2.0f;
|
||||
mtx->r[1].y = 1.0f / fovy_tan;
|
||||
mtx->r[2].w = near * far / (near - far);
|
||||
|
||||
if (isLeftHanded)
|
||||
{
|
||||
mtx->r[0].z = shift / fovy_tan_aspect;
|
||||
mtx->r[2].z = 0.5f*(near + far) / (far - near) - 0.5f;
|
||||
mtx->r[3].z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx->r[0].z = -shift / fovy_tan_aspect;
|
||||
mtx->r[2].z = 0.5f*(near + far) / (near - far) + 0.5f;
|
||||
mtx->r[3].z = -1.0f;
|
||||
}
|
||||
}
|
||||
33
libs/citro3d/source/maths/mtx_perspstereotilt.c
Normal file
33
libs/citro3d/source/maths/mtx_perspstereotilt.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_PerspStereoTilt(C3D_Mtx* mtx, float fovx, float invaspect, float near, float far, float iod, float screen, bool isLeftHanded)
|
||||
{
|
||||
// Notes:
|
||||
// Once again, we are passed "fovy" and the "aspect ratio"; however the 3DS screens are sideways,
|
||||
// and the formula had to be tweaked. With stereo, left/right separation becomes top/bottom separation.
|
||||
// The detailed mathematical explanation is in mtx_persptilt.c.
|
||||
|
||||
float fovx_tan = tanf(fovx/2.0f);
|
||||
float fovx_tan_invaspect = fovx_tan*invaspect;
|
||||
float shift = iod / (2.0f*screen); // 'near' not in the numerator because it cancels out in mp.r[1].z
|
||||
|
||||
Mtx_Zeros(mtx);
|
||||
|
||||
mtx->r[0].y = 1.0f / fovx_tan;
|
||||
mtx->r[1].x = -1.0f / fovx_tan_invaspect;
|
||||
mtx->r[1].w = iod / 2.0f;
|
||||
mtx->r[2].w = near * far / (near - far);
|
||||
|
||||
if (isLeftHanded)
|
||||
{
|
||||
mtx->r[1].z = -shift / fovx_tan_invaspect;
|
||||
mtx->r[2].z = 0.5f*(near + far) / (far - near) - 0.5f;
|
||||
mtx->r[3].z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx->r[1].z = shift / fovx_tan_invaspect;
|
||||
mtx->r[2].z = 0.5f*(near + far) / (near - far) + 0.5f;
|
||||
mtx->r[3].z = -1.0f;
|
||||
}
|
||||
}
|
||||
46
libs/citro3d/source/maths/mtx_persptilt.c
Normal file
46
libs/citro3d/source/maths/mtx_persptilt.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_PerspTilt(C3D_Mtx* mtx, float fovx, float invaspect, float near, float far, bool isLeftHanded)
|
||||
{
|
||||
// Notes:
|
||||
// We are passed "fovy" and the "aspect ratio". However, the 3DS screens are sideways,
|
||||
// and so are these parameters -- in fact, they are actually the fovx and the inverse
|
||||
// of the aspect ratio. Therefore the formula for the perspective projection matrix
|
||||
// had to be modified to be expressed in these terms instead.
|
||||
|
||||
// Notes:
|
||||
// Includes adjusting depth range from [-1,1] to [-1,0]
|
||||
// Includes rotation of the matrix one quarter of a turn clockwise in order to fix the 3DS screens' orientation
|
||||
|
||||
// Notes:
|
||||
// fovx = 2 atan(tan(fovy/2)*w/h)
|
||||
// fovy = 2 atan(tan(fovx/2)*h/w)
|
||||
// invaspect = h/w
|
||||
|
||||
// a0,0 = h / (w*tan(fovy/2)) =
|
||||
// = h / (w*tan(2 atan(tan(fovx/2)*h/w) / 2)) =
|
||||
// = h / (w*tan( atan(tan(fovx/2)*h/w) )) =
|
||||
// = h / (w * tan(fovx/2)*h/w) =
|
||||
// = 1 / tan(fovx/2)
|
||||
|
||||
// a1,1 = 1 / tan(fovy/2) = (...) = w / (h*tan(fovx/2))
|
||||
|
||||
float fovx_tan = tanf(fovx/2.0f);
|
||||
|
||||
Mtx_Zeros(mtx);
|
||||
|
||||
mtx->r[0].y = 1.0f / fovx_tan;
|
||||
mtx->r[1].x = -1.0f / (fovx_tan*invaspect);
|
||||
mtx->r[2].w = far*near / (near - far);
|
||||
|
||||
if (isLeftHanded)
|
||||
{
|
||||
mtx->r[2].z = 0.5f*(far + near) / (far - near) - 0.5f;
|
||||
mtx->r[3].z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx->r[2].z = 0.5f*(far + near) / (near - far) + 0.5f;
|
||||
mtx->r[3].z = -1.0f;
|
||||
}
|
||||
}
|
||||
72
libs/citro3d/source/maths/mtx_rotate.c
Normal file
72
libs/citro3d/source/maths/mtx_rotate.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Rotate(C3D_Mtx* mtx, C3D_FVec axis, float angle, bool bRightSide)
|
||||
{
|
||||
size_t i;
|
||||
C3D_Mtx om;
|
||||
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
float t = 1.0f - c;
|
||||
|
||||
axis = FVec3_Normalize(axis);
|
||||
|
||||
float x = axis.x;
|
||||
float y = axis.y;
|
||||
float z = axis.z;
|
||||
float w;
|
||||
|
||||
om.r[0].x = t*x*x + c;
|
||||
om.r[1].x = t*x*y + s*z;
|
||||
om.r[2].x = t*x*z - s*y;
|
||||
//om.r[3].x = 0.0f; //optimized out
|
||||
|
||||
om.r[0].y = t*y*x - s*z;
|
||||
om.r[1].y = t*y*y + c;
|
||||
om.r[2].y = t*y*z + s*x;
|
||||
//om.r[3].y = 0.0f; //optimized out
|
||||
|
||||
om.r[0].z = t*z*x + s*y;
|
||||
om.r[1].z = t*z*y - s*x;
|
||||
om.r[2].z = t*z*z + c;
|
||||
//om.r[3].z = 0.0f; //optimized out
|
||||
|
||||
/* optimized out
|
||||
om.r[0].w = 0.0f;
|
||||
om.r[1].w = 0.0f;
|
||||
om.r[2].w = 0.0f;
|
||||
om.r[3].w = 1.0f;
|
||||
*/
|
||||
|
||||
if (bRightSide)
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
x = mtx->r[i].x*om.r[0].x + mtx->r[i].y*om.r[1].x + mtx->r[i].z*om.r[2].x;
|
||||
y = mtx->r[i].x*om.r[0].y + mtx->r[i].y*om.r[1].y + mtx->r[i].z*om.r[2].y;
|
||||
z = mtx->r[i].x*om.r[0].z + mtx->r[i].y*om.r[1].z + mtx->r[i].z*om.r[2].z;
|
||||
|
||||
mtx->r[i].x = x;
|
||||
mtx->r[i].y = y;
|
||||
mtx->r[i].z = z;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
x = mtx->r[0].x*om.r[i].x + mtx->r[1].x*om.r[i].y + mtx->r[2].x*om.r[i].z;
|
||||
y = mtx->r[0].y*om.r[i].x + mtx->r[1].y*om.r[i].y + mtx->r[2].y*om.r[i].z;
|
||||
z = mtx->r[0].z*om.r[i].x + mtx->r[1].z*om.r[i].y + mtx->r[2].z*om.r[i].z;
|
||||
w = mtx->r[0].w*om.r[i].x + mtx->r[1].w*om.r[i].y + mtx->r[2].w*om.r[i].z;
|
||||
|
||||
om.r[i].x = x;
|
||||
om.r[i].y = y;
|
||||
om.r[i].z = z;
|
||||
om.r[i].w = w;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; ++i)
|
||||
mtx->r[i] = om.r[i];
|
||||
}
|
||||
}
|
||||
30
libs/citro3d/source/maths/mtx_rotatex.c
Normal file
30
libs/citro3d/source/maths/mtx_rotatex.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_RotateX(C3D_Mtx* mtx, float angle, bool bRightSide)
|
||||
{
|
||||
float a, b;
|
||||
float cosAngle = cosf(angle);
|
||||
float sinAngle = sinf(angle);
|
||||
size_t i;
|
||||
|
||||
if (bRightSide)
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = mtx->r[i].y*cosAngle + mtx->r[i].z*sinAngle;
|
||||
b = mtx->r[i].z*cosAngle - mtx->r[i].y*sinAngle;
|
||||
mtx->r[i].y = a;
|
||||
mtx->r[i].z = b;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = mtx->r[1].c[i]*cosAngle - mtx->r[2].c[i]*sinAngle;
|
||||
b = mtx->r[2].c[i]*cosAngle + mtx->r[1].c[i]*sinAngle;
|
||||
mtx->r[1].c[i] = a;
|
||||
mtx->r[2].c[i] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
libs/citro3d/source/maths/mtx_rotatey.c
Normal file
30
libs/citro3d/source/maths/mtx_rotatey.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_RotateY(C3D_Mtx* mtx, float angle, bool bRightSide)
|
||||
{
|
||||
float a, b;
|
||||
float cosAngle = cosf(angle);
|
||||
float sinAngle = sinf(angle);
|
||||
size_t i;
|
||||
|
||||
if (bRightSide)
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = mtx->r[i].x*cosAngle - mtx->r[i].z*sinAngle;
|
||||
b = mtx->r[i].z*cosAngle + mtx->r[i].x*sinAngle;
|
||||
mtx->r[i].x = a;
|
||||
mtx->r[i].z = b;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = mtx->r[0].c[i]*cosAngle + mtx->r[2].c[i]*sinAngle;
|
||||
b = mtx->r[2].c[i]*cosAngle - mtx->r[0].c[i]*sinAngle;
|
||||
mtx->r[0].c[i] = a;
|
||||
mtx->r[2].c[i] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
libs/citro3d/source/maths/mtx_rotatez.c
Normal file
30
libs/citro3d/source/maths/mtx_rotatez.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide)
|
||||
{
|
||||
float a, b;
|
||||
float cosAngle = cosf(angle);
|
||||
float sinAngle = sinf(angle);
|
||||
size_t i;
|
||||
|
||||
if (bRightSide)
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = mtx->r[i].x*cosAngle + mtx->r[i].y*sinAngle;
|
||||
b = mtx->r[i].y*cosAngle - mtx->r[i].x*sinAngle;
|
||||
mtx->r[i].x = a;
|
||||
mtx->r[i].y = b;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = mtx->r[0].c[i]*cosAngle - mtx->r[1].c[i]*sinAngle;
|
||||
b = mtx->r[1].c[i]*cosAngle + mtx->r[0].c[i]*sinAngle;
|
||||
mtx->r[0].c[i] = a;
|
||||
mtx->r[1].c[i] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
libs/citro3d/source/maths/mtx_scale.c
Normal file
12
libs/citro3d/source/maths/mtx_scale.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Scale(C3D_Mtx* mtx, float x, float y, float z)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
mtx->r[i].x *= x;
|
||||
mtx->r[i].y *= y;
|
||||
mtx->r[i].z *= z;
|
||||
}
|
||||
}
|
||||
21
libs/citro3d/source/maths/mtx_translate.c
Normal file
21
libs/citro3d/source/maths/mtx_translate.c
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
void Mtx_Translate(C3D_Mtx* mtx, float x, float y, float z, bool bRightSide)
|
||||
{
|
||||
|
||||
C3D_FVec v = FVec4_New(x, y, z, 1.0f);
|
||||
int i, j;
|
||||
|
||||
if (bRightSide)
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
mtx->r[i].w = FVec4_Dot(mtx->r[i], v);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; j < 3; ++j)
|
||||
for (i = 0; i < 4; ++i)
|
||||
mtx->r[j].c[i] += mtx->r[3].c[i] * v.c[3-j];
|
||||
}
|
||||
|
||||
}
|
||||
13
libs/citro3d/source/maths/quat_crossfvec3.c
Normal file
13
libs/citro3d/source/maths/quat_crossfvec3.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FVec Quat_CrossFVec3(C3D_FQuat q, C3D_FVec v)
|
||||
{
|
||||
C3D_FVec qv = FVec3_New(q.i, q.j, q.k);
|
||||
C3D_FVec uv = FVec3_Cross(qv, v);
|
||||
C3D_FVec uuv = FVec3_Cross(qv, uv);
|
||||
|
||||
uv = FVec3_Scale(uv, 2.0f * q.r);
|
||||
uuv = FVec3_Scale(uuv, 2.0f);
|
||||
|
||||
return FVec3_Add(v, FVec3_Add(uv, uuv));
|
||||
}
|
||||
11
libs/citro3d/source/maths/quat_multiply.c
Normal file
11
libs/citro3d/source/maths/quat_multiply.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FQuat Quat_Multiply(C3D_FQuat lhs, C3D_FQuat rhs)
|
||||
{
|
||||
float i = lhs.r*rhs.i + lhs.i*rhs.r + lhs.j*rhs.k - lhs.k*rhs.j;
|
||||
float j = lhs.r*rhs.j + lhs.j*rhs.r + lhs.k*rhs.i - lhs.i*rhs.k;
|
||||
float k = lhs.r*rhs.k + lhs.k*rhs.r + lhs.i*rhs.j - lhs.j*rhs.i;
|
||||
float r = lhs.r*rhs.r - lhs.i*rhs.i - lhs.j*rhs.j - lhs.k*rhs.k;
|
||||
|
||||
return Quat_New(i, j, k, r);
|
||||
}
|
||||
23
libs/citro3d/source/maths/quat_pow.c
Normal file
23
libs/citro3d/source/maths/quat_pow.c
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include <float.h>
|
||||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FQuat Quat_Pow(C3D_FQuat q, float p)
|
||||
{
|
||||
// if the power is very near to zero, return the identity quaternion to avoid blowing up with division
|
||||
if (p > -FLT_EPSILON && p < FLT_EPSILON)
|
||||
return Quat_Identity();
|
||||
|
||||
float mag = FVec4_Magnitude(q);
|
||||
|
||||
// if the magnitude is very near to one, this is equivalent to raising the real component by the power
|
||||
// also, acosf(1) == 0 and sinf(0) == 0 so you would get a divide-by-zero anyway
|
||||
if (fabsf(q.r / mag) > 1.0f - FLT_EPSILON && fabsf(q.r / mag) < 1.0f + FLT_EPSILON)
|
||||
return Quat_New(0.0f, 0.0f, 0.0f, powf(q.r, p));
|
||||
|
||||
float angle = acosf(q.r / mag);
|
||||
float newAngle = angle * p;
|
||||
float div = sinf(newAngle) / sinf(angle);
|
||||
float Mag = powf(mag, p - 1.0f);
|
||||
|
||||
return Quat_New(q.i*div*Mag, q.j*div*Mag, q.k*div*Mag, cosf(newAngle)*mag*Mag);
|
||||
}
|
||||
16
libs/citro3d/source/maths/quat_rotate.c
Normal file
16
libs/citro3d/source/maths/quat_rotate.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FQuat Quat_Rotate(C3D_FQuat q, C3D_FVec axis, float r, bool bRightSide)
|
||||
{
|
||||
float halfAngle = r/2.0f;
|
||||
float s = sinf(halfAngle);
|
||||
|
||||
axis = FVec3_Normalize(axis);
|
||||
|
||||
C3D_FQuat tmp = Quat_New(axis.x*s, axis.y*s, axis.z*s, cosf(halfAngle));
|
||||
|
||||
if (bRightSide)
|
||||
return Quat_Multiply(tmp, q);
|
||||
else
|
||||
return Quat_Multiply(q, tmp);
|
||||
}
|
||||
12
libs/citro3d/source/maths/quat_rotatex.c
Normal file
12
libs/citro3d/source/maths/quat_rotatex.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FQuat Quat_RotateX(C3D_FQuat q, float r, bool bRightSide)
|
||||
{
|
||||
float c = cosf(r/2.0f);
|
||||
float s = sinf(r/2.0f);
|
||||
|
||||
if (bRightSide)
|
||||
return Quat_New(q.r*s + q.i*c, q.j*c - q.k*s, q.k*c + q.j*s, q.r*c - q.i*s);
|
||||
else
|
||||
return Quat_New(q.r*s + q.i*c, q.j*c + q.k*s, q.k*c - q.j*s, q.r*c - q.i*s);
|
||||
}
|
||||
12
libs/citro3d/source/maths/quat_rotatey.c
Normal file
12
libs/citro3d/source/maths/quat_rotatey.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FQuat Quat_RotateY(C3D_FQuat q, float r, bool bRightSide)
|
||||
{
|
||||
float c = cosf(r/2.0f);
|
||||
float s = sinf(r/2.0f);
|
||||
|
||||
if (bRightSide)
|
||||
return Quat_New(q.i*c + q.k*s, q.r*s + q.j*c, q.k*c - q.i*s, q.r*c - q.j*s);
|
||||
else
|
||||
return Quat_New(q.i*c - q.k*s, q.r*s + q.j*c, q.k*c + q.i*s, q.r*c - q.j*s);
|
||||
}
|
||||
12
libs/citro3d/source/maths/quat_rotatez.c
Normal file
12
libs/citro3d/source/maths/quat_rotatez.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <c3d/maths.h>
|
||||
|
||||
C3D_FQuat Quat_RotateZ(C3D_FQuat q, float r, bool bRightSide)
|
||||
{
|
||||
float c = cosf(r/2.0f);
|
||||
float s = sinf(r/2.0f);
|
||||
|
||||
if (bRightSide)
|
||||
return Quat_New(q.i*c - q.j*s, q.j*c + q.i*s, q.r*s + q.k*c, q.r*c - q.k*s);
|
||||
else
|
||||
return Quat_New(q.i*c + q.j*s, q.j*c - q.i*s, q.r*s + q.k*c, q.r*c - q.k*s);
|
||||
}
|
||||
43
libs/citro3d/source/mtxstack.c
Normal file
43
libs/citro3d/source/mtxstack.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include <c3d/mtxstack.h>
|
||||
#include <c3d/uniforms.h>
|
||||
|
||||
void MtxStack_Init(C3D_MtxStack* stk)
|
||||
{
|
||||
stk->pos = 0;
|
||||
stk->unifPos = 0xFF;
|
||||
stk->isDirty = true;
|
||||
Mtx_Identity(&stk->m[0]);
|
||||
}
|
||||
|
||||
void MtxStack_Bind(C3D_MtxStack* stk, GPU_SHADER_TYPE unifType, int unifPos, int unifLen)
|
||||
{
|
||||
stk->unifType = unifType;
|
||||
stk->unifPos = unifPos;
|
||||
stk->unifLen = unifLen;
|
||||
stk->isDirty = true;
|
||||
}
|
||||
|
||||
C3D_Mtx* MtxStack_Push(C3D_MtxStack* stk)
|
||||
{
|
||||
if (stk->pos == (C3D_MTXSTACK_SIZE-1)) return NULL;
|
||||
stk->pos ++;
|
||||
Mtx_Copy(&stk->m[stk->pos], &stk->m[stk->pos-1]);
|
||||
return MtxStack_Cur(stk);
|
||||
}
|
||||
|
||||
C3D_Mtx* MtxStack_Pop(C3D_MtxStack* stk)
|
||||
{
|
||||
if (stk->pos == 0) return NULL;
|
||||
stk->pos --;
|
||||
return MtxStack_Cur(stk);
|
||||
}
|
||||
|
||||
void MtxStack_Update(C3D_MtxStack* stk)
|
||||
{
|
||||
if (!stk->isDirty) return;
|
||||
|
||||
if (stk->unifPos != 0xFF)
|
||||
C3D_FVUnifMtxNx4(stk->unifType, stk->unifPos, &stk->m[stk->pos], stk->unifLen);
|
||||
|
||||
stk->isDirty = false;
|
||||
}
|
||||
110
libs/citro3d/source/renderbuffer.c
Normal file
110
libs/citro3d/source/renderbuffer.c
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#include "context.h"
|
||||
#include <string.h>
|
||||
|
||||
static const u8 colorFmtSizes[] = {2,1,0,0,0};
|
||||
static const u8 depthFmtSizes[] = {0,0,1,2};
|
||||
|
||||
static inline u16 getColorBufFillFlag(int fmt)
|
||||
{
|
||||
if (fmt < 0) return 0;
|
||||
return BIT(0) | ((u32)colorFmtSizes[fmt] << 8);
|
||||
}
|
||||
|
||||
static inline u16 getDepthBufFillFlag(int fmt)
|
||||
{
|
||||
if (fmt < 0) return 0;
|
||||
return BIT(0) | ((u32)depthFmtSizes[fmt] << 8);
|
||||
}
|
||||
|
||||
static inline u32 getColorBufFormatReg(int fmt)
|
||||
{
|
||||
return (fmt << 16) | colorFmtSizes[fmt];
|
||||
}
|
||||
|
||||
static inline GPU_TEXCOLOR colorFmtFromDepthFmt(int fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case GPU_RB_DEPTH16:
|
||||
return GPU_RGB565;
|
||||
case GPU_RB_DEPTH24:
|
||||
return GPU_RGB8;
|
||||
case GPU_RB_DEPTH24_STENCIL8:
|
||||
return GPU_RGBA8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool C3D_RenderBufInit(C3D_RenderBuf* rb, int width, int height, int colorFmt, int depthFmt)
|
||||
{
|
||||
memset(rb, 0, sizeof(*rb));
|
||||
|
||||
rb->depthFmt = depthFmt;
|
||||
rb->clearColor = rb->clearDepth = 0;
|
||||
|
||||
if (colorFmt < 0)
|
||||
return false;
|
||||
if (!C3D_TexInitVRAM(&rb->colorBuf, width, height, colorFmt))
|
||||
return false;
|
||||
|
||||
if (depthFmt >= 0)
|
||||
{
|
||||
if (!C3D_TexInitVRAM(&rb->depthBuf, width, height, colorFmtFromDepthFmt(depthFmt)))
|
||||
{
|
||||
C3D_TexDelete(&rb->colorBuf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_RenderBufClearAsync(C3D_RenderBuf* rb)
|
||||
{
|
||||
GX_MemoryFill(
|
||||
(u32*)rb->colorBuf.data, rb->clearColor, (u32*)((u8*)rb->colorBuf.data+rb->colorBuf.size), getColorBufFillFlag(rb->colorBuf.fmt),
|
||||
(u32*)rb->depthBuf.data, rb->clearDepth, (u32*)((u8*)rb->depthBuf.data+rb->depthBuf.size), getDepthBufFillFlag(rb->depthFmt));
|
||||
}
|
||||
|
||||
void C3D_RenderBufTransferAsync(C3D_RenderBuf* rb, u32* frameBuf, u32 flags)
|
||||
{
|
||||
u32 dim = GX_BUFFER_DIM((u32)rb->colorBuf.width, (u32)rb->colorBuf.height);
|
||||
GX_DisplayTransfer((u32*)rb->colorBuf.data, dim, frameBuf, dim, flags);
|
||||
}
|
||||
|
||||
void C3D_RenderBufBind(C3D_RenderBuf* rb)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
ctx->flags |= C3DiF_RenderBuf;
|
||||
ctx->rb = rb;
|
||||
C3D_SetViewport(0, 0, rb->colorBuf.width, rb->colorBuf.height);
|
||||
}
|
||||
|
||||
void C3Di_RenderBufBind(C3D_RenderBuf* rb)
|
||||
{
|
||||
u32 param[4] = { 0, 0, 0, 0 };
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 1);
|
||||
|
||||
param[0] = osConvertVirtToPhys(rb->depthBuf.data) >> 3;
|
||||
param[1] = osConvertVirtToPhys(rb->colorBuf.data) >> 3;
|
||||
param[2] = 0x01000000 | (((u32)(rb->colorBuf.height-1) & 0xFFF) << 12) | (rb->colorBuf.width & 0xFFF);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, param, 3);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_RENDERBUF_DIM, param[2]);
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, rb->depthFmt >= 0 ? rb->depthFmt : GPU_RB_DEPTH16);
|
||||
GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, getColorBufFormatReg(rb->colorBuf.fmt));
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_BLOCK32, 0x00000000); //?
|
||||
|
||||
// Enable or disable color/depth buffers
|
||||
param[0] = param[1] = rb->colorBuf.data ? 0xF : 0;
|
||||
param[2] = param[3] = rb->depthBuf.data ? 0x2 : 0;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_COLORBUFFER_READ, param, 4);
|
||||
}
|
||||
|
||||
void C3D_RenderBufDelete(C3D_RenderBuf* rb)
|
||||
{
|
||||
C3D_TexDelete(&rb->colorBuf);
|
||||
C3D_TexDelete(&rb->depthBuf);
|
||||
}
|
||||
404
libs/citro3d/source/renderqueue.c
Normal file
404
libs/citro3d/source/renderqueue.c
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
#include "context.h"
|
||||
#include <c3d/renderqueue.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static C3D_RenderTarget *firstTarget, *lastTarget;
|
||||
static C3D_RenderTarget *linkedTarget[3];
|
||||
static C3D_RenderTarget *transferQueue, *clearQueue;
|
||||
|
||||
static struct
|
||||
{
|
||||
C3D_RenderTarget* targetList;
|
||||
u32* cmdBuf;
|
||||
u32 cmdBufSize;
|
||||
u8 flags;
|
||||
} queuedFrame[2];
|
||||
static u8 queueSwap, queuedCount, queuedState;
|
||||
|
||||
static bool inFrame, inSafeTransfer, inSafeClear;
|
||||
|
||||
static void onRenderFinish(void* unused);
|
||||
static void onTransferFinish(void* unused);
|
||||
static void onClearDone(void* unused);
|
||||
|
||||
static void performDraw(void)
|
||||
{
|
||||
gspSetEventCallback(GSPGPU_EVENT_P3D, onRenderFinish, NULL, true);
|
||||
GX_ProcessCommandList(queuedFrame[queueSwap].cmdBuf, queuedFrame[queueSwap].cmdBufSize, queuedFrame[queueSwap].flags);
|
||||
}
|
||||
|
||||
static void performTransfer(void)
|
||||
{
|
||||
if (inSafeTransfer) return; // Let the safe transfer finish handler retry this
|
||||
C3D_RenderBuf* renderBuf = &transferQueue->renderBuf;
|
||||
u32* frameBuf = (u32*)gfxGetFramebuffer(transferQueue->screen, transferQueue->side, NULL, NULL);
|
||||
if (transferQueue->side == GFX_LEFT)
|
||||
gfxConfigScreen(transferQueue->screen, false);
|
||||
gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true);
|
||||
C3D_RenderBufTransferAsync(renderBuf, frameBuf, transferQueue->transferFlags);
|
||||
}
|
||||
|
||||
static void performClear(void)
|
||||
{
|
||||
if (inSafeClear) return; // Let the safe clear finish handler retry this
|
||||
C3D_RenderBuf* renderBuf = &clearQueue->renderBuf;
|
||||
// TODO: obey renderBuf->clearBits
|
||||
gspSetEventCallback(renderBuf->colorBuf.data ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true);
|
||||
C3D_RenderBufClearAsync(renderBuf);
|
||||
}
|
||||
|
||||
static void updateFrameQueue(void)
|
||||
{
|
||||
C3D_RenderTarget* a;
|
||||
if (queuedState>0) return; // Still rendering
|
||||
|
||||
// Check that all targets are OK to be drawn on
|
||||
for (a = queuedFrame[queueSwap].targetList; a; a = a->frame[queueSwap])
|
||||
if (!a->drawOk)
|
||||
return; // Nope, we can't start rendering yet
|
||||
|
||||
// Start rendering the frame
|
||||
queuedState=1;
|
||||
for (a = queuedFrame[queueSwap].targetList; a; a = a->frame[queueSwap])
|
||||
a->drawOk = false;
|
||||
performDraw();
|
||||
}
|
||||
|
||||
static void transferTarget(C3D_RenderTarget* target)
|
||||
{
|
||||
C3D_RenderTarget* a;
|
||||
target->transferOk = false;
|
||||
target->link = NULL;
|
||||
if (!transferQueue)
|
||||
{
|
||||
transferQueue = target;
|
||||
performTransfer();
|
||||
return;
|
||||
}
|
||||
for (a = transferQueue; a->link; a = a->link);
|
||||
a->link = target;
|
||||
}
|
||||
|
||||
static void clearTarget(C3D_RenderTarget* target)
|
||||
{
|
||||
C3D_RenderTarget* a;
|
||||
target->link = NULL;
|
||||
if (!clearQueue)
|
||||
{
|
||||
clearQueue = target;
|
||||
performClear();
|
||||
return;
|
||||
}
|
||||
for (a = clearQueue; a->link; a = a->link);
|
||||
a->link = target;
|
||||
}
|
||||
|
||||
static void onVBlank0(void* unused)
|
||||
{
|
||||
if (!linkedTarget[0]) return;
|
||||
|
||||
if (gfxIs3D())
|
||||
{
|
||||
if (linkedTarget[1] && linkedTarget[1]->transferOk)
|
||||
transferTarget(linkedTarget[1]);
|
||||
else if (linkedTarget[0]->transferOk)
|
||||
{
|
||||
// Use a temporary copy of the left framebuffer to fill in the missing right image.
|
||||
static C3D_RenderTarget temp;
|
||||
memcpy(&temp, linkedTarget[0], sizeof(temp));
|
||||
temp.side = GFX_RIGHT;
|
||||
temp.clearBits = false;
|
||||
transferTarget(&temp);
|
||||
}
|
||||
}
|
||||
if (linkedTarget[0]->transferOk)
|
||||
transferTarget(linkedTarget[0]);
|
||||
}
|
||||
|
||||
static void onVBlank1(void* unused)
|
||||
{
|
||||
if (linkedTarget[2] && linkedTarget[2]->transferOk)
|
||||
transferTarget(linkedTarget[2]);
|
||||
}
|
||||
|
||||
void onRenderFinish(void* unused)
|
||||
{
|
||||
C3D_RenderTarget *a, *next;
|
||||
|
||||
// The following check should never trigger
|
||||
if (queuedState!=1) svcBreak(USERBREAK_PANIC);
|
||||
|
||||
for (a = queuedFrame[queueSwap].targetList; a; a = next)
|
||||
{
|
||||
next = a->frame[queueSwap];
|
||||
a->frame[queueSwap] = NULL;
|
||||
if (a->linked)
|
||||
a->transferOk = true;
|
||||
else if (a->clearBits)
|
||||
clearTarget(a);
|
||||
else
|
||||
a->drawOk = true;
|
||||
}
|
||||
|
||||
// Consume the frame that has been just rendered
|
||||
memset(&queuedFrame[queueSwap], 0, sizeof(queuedFrame[queueSwap]));
|
||||
queueSwap ^= 1;
|
||||
queuedCount--;
|
||||
queuedState = 0;
|
||||
|
||||
// Update the frame queue if there are still frames to render
|
||||
if (queuedCount>0)
|
||||
updateFrameQueue();
|
||||
}
|
||||
|
||||
void onTransferFinish(void* unused)
|
||||
{
|
||||
C3D_RenderTarget* target = transferQueue;
|
||||
if (inSafeTransfer)
|
||||
{
|
||||
inSafeTransfer = false;
|
||||
// Try again if there are queued transfers
|
||||
if (target)
|
||||
performTransfer();
|
||||
return;
|
||||
}
|
||||
transferQueue = target->link;
|
||||
if (target->clearBits)
|
||||
clearTarget(target);
|
||||
else
|
||||
target->drawOk = true;
|
||||
if (transferQueue)
|
||||
performTransfer();
|
||||
if (target->drawOk && queuedCount>0 && queuedState==0)
|
||||
updateFrameQueue();
|
||||
}
|
||||
|
||||
void onClearDone(void* unused)
|
||||
{
|
||||
C3D_RenderTarget* target = clearQueue;
|
||||
if (inSafeClear)
|
||||
{
|
||||
inSafeClear = false;
|
||||
// Try again if there are queued clears
|
||||
if (target)
|
||||
performClear();
|
||||
return;
|
||||
}
|
||||
clearQueue = target->link;
|
||||
target->drawOk = true;
|
||||
if (clearQueue)
|
||||
performClear();
|
||||
if (queuedCount>0 && queuedState==0)
|
||||
updateFrameQueue();
|
||||
}
|
||||
|
||||
static void C3Di_RenderQueueInit(void)
|
||||
{
|
||||
gspSetEventCallback(GSPGPU_EVENT_VBlank0, onVBlank0, NULL, false);
|
||||
gspSetEventCallback(GSPGPU_EVENT_VBlank1, onVBlank1, NULL, false);
|
||||
}
|
||||
|
||||
static void C3Di_RenderQueueExit(void)
|
||||
{
|
||||
int i;
|
||||
C3D_RenderTarget *a, *next;
|
||||
|
||||
for (a = firstTarget; a; a = next)
|
||||
{
|
||||
next = a->next;
|
||||
C3D_RenderTargetDelete(a);
|
||||
}
|
||||
|
||||
gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, false);
|
||||
gspSetEventCallback(GSPGPU_EVENT_VBlank1, NULL, NULL, false);
|
||||
|
||||
for (i = 0; i < 3; i ++)
|
||||
linkedTarget[i] = NULL;
|
||||
|
||||
memset(queuedFrame, 0, sizeof(queuedFrame));
|
||||
queueSwap = 0;
|
||||
queuedCount = 0;
|
||||
queuedState = 0;
|
||||
}
|
||||
|
||||
static void C3Di_RenderQueueWaitDone(void)
|
||||
{
|
||||
while (queuedCount || transferQueue || clearQueue)
|
||||
gspWaitForAnyEvent();
|
||||
}
|
||||
|
||||
bool checkRenderQueueInit(void)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return false;
|
||||
|
||||
if (!ctx->renderQueueExit)
|
||||
{
|
||||
C3Di_RenderQueueInit();
|
||||
ctx->renderQueueWaitDone = C3Di_RenderQueueWaitDone;
|
||||
ctx->renderQueueExit = C3Di_RenderQueueExit;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C3D_FrameBegin(u8 flags)
|
||||
{
|
||||
if (inFrame) return false;
|
||||
int maxCount = (flags & C3D_FRAME_SYNCDRAW) ? 1 : 2;
|
||||
while (queuedCount >= maxCount)
|
||||
{
|
||||
if (flags & C3D_FRAME_NONBLOCK)
|
||||
return false;
|
||||
gspWaitForP3D();
|
||||
}
|
||||
inFrame = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C3D_FrameDrawOn(C3D_RenderTarget* target)
|
||||
{
|
||||
if (!inFrame) return false;
|
||||
|
||||
// Queue the target in the frame if it hasn't already been.
|
||||
int pos = queueSwap^queuedCount;
|
||||
if (!target->frame[pos])
|
||||
{
|
||||
if (!queuedFrame[pos].targetList)
|
||||
queuedFrame[pos].targetList = target;
|
||||
else
|
||||
{
|
||||
C3D_RenderTarget* a;
|
||||
for (a = queuedFrame[pos].targetList; a->frame[pos]; a = a->frame[pos]);
|
||||
a->frame[pos] = target;
|
||||
}
|
||||
}
|
||||
|
||||
C3D_RenderBufBind(&target->renderBuf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void C3D_FrameEnd(u8 flags)
|
||||
{
|
||||
if (!inFrame) return;
|
||||
inFrame = false;
|
||||
|
||||
int pos = queueSwap^queuedCount;
|
||||
if (!queuedFrame[pos].targetList) return;
|
||||
|
||||
// Add the frame to the queue
|
||||
queuedCount++;
|
||||
C3Di_FinalizeFrame(&queuedFrame[pos].cmdBuf, &queuedFrame[pos].cmdBufSize);
|
||||
queuedFrame[pos].flags = flags;
|
||||
|
||||
// Flush the entire linear memory if the user did not explicitly mandate to flush the command list
|
||||
if (!(flags & GX_CMDLIST_FLUSH))
|
||||
{
|
||||
// Take advantage of GX_FlushCacheRegions to flush gsp heap
|
||||
extern u32 __ctru_linear_heap;
|
||||
extern u32 __ctru_linear_heap_size;
|
||||
GX_FlushCacheRegions(queuedFrame[queueSwap].cmdBuf, queuedFrame[queueSwap].cmdBufSize, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0);
|
||||
}
|
||||
|
||||
// Update the frame queue
|
||||
updateFrameQueue();
|
||||
}
|
||||
|
||||
C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, int depthFmt)
|
||||
{
|
||||
if (!checkRenderQueueInit()) return NULL;
|
||||
C3D_RenderTarget* target = (C3D_RenderTarget*)malloc(sizeof(C3D_RenderTarget));
|
||||
if (!target) return NULL;
|
||||
memset(target, 0, sizeof(C3D_RenderTarget));
|
||||
if (!C3D_RenderBufInit(&target->renderBuf, width, height, colorFmt, depthFmt))
|
||||
{
|
||||
free(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
target->drawOk = true;
|
||||
target->prev = lastTarget;
|
||||
target->next = NULL;
|
||||
if (lastTarget)
|
||||
lastTarget->next = target;
|
||||
if (!firstTarget)
|
||||
firstTarget = target;
|
||||
lastTarget = target;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
void C3D_RenderTargetDelete(C3D_RenderTarget* target)
|
||||
{
|
||||
target->clearBits = 0;
|
||||
target->linked = false;
|
||||
while (!target->drawOk)
|
||||
gspWaitForAnyEvent();
|
||||
C3D_RenderBufDelete(&target->renderBuf);
|
||||
C3D_RenderTarget** prevNext = target->prev ? &target->prev->next : &firstTarget;
|
||||
C3D_RenderTarget** nextPrev = target->next ? &target->next->prev : &lastTarget;
|
||||
*prevNext = target->next;
|
||||
*nextPrev = target->prev;
|
||||
free(target);
|
||||
}
|
||||
|
||||
void C3D_RenderTargetSetClear(C3D_RenderTarget* target, u32 clearBits, u32 clearColor, u32 clearDepth)
|
||||
{
|
||||
if (target->renderBuf.colorBuf.data==NULL) clearBits &= ~C3D_CLEAR_COLOR;
|
||||
if (target->renderBuf.depthBuf.data==NULL) clearBits &= ~C3D_CLEAR_DEPTH;
|
||||
|
||||
u32 oldClearBits = target->clearBits;
|
||||
target->clearBits = clearBits & 0xFF;
|
||||
target->renderBuf.clearColor = clearColor;
|
||||
target->renderBuf.clearDepth = clearDepth;
|
||||
|
||||
if (clearBits &~ oldClearBits && target->drawOk)
|
||||
{
|
||||
target->drawOk = false;
|
||||
clearTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags)
|
||||
{
|
||||
int id = 0;
|
||||
if (screen==GFX_BOTTOM) id = 2;
|
||||
else if (side==GFX_RIGHT) id = 1;
|
||||
if (linkedTarget[id])
|
||||
linkedTarget[id]->linked = false;
|
||||
linkedTarget[id] = target;
|
||||
target->linked = true;
|
||||
target->transferFlags = transferFlags;
|
||||
target->screen = screen;
|
||||
target->side = side;
|
||||
}
|
||||
|
||||
void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags)
|
||||
{
|
||||
while (transferQueue || inSafeTransfer)
|
||||
gspWaitForPPF();
|
||||
inSafeTransfer = true;
|
||||
gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true);
|
||||
GX_DisplayTransfer(inadr, indim, outadr, outdim, flags);
|
||||
}
|
||||
|
||||
void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags)
|
||||
{
|
||||
while (transferQueue || inSafeTransfer)
|
||||
gspWaitForPPF();
|
||||
inSafeTransfer = true;
|
||||
gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true);
|
||||
GX_TextureCopy(inadr, indim, outadr, outdim, size, flags);
|
||||
}
|
||||
|
||||
void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1)
|
||||
{
|
||||
while (clearQueue || inSafeClear)
|
||||
gspWaitForAnyEvent();
|
||||
inSafeClear = true;
|
||||
gspSetEventCallback(buf0a ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true);
|
||||
GX_MemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1);
|
||||
}
|
||||
81
libs/citro3d/source/texenv.c
Normal file
81
libs/citro3d/source/texenv.c
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#include <c3d/texenv.h>
|
||||
#include <string.h>
|
||||
#include "context.h"
|
||||
|
||||
void TexEnv_Init(C3D_TexEnv* env)
|
||||
{
|
||||
env->srcRgb = GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0);
|
||||
env->srcAlpha = env->srcRgb;
|
||||
env->opRgb = GPU_TEVOPERANDS(0,0,0);
|
||||
env->opAlpha = env->opRgb;
|
||||
env->funcRgb = GPU_REPLACE;
|
||||
env->funcAlpha = env->funcRgb;
|
||||
env->color = 0xFFFFFFFF;
|
||||
env->scaleRgb = GPU_TEVSCALE_1;
|
||||
env->scaleAlpha = GPU_TEVSCALE_1;
|
||||
}
|
||||
|
||||
C3D_TexEnv* C3D_GetTexEnv(int id)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return NULL;
|
||||
|
||||
ctx->flags |= C3DiF_TexEnv(id);
|
||||
return &ctx->texEnv[id];
|
||||
}
|
||||
|
||||
void C3D_SetTexEnv(int id, C3D_TexEnv* env)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
memcpy(&ctx->texEnv[id], env, sizeof(*env));
|
||||
ctx->flags |= C3DiF_TexEnv(id);
|
||||
}
|
||||
|
||||
void C3Di_TexEnvBind(int id, C3D_TexEnv* env)
|
||||
{
|
||||
if (id >= 4) id += 2;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_TEXENV0_SOURCE + id*8, (u32*)env, sizeof(C3D_TexEnv)/sizeof(u32));
|
||||
}
|
||||
|
||||
void C3D_TexEnvBufUpdate(int mode, int mask)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
u32 val = ctx->texEnvBuf;
|
||||
mask &= 0xF;
|
||||
|
||||
if (mode & C3D_RGB)
|
||||
{
|
||||
val &= ~(0xF << 8);
|
||||
val |= mask << 8;
|
||||
}
|
||||
|
||||
if (mode & C3D_Alpha)
|
||||
{
|
||||
val &= ~(0xF << 12);
|
||||
val |= mask << 12;
|
||||
}
|
||||
|
||||
ctx->texEnvBuf = val;
|
||||
ctx->flags |= C3DiF_TexEnvBuf;
|
||||
}
|
||||
|
||||
void C3D_TexEnvBufColor(u32 color)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
ctx->texEnvBufClr = color;
|
||||
ctx->flags |= C3DiF_TexEnvBuf;
|
||||
}
|
||||
115
libs/citro3d/source/texture.c
Normal file
115
libs/citro3d/source/texture.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#include "context.h"
|
||||
#include <string.h>
|
||||
|
||||
// Return bits per pixel
|
||||
static inline size_t fmtSize(GPU_TEXCOLOR fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case GPU_RGBA8:
|
||||
return 32;
|
||||
case GPU_RGB8:
|
||||
return 24;
|
||||
case GPU_RGBA5551:
|
||||
case GPU_RGB565:
|
||||
case GPU_RGBA4:
|
||||
case GPU_LA8:
|
||||
case GPU_HILO8:
|
||||
return 16;
|
||||
case GPU_L8:
|
||||
case GPU_A8:
|
||||
case GPU_LA4:
|
||||
case GPU_ETC1A4:
|
||||
return 8;
|
||||
case GPU_L4:
|
||||
case GPU_A4:
|
||||
case GPU_ETC1:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool addrIsVRAM(const void* addr)
|
||||
{
|
||||
u32 vaddr = (u32)addr;
|
||||
return vaddr >= 0x1F000000 && vaddr < 0x1F600000;
|
||||
}
|
||||
|
||||
static bool C3Di_TexInitCommon(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format, void* (*texAlloc)(size_t))
|
||||
{
|
||||
if (tex->data) return false;
|
||||
|
||||
u32 size = fmtSize(format);
|
||||
if (!size) return false;
|
||||
size *= width * height / 8;
|
||||
|
||||
tex->data = texAlloc(size);
|
||||
if (!tex->data) return false;
|
||||
|
||||
tex->width = width;
|
||||
tex->height = height;
|
||||
tex->param = GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST);
|
||||
if (format == GPU_ETC1)
|
||||
tex->param |= GPU_TEXTURE_ETC1_PARAM;
|
||||
tex->fmt = format;
|
||||
tex->size = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C3D_TexInit(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3Di_TexInitCommon(tex, width, height, format, linearAlloc);
|
||||
}
|
||||
|
||||
bool C3D_TexInitVRAM(C3D_Tex* tex, int width, int height, GPU_TEXCOLOR format)
|
||||
{
|
||||
return C3Di_TexInitCommon(tex, width, height, format, vramAlloc);
|
||||
}
|
||||
|
||||
void C3D_TexUpload(C3D_Tex* tex, const void* data)
|
||||
{
|
||||
if (tex->data && !addrIsVRAM(tex->data))
|
||||
memcpy(tex->data, data, tex->size);
|
||||
}
|
||||
|
||||
void C3D_TexSetFilter(C3D_Tex* tex, GPU_TEXTURE_FILTER_PARAM magFilter, GPU_TEXTURE_FILTER_PARAM minFilter)
|
||||
{
|
||||
tex->param &= ~(GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR));
|
||||
tex->param |= GPU_TEXTURE_MAG_FILTER(magFilter) | GPU_TEXTURE_MIN_FILTER(minFilter);
|
||||
}
|
||||
|
||||
void C3D_TexSetWrap(C3D_Tex* tex, GPU_TEXTURE_WRAP_PARAM wrapS, GPU_TEXTURE_WRAP_PARAM wrapT)
|
||||
{
|
||||
tex->param &= ~(GPU_TEXTURE_WRAP_S(3) | GPU_TEXTURE_WRAP_T(3));
|
||||
tex->param |= GPU_TEXTURE_WRAP_S(wrapS) | GPU_TEXTURE_WRAP_T(wrapT);
|
||||
}
|
||||
|
||||
void C3D_TexBind(int unitId, C3D_Tex* tex)
|
||||
{
|
||||
C3D_Context* ctx = C3Di_GetContext();
|
||||
|
||||
if (!(ctx->flags & C3DiF_Active))
|
||||
return;
|
||||
|
||||
ctx->flags |= C3DiF_Tex(unitId);
|
||||
ctx->tex[unitId] = tex;
|
||||
}
|
||||
|
||||
void C3D_TexFlush(C3D_Tex* tex)
|
||||
{
|
||||
if (tex->data && !addrIsVRAM(tex->data))
|
||||
GSPGPU_FlushDataCache(tex->data, tex->size);
|
||||
}
|
||||
|
||||
void C3D_TexDelete(C3D_Tex* tex)
|
||||
{
|
||||
if (!tex->data) return;
|
||||
|
||||
if (addrIsVRAM(tex->data))
|
||||
vramFree(tex->data);
|
||||
else
|
||||
linearFree(tex->data);
|
||||
|
||||
tex->data = NULL;
|
||||
}
|
||||
134
libs/citro3d/source/uniforms.c
Normal file
134
libs/citro3d/source/uniforms.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include <c3d/uniforms.h>
|
||||
//#include <stdio.h>
|
||||
|
||||
C3D_FVec C3D_FVUnif[2][C3D_FVUNIF_COUNT];
|
||||
C3D_IVec C3D_IVUnif[2][C3D_IVUNIF_COUNT];
|
||||
u16 C3D_BoolUnifs[2];
|
||||
|
||||
bool C3D_FVUnifDirty[2][C3D_FVUNIF_COUNT];
|
||||
bool C3D_IVUnifDirty[2][C3D_IVUNIF_COUNT];
|
||||
bool C3D_BoolUnifsDirty[2];
|
||||
|
||||
static struct
|
||||
{
|
||||
bool dirty;
|
||||
int count;
|
||||
float24Uniform_s* data;
|
||||
} C3Di_ShaderFVecData[2];
|
||||
|
||||
static bool C3Di_FVUnifEverDirty[2][C3D_FVUNIF_COUNT];
|
||||
static bool C3Di_IVUnifEverDirty[2][C3D_IVUNIF_COUNT];
|
||||
|
||||
void C3D_UpdateUniforms(GPU_SHADER_TYPE type)
|
||||
{
|
||||
int offset = type == GPU_GEOMETRY_SHADER ? (GPUREG_GSH_BOOLUNIFORM-GPUREG_VSH_BOOLUNIFORM) : 0;
|
||||
int i = 0;
|
||||
|
||||
// Update FVec uniforms that come from shader constants
|
||||
if (C3Di_ShaderFVecData[type].dirty)
|
||||
{
|
||||
while (i < C3Di_ShaderFVecData[type].count)
|
||||
{
|
||||
float24Uniform_s* u = &C3Di_ShaderFVecData[type].data[i++];
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VSH_FLOATUNIFORM_CONFIG+offset, (u32*)u, 4);
|
||||
C3D_FVUnifDirty[type][u->id] = false;
|
||||
}
|
||||
C3Di_ShaderFVecData[type].dirty = false;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
// Update FVec uniforms
|
||||
while (i < C3D_FVUNIF_COUNT)
|
||||
{
|
||||
if (!C3D_FVUnifDirty[type][i])
|
||||
{
|
||||
i ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the number of consecutive dirty uniforms
|
||||
int j;
|
||||
for (j = i; j < C3D_FVUNIF_COUNT && C3D_FVUnifDirty[type][j]; j ++);
|
||||
|
||||
// Upload the uniforms
|
||||
GPUCMD_AddWrite(GPUREG_VSH_FLOATUNIFORM_CONFIG+offset, 0x80000000|i);
|
||||
GPUCMD_AddWrites(GPUREG_VSH_FLOATUNIFORM_DATA+offset, (u32*)&C3D_FVUnif[type][i], (j-i)*4);
|
||||
|
||||
// Clear the dirty flag
|
||||
int k;
|
||||
for (k = i; k < j; k ++)
|
||||
{
|
||||
C3D_FVUnifDirty[type][k] = false;
|
||||
C3Di_FVUnifEverDirty[type][k] = true;
|
||||
}
|
||||
|
||||
// Advance
|
||||
i += j;
|
||||
}
|
||||
|
||||
// Update IVec uniforms
|
||||
for (i = 0; i < C3D_IVUNIF_COUNT; i ++)
|
||||
{
|
||||
if (!C3D_IVUnifDirty[type][i]) continue;
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_VSH_INTUNIFORM_I0+offset+i, C3D_IVUnif[type][i]);
|
||||
C3D_IVUnifDirty[type][i] = false;
|
||||
C3Di_IVUnifEverDirty[type][i] = false;
|
||||
}
|
||||
|
||||
// Update bool uniforms
|
||||
if (C3D_BoolUnifsDirty[type])
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_VSH_BOOLUNIFORM+offset, 0x7FFF0000 | C3D_BoolUnifs[type]);
|
||||
C3D_BoolUnifsDirty[type] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void C3Di_DirtyUniforms(GPU_SHADER_TYPE type)
|
||||
{
|
||||
int i;
|
||||
C3D_BoolUnifsDirty[type] = true;
|
||||
if (C3Di_ShaderFVecData[type].count)
|
||||
C3Di_ShaderFVecData[type].dirty = true;
|
||||
for (i = 0; i < C3D_FVUNIF_COUNT; i ++)
|
||||
C3D_FVUnifDirty[type][i] = C3D_FVUnifDirty[type][i] || C3Di_FVUnifEverDirty[type][i];
|
||||
for (i = 0; i < C3D_IVUNIF_COUNT; i ++)
|
||||
C3D_IVUnifDirty[type][i] = C3D_IVUnifDirty[type][i] || C3Di_IVUnifEverDirty[type][i];
|
||||
}
|
||||
|
||||
void C3Di_LoadShaderUniforms(shaderInstance_s* si)
|
||||
{
|
||||
GPU_SHADER_TYPE type = si->dvle->type;
|
||||
if (si->boolUniformMask)
|
||||
{
|
||||
C3D_BoolUnifs[type] &= ~si->boolUniformMask;
|
||||
C3D_BoolUnifs[type] |= si->boolUniforms;
|
||||
}
|
||||
|
||||
if (type == GPU_GEOMETRY_SHADER)
|
||||
C3D_BoolUnifs[type] &= ~BIT(15);
|
||||
C3D_BoolUnifsDirty[type] = true;
|
||||
|
||||
if (si->intUniformMask)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i ++)
|
||||
{
|
||||
if (si->intUniformMask & BIT(i))
|
||||
{
|
||||
C3D_IVUnif[type][i] = si->intUniforms[i];
|
||||
C3D_IVUnifDirty[type][i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
C3Di_ShaderFVecData[type].dirty = true;
|
||||
C3Di_ShaderFVecData[type].count = si->numFloat24Uniforms;
|
||||
C3Di_ShaderFVecData[type].data = si->float24Uniforms;
|
||||
}
|
||||
|
||||
void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type)
|
||||
{
|
||||
C3Di_ShaderFVecData[type].dirty = false;
|
||||
C3Di_ShaderFVecData[type].count = 0;
|
||||
C3Di_ShaderFVecData[type].data = NULL;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue