diff options
| author | enzofc708 <47937189+enzofc708@users.noreply.github.com> | 2026-04-16 15:38:59 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-16 20:38:59 +0200 |
| commit | ef2caebcefe1a0d370a56340944931f71bcd39a8 (patch) | |
| tree | 7cdd9e0447e418d937effd0c0424c6909913c077 /libs | |
| parent | 98cc0af690719f10bd7b67c1c11d207bfcdbbfe7 (diff) | |
Decomp sbc.c (100%) (#144)
* start sbc.cpp
* add G3d_SBCRender_007
* match G3d_SBCRender_007
* match G3d_SBCRender_008
* match G3d_SBCRender_SKN
* fix EUR relocs file
* match G3d_SBCRender_00C
* match G3d_SBCRender_00D
* complete sbc.cpp
* fix EUR delinks
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/nds/include/nds/g3d/g3d.h | 166 | ||||
| -rw-r--r-- | libs/nds/include/nds/g3d/sbc.h | 110 | ||||
| -rw-r--r-- | libs/nds/include/nds/gfx.h | 7 | ||||
| -rw-r--r-- | libs/nds/src/sbc.c | 855 |
4 files changed, 1138 insertions, 0 deletions
diff --git a/libs/nds/include/nds/g3d/g3d.h b/libs/nds/include/nds/g3d/g3d.h new file mode 100644 index 00000000..c4175327 --- /dev/null +++ b/libs/nds/include/nds/g3d/g3d.h @@ -0,0 +1,166 @@ +#include "nds/math.h" + +struct G3d_RenderState_; +typedef void (*G3d_CallbackFunction)(struct G3d_RenderState_ *); + +typedef struct G3d_NameList_ { + /* 00 */ u8 dummy; + /* 01 */ u8 numElmnts; // number of elements + /* 02 */ u16 size; // size of this NameList in bytes + /* 04 */ u16 dummy2; + /* 06 */ u16 ofsHeader; // offset to the G3d_NameList_Header + /* 08 */ void *entry[1]; // variable size + /* 0c */ +} G3d_NameList; + +typedef struct G3d_NameList_Header_ { + /* 00 */ u16 element_size; + /* 02 */ u16 data_section_size; + /* 04 */ u8 data[4]; + /* 08 */ +} G3d_NameList_Header; + +typedef struct G3d_InvBindMtx_ { + /* 00 */ Mat4x3p mtx; + /* 30 */ Mat3p unkMtx; + /* 54 */ +} G3d_InvBindMtx; + +typedef struct G3d_BoneMtxStruct_ { + /* 00 */ u32 flag; + /* 04 */ u8 mUnk_04[0x24]; + /* 28 */ Mat3p rot; + /* 58 */ u8 mUnk_58[0xc]; + /* 64 */ +} G3d_BoneMtxStruct; + +typedef enum { + G3D_ANIMBIND_UNK = 0xff, + G3D_ANIMBIND_EXISTS = 0x100, + G3D_ANIMBIND_OFF = 0x200 +} G3d_AnimationBinds; + +typedef struct G3d_Animation_ { + /* 00 */ u8 mUnk_00[0x10]; + /* 10 */ struct G3d_Animation_ *next; // next animation in the list + /* 14 */ u8 mUnk_14[0x5]; + /* 19 */ u8 numElmnts; // number of elements in the elementBinds array + /* 1a */ u16 elementBinds[1]; // each bit corresponds to a bone/material and determines whether an animation exists for it + /* 1c */ +} G3d_Animation; + +// Structure representing the NSBMD model file +typedef struct G3d_Model_ { + /* 00 */ u32 size; // size of the model in bytes + /* 04 */ u32 offSbc; // offset of the SBC commands list + /* 08 */ u32 offMat; // offset of the material list + /* 0c */ u32 offMesh; // offset of the mesh list + /* 10 */ u32 offInvBMtx; // offset of the InvBindMatrix list + /* 14 */ u8 dummy1; + /* 15 */ u8 scalingHandler; // Determines which of the G3d_gScaleHandlers to use for this model + /* 16 */ u8 textureHandler; // Determines which of the G3d_gTextureHandlers to use for this model + /* 17 */ u8 numBones; // number of nodes + /* 18 */ u8 numMat; // number of materials + /* 19 */ u8 numMesh; // number of meshes + /* 1a */ u8 dummy2[2]; + /* 1c */ q20 upScale; + /* 20 */ q20 downScale; + /* 24 */ u16 numVertex; // number of vertices + /* 26 */ u16 numPolygon; // number of polygons + /* 28 */ u16 numTriangle; // number of triangles + /* 2a */ u16 numQuad; // number of quads + /* 2c */ q4 boundingBoxMin[3]; // bounding box lower vertex + /* 32 */ q4 boundingBoxMax[3]; // bounding box upper vertex + /* 38 */ u8 dummy3[8]; + /* 40 */ G3d_NameList boneList; // bone list + /* 4c */ +} G3d_Model; + +static inline G3d_NameList *G3d_GetBoneList(const G3d_Model *mdl) { + return (G3d_NameList *) &mdl->boneList; +} + +static inline void *G3d_GetMat(const G3d_Model *mdl) { + + return (void *) ((u8 *) mdl + mdl->offMat); +} + +static inline G3d_NameList *G3d_GetMesh(const G3d_Model *mdl) { + return (G3d_NameList *) ((u8 *) mdl + mdl->offMesh); +} + +typedef enum { + G3D_RENDEROBJ_FLAG_STORE = 0x1, // stores results in local cache + G3D_RENDEROBJ_FLAG_SKIP_CMD = 0x2, // skips pushing geometry commands to the FIFO + G3D_RENDEROBJ_FLAG_SKIP_SBC_DRAW = 0x4, // skips the execution of rendering commands + G3D_RENDEROBJ_FLAG_SKIP_SBC_MTXCALC = 0x8, // skips the execution of matrix calculation commands + G3D_RENDEROBJ_FLAG_ANIMMAP_OUTDATED = 0x10 // set when the animation map arrays in the render object are outdated +} G3d_RenderObjFlag; + +// Structure that handles the parameters for drawing a model +typedef struct G3d_RenderObject_ { + /* 00 */ u32 flag; // G3d_RenderObjFlag + /* 04 */ G3d_Model *model; + /* 08 */ G3d_Animation *matAnim; // material animation + /* 0c */ void *mUnk_0c; + /* 10 */ G3d_Animation *jntAnim; // joint animation + /* 14 */ void *mUnk_14; + /* 18 */ G3d_Animation *mUnk_18; + /* 1c */ void *mUnk_1c; + /* 20 */ G3d_CallbackFunction callbackFunction; + /* 24 */ u8 callbackIdx; // index of the callbackFunction in the callback array of G3d_RenderState + /* 25 */ u8 mUnk_25; // related to callback + /* 26 */ u16 dummy_; + /* 28 */ G3d_CallbackFunction callbackInitFunc; // initializes the G3d_RenderState callback array + /* 2c */ void *modelRender; // pointer to the ModelRender that is rendering this model + /* 30 */ u8 *unkCommandsList; // if not null, this command list is used instead of the one in the model + /* 34 */ G3d_BoneMtxStruct *cacheJntAnm; + /* 38 */ void *cacheMatAnm; + /* 3c */ u32 matAnimBindMap[2]; + /* 44 */ u32 jntAnimBindMap[2]; + /* 4c */ u32 unkAnimBindMap[2]; + /* 54 */ +} G3d_RenderObject; + +typedef struct G3d_Material_List_ { + /* 00 */ u16 texture_pairings_off; + /* 02 */ u16 palette_pairings_off; + /* 04 */ G3d_NameList materials; + /* 10 */ +} G3d_Material_List; + +typedef struct G3d_Material_ { + /* 00 */ u32 mUnk_00; + /* 04 */ u32 dif_amb; + /* 08 */ u32 spe_emi; + /* 0c */ u32 polygon_attr; + /* 10 */ u32 mUnk_10; + /* 14 */ u32 teximage_params; + /* 18 */ u32 mUnk_18; + /* 1c */ u16 pltt_base; + /* 1e */ u16 flag; + /* 20 */ u16 width; + /* 22 */ u16 height; + /* 24 */ u8 mUnk_24[0x8]; + /* 2c */ +} G3d_Material; + +typedef struct G3d_MaterialAnimation_ { + /* 00 */ u32 flag; + /* 04 */ u32 dif_amb; + /* 08 */ u32 spe_emi; + /* 0c */ u32 polygon_attr; + /* 10 */ u32 teximage_params; + /* 14 */ u32 pltt_base; + /* 18 */ u8 mUnk_18[0x14]; + /* 2c */ u16 width; + /* 2e */ u16 height; + /* 30 */ u8 mUnk_30[0x8]; + /* 38 */ +} G3d_MaterialAnimation; + +#define G3D_TEXIMAGE_PARM_TEX_COORD_MODE 0xc0000000 + +extern void *G3d_gScaleHandlers[3]; +extern void *G3d_gSRTTransformHandlers[3]; +extern void *G3d_gTextureHandlers[4];
\ No newline at end of file diff --git a/libs/nds/include/nds/g3d/sbc.h b/libs/nds/include/nds/g3d/sbc.h new file mode 100644 index 00000000..6f0416c4 --- /dev/null +++ b/libs/nds/include/nds/g3d/sbc.h @@ -0,0 +1,110 @@ +#pragma once +#include "g3d.h" + +extern void PushGeometryCommand(u32 command, void *data, s32 length); + +typedef enum { + G3D_SBC_CMD_NOP = 0x0, + G3D_SBC_CMD_END = 0x1, + G3D_SBC_CMD_VIS = 0x2, + G3D_SBC_CMD_007 = 0x7, + G3D_SBC_CMD_008 = 0x8, + G3D_SBC_CMD_SKN = 0x9, + G3D_SBC_CMD_00A = 0xa, + G3D_SBC_CMD_SCL = 0xb, + G3D_SBC_CMD_00C = 0xc, + G3D_SBC_CMD_00D = 0xd +} G3d_SBC_Commands; + +typedef enum { + G3D_RENDERST_FLAG_BONE_VISIBLE = 0x1, + G3D_RENDERST_FLAG_MAT_TRANSPARENT = 0x2, + G3D_RENDERST_FLAG_VALID_NODE = 0x4, + G3D_RENDERST_FLAG_VALID_MAT = 0x8, + G3D_RENDERST_FLAG_VALID_BONEMTX = 0x10, + G3D_RENDERST_FLAG_END = 0x20, // set when the end of the SBC command list is reached + G3D_RENDERST_FLAG_SKIP_CALLBACK = 0x40, // skip callback + G3D_RENDERST_FLAG_STORE = 0x80, // stores results in G3d_RenderObject local cache + G3D_RENDERST_FLAG_SKIP_CMD = 0x100, // skips pushing geometry commands to the FIFO + G3D_RENDERST_FLAG_SKIP_SBC_RENDER = 0x200, // skips the execution of rendering commands + G3D_RENDERST_FLAG_SKIP_SBC_MTXCALC = 0x400 // skips the execution of matrix calculation commands +} G3d_RenderStateFlag; + +typedef struct G3d_RenderState_ { + /* 00 */ u8 *currentCmd; // current command being processed + /* 04 */ G3d_RenderObject *renderObj; // current render object being processed + /* 08 */ u32 flag; // G3d_RenderStateFlag + /* 0c */ G3d_CallbackFunction callbackFuncs[32]; // callback function for each SBC command + /* 8c */ u8 callbackSegment[32]; // determines at which segment of the SBC command to invoke the callback + /* ac */ u8 currentBoneId; + /* ad */ u8 currentMaterialId; + /* ae */ u8 currentBoneMtxId; + /* af */ u8 dummy; + /* b0 */ G3d_MaterialAnimation *matAnim; + /* b4 */ void *mUnk_19; + /* b8 */ u8 *visibilityPtr; // points to isVisible (0x187) + /* bc */ u32 mUnk_bc[2]; + /* c4 */ u32 mUnk_c4[2]; + /* cc */ u32 mUnk_cc[2]; + /* d4 */ G3d_NameList *boneList; + /* d8 */ const G3d_Material_List *materialList; + /* dc */ G3d_NameList *meshList; + /* e0 */ q20 upScale; + /* e4 */ q20 downScale; + /* e8 */ void *jntScalingHandler; // scaling handler + /* ec */ void *jntSRTHandler; // SRT transform handler + /* f0 */ void *textureHandler; // texture matrix handler + /* f4 */ u8 mUnk_f4[0x93]; + /* 187 */ u8 isVisible; + /* 188 */ +} G3d_RenderState; + +typedef struct UnkStruct_0205ae08_ { + /* 00 */ u8 mUnk_00[0x1400]; + /* 1400 */ struct { + Mat4p mtx1; + Mat3p mtx2; + } mUnk_1400[64]; +} UnkStruct_0205ae08; + +typedef void (*G3d_FuncSbc)(G3d_RenderState *, u32); +extern G3d_FuncSbc G3d_FuncSbcTable[32]; +extern G3d_RenderState *G3d_gRenderState; +extern UnkStruct_0205ae08 data_0205ae08; +void G3d_Render(G3d_RenderObject *renderObj); + +static inline u32 G3d_FindInBitArray(const u32 *arr, u32 idx) { + return (u32) (arr[idx >> 5] & (1 << (idx & 31))); +} + +static inline void G3d_SetBitArray(u32 *arr, u32 idx) { + arr[idx >> 5] |= 1 << (idx & 31); +} + +static inline void G3d_SetMtxMode_inline(u32 mode) { + PushGeometryCommand(0x10, &mode, 1); +} + +static inline void G3d_RestoreMtx_inline(u32 idx) { + PushGeometryCommand(0x14, &idx, 1); +} + +static inline void G3d_MtxMult33_inline(const Mat3p *m) { + PushGeometryCommand(0x1a, (u32 *) m, 9); +} + +static inline void G3d_MtxMult43_inline(const Mat4x3p *m) { + PushGeometryCommand(0x19, (u32 *) m, 12); +} + +static inline void G3d_MtxMult44_inline(const Mat4p *m) { + PushGeometryCommand(0x18, (u32 *) m, 0x10); +} + +static inline void G3d_Scale_inline(q20 x, q20 y, q20 z) { + Vec3p vec; + vec.x = x; + vec.y = y; + vec.z = z; + PushGeometryCommand(0x1b, (u32 *) &vec, 3); +}
\ No newline at end of file diff --git a/libs/nds/include/nds/gfx.h b/libs/nds/include/nds/gfx.h index dea3eca5..2444ae2a 100644 --- a/libs/nds/include/nds/gfx.h +++ b/libs/nds/include/nds/gfx.h @@ -8,6 +8,13 @@ extern "C" { #endif +#define REG_GFX_FIFO (*(volatile u32 *) 0x04000400) +#define GFX_FIFO_MTX_MODE (*(volatile u32 *) 0x04000440) +#define GFX_FIFO_MTX_PUSH (*(volatile u32 *) 0x04000444) +#define GFX_FIFO_MTX_POP (*(volatile u32 *) 0x04000448) +#define GFX_FIFO_MTX_STORE (*(volatile u32 *) 0x0400044c) +#define GFX_FIFO_MTX_RESTORE (*(volatile u32 *) 0x04000450) +#define GFX_FIFO_MTX_IDENTITY (*(volatile u32 *) 0x04000454) #define GFX_FIFO_SWAP_BUFFERS (*(volatile u32 *) 0x04000540) #define GFX_FIFO_VIEWPORT (*(volatile u32 *) 0x04000580) #define REG_GFX_RAM_COUNT (*(volatile u16 *) 0x04000604) diff --git a/libs/nds/src/sbc.c b/libs/nds/src/sbc.c new file mode 100644 index 00000000..62071d4e --- /dev/null +++ b/libs/nds/src/sbc.c @@ -0,0 +1,855 @@ +#include "nds/g3d/sbc.h" +#include "DTCM/UnkStruct_027e037c.h" +#include "nds/gfx.h" + +#define G3D_SBC_CMD_MASK 0x1f +#define G3D_SBC_FLG_MASK 0xe0 +#define GX_ST(s, t) ((u32) ((u16) (s16) (s >> 8) | ((u16) (s16) (t >> 8) << 16))) +#define GX_PACK_TEXCOORD_PARAM(s, t) (GX_ST((s), (t))) + +extern void Fill256(unk32, unk16 *, unk32); +extern void Fill32(unk32, u32 *, unk32); +extern void FlushGfxQueue(); +extern s32 func_0200598c(Mat4p *matrix); +extern Mat4x3p *func_02018450(); +extern Mat4x3p *func_02018738(); +extern Mat4x3p *func_02018770(); +extern s32 func_020059bc(Mat3p *matrix); +extern void func_0200567c(unk32 param1); +extern void func_02005644(Mat4x3p *matrix); +extern void func_01ffa94c(const void *param1, u32 param2); +extern Mat3p gGeomMatrix; +extern Vec3p gGeomTranslation; +extern void G3d_GetCurrentMtx(Mat4x3p *mtx1, Mat3p *mtx2); + +UnkStruct_0205ae08 data_0205ae08; + +// Renders all SBC commands until the end of the list +void G3d_RenderSBCCommands(G3d_RenderState *renderState) { + do { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*G3d_FuncSbcTable[(*renderState->currentCmd) & G3D_SBC_CMD_MASK])(renderState, (*renderState->currentCmd) & + (u32) G3D_SBC_FLG_MASK); + } while (!(renderState->flag & G3D_RENDERST_FLAG_END)); +} + +// Initializes the render state and starts rendering the SBC command list +void G3d_InitRenderState(G3d_RenderState *renderState, G3d_RenderObject *renderObj) { + Fill256(0, (short *) renderState, sizeof(*renderState)); + renderState->mUnk_c4[0] = 1; + renderState->flag = G3D_RENDERST_FLAG_BONE_VISIBLE; + + if (renderObj->unkCommandsList) { + renderState->currentCmd = renderObj->unkCommandsList; + } else { + renderState->currentCmd = (u8 *) renderObj->model + renderObj->model->offSbc; + } + + renderState->renderObj = renderObj; + renderState->boneList = G3d_GetBoneList(renderObj->model); + renderState->materialList = G3d_GetMat(renderObj->model); + renderState->meshList = G3d_GetMesh(renderObj->model); + renderState->jntScalingHandler = G3d_gScaleHandlers[renderObj->model->scalingHandler]; + renderState->jntSRTHandler = G3d_gSRTTransformHandlers[renderObj->model->scalingHandler]; + renderState->textureHandler = G3d_gTextureHandlers[renderObj->model->textureHandler]; + renderState->upScale = renderObj->model->upScale; + renderState->downScale = renderObj->model->downScale; + if (renderObj->callbackFunction && renderObj->callbackIdx < 32) { + renderState->callbackFuncs[renderObj->callbackIdx] = renderObj->callbackFunction; + renderState->callbackSegment[renderObj->callbackIdx] = renderObj->mUnk_25; + } + + if (renderObj->flag & G3D_RENDEROBJ_FLAG_STORE) { + renderState->flag |= G3D_RENDERST_FLAG_STORE; + } + + if (renderObj->flag & G3D_RENDEROBJ_FLAG_SKIP_CMD) { + renderState->flag |= G3D_RENDERST_FLAG_SKIP_CMD; + } + + if (renderObj->flag & G3D_RENDEROBJ_FLAG_SKIP_SBC_DRAW) { + renderState->flag |= G3D_RENDERST_FLAG_SKIP_SBC_RENDER; + } + + if (renderObj->flag & G3D_RENDEROBJ_FLAG_SKIP_SBC_MTXCALC) { + renderState->flag |= G3D_RENDERST_FLAG_SKIP_SBC_MTXCALC; + } + + if (renderObj->callbackInitFunc) { + (*renderObj->callbackInitFunc)(renderState); + } + + G3d_RenderSBCCommands(renderState); + + renderObj->flag &= ~G3D_RENDEROBJ_FLAG_STORE; +} + +// Sets the bits in the anim array according to the map data of the animation +void G3d_SetRenderObjAnimationMap(u32 *arr, const G3d_Animation *anim) { + while (anim) { + int i; + for (i = 0; i < anim->numElmnts; i++) { + if (anim->elementBinds[i] & G3D_ANIMBIND_EXISTS) { + arr[i >> 5] |= 1 << (i & 31); + } + } + anim = anim->next; + } +} + +// Renders a model by processing the SBC command list +void G3d_Render(G3d_RenderObject *renderObj) { + if ((renderObj->flag & G3D_RENDEROBJ_FLAG_ANIMMAP_OUTDATED) == G3D_RENDEROBJ_FLAG_ANIMMAP_OUTDATED) { + Fill32(0, &renderObj->matAnimBindMap[0], 8); + Fill32(0, &renderObj->jntAnimBindMap[0], 8); + Fill32(0, &renderObj->unkAnimBindMap[0], 8); + + if (renderObj->matAnim) { + G3d_SetRenderObjAnimationMap(&renderObj->matAnimBindMap[0], renderObj->matAnim); + } + if (renderObj->jntAnim) { + G3d_SetRenderObjAnimationMap(&renderObj->jntAnimBindMap[0], renderObj->jntAnim); + } + if (renderObj->mUnk_18) { + G3d_SetRenderObjAnimationMap(&renderObj->unkAnimBindMap[0], renderObj->mUnk_18); + } + renderObj->flag &= ~G3D_RENDEROBJ_FLAG_ANIMMAP_OUTDATED; + } + + if (G3d_gRenderState) { + G3d_InitRenderState(G3d_gRenderState, renderObj); + } else { + G3d_RenderState rs; + G3d_gRenderState = &rs; + G3d_InitRenderState(&rs, renderObj); + G3d_gRenderState = NULL; + } +} + +// Renders the NOP SBC command +void G3d_SBCRender_NOP(G3d_RenderState *renderState, u32) { + if (renderState->callbackFuncs[G3D_SBC_CMD_NOP]) { + (*renderState->callbackFuncs[G3D_SBC_CMD_NOP])(renderState); + } + renderState->currentCmd++; +} + +// Renders the END SBC command +void G3d_SBCRender_END(G3d_RenderState *renderState, u32) { + if (renderState->callbackFuncs[G3D_SBC_CMD_END]) { + (*renderState->callbackFuncs[G3D_SBC_CMD_END])(renderState); + } + renderState->flag |= G3D_RENDERST_FLAG_END; +} + +// Renders the SBC command 0x7 (unknown) +void G3d_SBCRender_007(G3d_RenderState *renderState, u32 opCode) { + + u32 totalArgs = 2; + + static u32 funcArgs[] = {0x1b171012, // MTX_POP | MTX_MODE | MTX_LOAD_4x3 | MTX_SCALE + 1, // MTX_MODE = Position + 2, 0x1000, 0, 0, 0, 0x1000, 0, 0, 0, 0x1000, // Identity MTX + 0, 0, 0, 0, 0, 0}; + + Vec3p *translationVec = (Vec3p *) &funcArgs[12]; + Vec3p *scaleVec = (Vec3p *) &funcArgs[15]; + Mat4p currentMtx; + u8 callbackSkip; + u32 callbackSegment; + + if (renderState->flag & G3D_RENDERST_FLAG_SKIP_SBC_RENDER) { + if (opCode == 0x40 || opCode == 0x60) { + totalArgs++; + } + if (opCode == 0x20 || opCode == 0x60) { + totalArgs++; + } + renderState->currentCmd += totalArgs; + return; + } + + if (opCode == 0x40 || opCode == 0x60) { + totalArgs++; + + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD)) { + u32 matrixIndex; + if (opCode == 0x40) { + matrixIndex = *(renderState->currentCmd + 2); + } else { + matrixIndex = *(renderState->currentCmd + 3); + } + PushGeometryCommand(0x14, &matrixIndex, 1); // MTX_RESTORE + } + } + + if (renderState->callbackFuncs[G3D_SBC_CMD_007]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_007]; + } else { + callbackSegment = 0; + } + + if (callbackSegment == 1) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_007])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_007]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_007]; + } else { + callbackSegment = 0; + } + callbackSkip = (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD) && !callbackSkip) { + FlushGfxQueue(); + + REG_GFX_FIFO = 0x151110; // MTX_MODE | MTX_PUSH | MTX_IDENTITY + REG_GFX_FIFO = 0; // MTX_MODE = Projection + + REG_GFX_FIFO = 0; + + while (func_0200598c(¤tMtx)) + ; + + if (data_027e037c.flags & 1) { + const Mat4x3p *mtx1 = func_02018738(); + Mat4p mtx2; + + Mat4x3p_CopyToMat4p(mtx1, &mtx2); + Mat4p_Multiply(¤tMtx, &mtx2, ¤tMtx); + } else if (data_027e037c.flags & 2) { + const Mat4x3p *mtx1 = &data_027e037c.mUnk_04c; + Mat4p mtx2; + + Mat4x3p_CopyToMat4p(mtx1, &mtx2); + Mat4p_Multiply(¤tMtx, &mtx2, ¤tMtx); + } + + translationVec->x = currentMtx.wColumn.x; + translationVec->y = currentMtx.wColumn.y; + translationVec->z = currentMtx.wColumn.z; + + scaleVec->x = Vec3p_Length((Vec3p *) ¤tMtx.xColumn); + scaleVec->y = Vec3p_Length((Vec3p *) ¤tMtx.yColumn); + scaleVec->z = Vec3p_Length((Vec3p *) ¤tMtx.zColumn); + + if (data_027e037c.flags & 1) { + REG_GFX_FIFO = 0x171012; // MTX_POP | MTX_MODE | MTX_LOAD_4x3 + Stream32(&funcArgs[1], ®_GFX_FIFO, 8); // MTX_MODE = Position + Stream32(func_02018770(), ®_GFX_FIFO, 0x30); + + REG_GFX_FIFO = 0x1b19; // MTX_MULT_4x3 | MTX_SCALE + Stream32(&funcArgs[3], ®_GFX_FIFO, 0x3c); // Identity MTX + } else if (data_027e037c.flags & 2) { + REG_GFX_FIFO = 0x171012; // MTX_POP | MTX_MODE | MTX_LOAD_4x3 + Stream32(&funcArgs[1], ®_GFX_FIFO, 8); // MTX_MODE = Position + Stream32(func_02018450(), ®_GFX_FIFO, 0x30); + + REG_GFX_FIFO = 0x1b19; // MTX_MULT_4x3 | MTX_SCALE + Stream32(&funcArgs[3], ®_GFX_FIFO, 0x3c); // Identity MTX + } else { + Stream32(&funcArgs, ®_GFX_FIFO, 0x48); // MTX_POP | MTX_MODE | MTX_LOAD_4x3 | MTX_SCALE + } + } + + if (callbackSegment == 3) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_007])(renderState); + callbackSkip = renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK; + } else { + callbackSkip = 0; + } + + if (opCode == 0x20 || opCode == 0x60) { + totalArgs++; + + if (!callbackSkip) { + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD)) { + u32 matrixIndex = *(renderState->currentCmd + 2); + PushGeometryCommand(0x13, &matrixIndex, 1); // MTX_STORE + } + } + } + renderState->currentCmd += totalArgs; +} + +// Renders the SBC command 0x8 (unknown) +void G3d_SBCRender_008(G3d_RenderState *renderState, u32 opCode) { + u32 totalArgs = 2; + Mat4p currentMtx; + + static u32 funcArgs[] = {0x1b171012, // MTX_POP | MTX_MODE | MTX_LOAD_4x3 | MTX_SCALE + 1, // MTX_MODE = Position + 2, 0x1000, 0, 0, 0, 0x1000, 0, 0, 0, 0x1000, // Identity MTX + 0, 0, 0, 0, 0, 0}; + + Vec3p *translationVec = (Vec3p *) &funcArgs[12]; + Vec3p *scaleVec = (Vec3p *) &funcArgs[15]; + Mat4x3p *mtx = (Mat4x3p *) &funcArgs[3]; + u8 callbackSkip; + u32 callbackSegment; + + if (renderState->flag & G3D_RENDERST_FLAG_SKIP_SBC_RENDER) { + if (opCode == 0x40 || opCode == 0x60) { + totalArgs++; + } + if (opCode == 0x20 || opCode == 0x60) { + totalArgs++; + } + renderState->currentCmd += totalArgs; + return; + } + + if (opCode == 0x40 || opCode == 0x60) { + totalArgs++; + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD)) { + u32 matrixIndex; + if (opCode == 0x40) { + matrixIndex = *(renderState->currentCmd + 2); + } else { + matrixIndex = *(renderState->currentCmd + 3); + } + PushGeometryCommand(0x14, &matrixIndex, 1); + } + } + + if (renderState->callbackFuncs[G3D_SBC_CMD_008]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_008]; + } else { + callbackSegment = 0; + } + + if (callbackSegment == 1) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_008])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_008]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_008]; + } else { + callbackSegment = 0; + } + callbackSkip = (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD) && !callbackSkip) { + FlushGfxQueue(); + + REG_GFX_FIFO = 0x151110; // MTX_MODE | MTX_PUSH | MTX_IDENTITY + REG_GFX_FIFO = 0; // MTX_MODE = Projection + + REG_GFX_FIFO = 0; + + while (func_0200598c(¤tMtx)) + ; + + if (data_027e037c.flags & 1) { + const Mat4x3p *mtx1 = func_02018738(); + Mat4p mtx2; + + Mat4x3p_CopyToMat4p(mtx1, &mtx2); + Mat4p_Multiply(¤tMtx, &mtx2, ¤tMtx); + } else if (data_027e037c.flags & 2) { + const Mat4x3p *mtx1 = &data_027e037c.mUnk_04c; + Mat4p mtx2; + + Mat4x3p_CopyToMat4p(mtx1, &mtx2); + Mat4p_Multiply(¤tMtx, &mtx2, ¤tMtx); + } + + translationVec->x = currentMtx.wColumn.x; + translationVec->y = currentMtx.wColumn.y; + translationVec->z = currentMtx.wColumn.z; + + scaleVec->x = Vec3p_Length((Vec3p *) ¤tMtx.xColumn); + scaleVec->y = Vec3p_Length((Vec3p *) ¤tMtx.yColumn); + scaleVec->z = Vec3p_Length((Vec3p *) ¤tMtx.zColumn); + + if (currentMtx.yColumn.y != 0 || currentMtx.yColumn.z != 0) { + Vec3p_Normalize((Vec3p *) ¤tMtx.yColumn, (Vec3p *) &mtx->yColumn); + + mtx->zColumn.y = -mtx->yColumn.z; + mtx->zColumn.z = mtx->yColumn.y; + } else { + Vec3p_Normalize((Vec3p *) ¤tMtx.zColumn, (Vec3p *) &mtx->zColumn); + + mtx->yColumn.z = -mtx->zColumn.y; + mtx->yColumn.y = mtx->zColumn.z; + } + + if (data_027e037c.flags & 1) { + REG_GFX_FIFO = 0x171012; // MTX_POP | MTX_MODE | MTX_LOAD_4x3 + Stream32(&funcArgs[1], ®_GFX_FIFO, 8); // MTX_MODE = Position + Stream32(func_02018770(), ®_GFX_FIFO, 0x30); + + REG_GFX_FIFO = 0x1b19; // MTX_MULT_4x3 | MTX_SCALE + Stream32(&funcArgs[3], ®_GFX_FIFO, 0x3c); // Identity MTX + } else if (data_027e037c.flags & 2) { + REG_GFX_FIFO = 0x171012; // MTX_POP | MTX_MODE | MTX_LOAD_4x3 + Stream32(&funcArgs[1], ®_GFX_FIFO, 8); // MTX_MODE = Position + Stream32(func_02018450(), ®_GFX_FIFO, 0x30); + + REG_GFX_FIFO = 0x1b19; // MTX_MULT_4x3 | MTX_SCALE + Stream32(&funcArgs[3], ®_GFX_FIFO, 0x3c); // Identity MTX + } else { + Stream32(&funcArgs, ®_GFX_FIFO, 0x48); // MTX_POP | MTX_MODE | MTX_LOAD_4x3 | MTX_SCALE + } + } + + if (callbackSegment == 3) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_008])(renderState); + callbackSkip = renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK; + } else { + callbackSkip = 0; + } + + if (opCode == 0x20 || opCode == 0x60) { + totalArgs++; + + if (!callbackSkip) { + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD)) { + u32 matrixIndex = *(renderState->currentCmd + 2); + PushGeometryCommand(0x13, &matrixIndex, 1); // MTX_STORE + } + } + } + + renderState->currentCmd += totalArgs; +} + +// Renders the Skinning Equation SBC command +void G3d_SBCRender_SKN(G3d_RenderState *renderState, u32) { + G3d_InvBindMtx *invBMtx = + (G3d_InvBindMtx *) ((u8 *) renderState->renderObj->model + renderState->renderObj->model->offInvBMtx); + u32 numTerms = *(renderState->currentCmd + 2); + s64 weight = 0; + u8 *termPtr = renderState->currentCmd + 3; + u32 i; + struct { + Mat4x3p mtx1; + Mat3p mtx2; + } mtxStruct; + Mat4p *mat4x; + Mat3p *mat3x; + + Fill256(0, (unk16 *) &mtxStruct, sizeof(mtxStruct)); + FlushGfxQueue(); + + GFX_FIFO_MTX_MODE = 0; // Projection + GFX_FIFO_MTX_STORE = 1; + GFX_FIFO_MTX_IDENTITY = 0; + GFX_FIFO_MTX_MODE = 2; // Position + Vector + + for (i = 0; i < numTerms; i++) { + u32 jntIndex = *(termPtr + 1); + u32 unk = G3d_FindInBitArray(&renderState->mUnk_cc[0], jntIndex); + + mat4x = &data_0205ae08.mUnk_1400[jntIndex].mtx1; + if (!unk) { + G3d_SetBitArray(&renderState->mUnk_cc[0], jntIndex); + + GFX_FIFO_MTX_RESTORE = (*termPtr); + GFX_FIFO_MTX_MODE = 1; // Position + func_0200567c(&invBMtx[jntIndex].mtx); + } + + if (i != 0) { + mtxStruct.mtx2.xColumn.x += (weight * mat3x->xColumn.x) >> 0xc; + mtxStruct.mtx2.xColumn.y += (weight * mat3x->xColumn.y) >> 0xc; + mtxStruct.mtx2.xColumn.z += (weight * mat3x->xColumn.z) >> 0xc; + + mtxStruct.mtx2.yColumn.x += (weight * mat3x->yColumn.x) >> 0xc; + mtxStruct.mtx2.yColumn.y += (weight * mat3x->yColumn.y) >> 0xc; + mtxStruct.mtx2.yColumn.z += (weight * mat3x->yColumn.z) >> 0xc; + + mtxStruct.mtx2.zColumn.x += (weight * mat3x->zColumn.x) >> 0xc; + mtxStruct.mtx2.zColumn.y += (weight * mat3x->zColumn.y) >> 0xc; + mtxStruct.mtx2.zColumn.z += (weight * mat3x->zColumn.z) >> 0xc; + } + + if (!unk) { + while (func_0200598c(mat4x)) + ; + GFX_FIFO_MTX_MODE = 2; // Position + Vector + func_02005698(&invBMtx[jntIndex].unkMtx); + } + + weight = *(termPtr + 2) << 4; + + mtxStruct.mtx1.xColumn.x += (weight * mat4x->xColumn.x) >> 0xc; + mtxStruct.mtx1.xColumn.y += (weight * mat4x->xColumn.y) >> 0xc; + mtxStruct.mtx1.xColumn.z += (weight * mat4x->xColumn.z) >> 0xc; + + mtxStruct.mtx1.yColumn.x += (weight * mat4x->yColumn.x) >> 0xc; + mtxStruct.mtx1.yColumn.y += (weight * mat4x->yColumn.y) >> 0xc; + mtxStruct.mtx1.yColumn.z += (weight * mat4x->yColumn.z) >> 0xc; + + mtxStruct.mtx1.zColumn.x += (weight * mat4x->zColumn.x) >> 0xc; + mtxStruct.mtx1.zColumn.y += (weight * mat4x->zColumn.y) >> 0xc; + mtxStruct.mtx1.zColumn.z += (weight * mat4x->zColumn.z) >> 0xc; + + mtxStruct.mtx1.wColumn.x += (weight * mat4x->wColumn.x) >> 0xc; + mtxStruct.mtx1.wColumn.y += (weight * mat4x->wColumn.y) >> 0xc; + mtxStruct.mtx1.wColumn.z += (weight * mat4x->wColumn.z) >> 0xc; + + termPtr += 3; + mat3x = &data_0205ae08.mUnk_1400[jntIndex].mtx2; + + if (!unk) { + while (func_020059bc(mat3x)) + ; + } + } + mtxStruct.mtx2.xColumn.x += (weight * mat3x->xColumn.x) >> 0xc; + mtxStruct.mtx2.xColumn.y += (weight * mat3x->xColumn.y) >> 0xc; + mtxStruct.mtx2.xColumn.z += (weight * mat3x->xColumn.z) >> 0xc; + + mtxStruct.mtx2.yColumn.x += (weight * mat3x->yColumn.x) >> 0xc; + mtxStruct.mtx2.yColumn.y += (weight * mat3x->yColumn.y) >> 0xc; + mtxStruct.mtx2.yColumn.z += (weight * mat3x->yColumn.z) >> 0xc; + + mtxStruct.mtx2.zColumn.x += (weight * mat3x->zColumn.x) >> 0xc; + mtxStruct.mtx2.zColumn.y += (weight * mat3x->zColumn.y) >> 0xc; + mtxStruct.mtx2.zColumn.z += (weight * mat3x->zColumn.z) >> 0xc; + + func_02005644((const Mat4x3p *) &mtxStruct.mtx2); + GFX_FIFO_MTX_MODE = 1; // Position + func_02005644(&mtxStruct.mtx1); + GFX_FIFO_MTX_MODE = 0; // Projection + GFX_FIFO_MTX_RESTORE = 1; + GFX_FIFO_MTX_MODE = 2; // Position + Vector + GFX_FIFO_MTX_STORE = (*(renderState->currentCmd + 1)); + renderState->currentCmd += 3 + *(renderState->currentCmd + 2) * 3; +} + +// Renders the SBC command 0xA (unknown) +void G3d_SBCRender_00A(G3d_RenderState *renderState, u32) { + u32 callbackSkip; + u32 callbackSegment; + + if (renderState->callbackFuncs[G3D_SBC_CMD_00A]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00A]; + } else { + callbackSegment = 0; + } + + if (callbackSegment == 1) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00A])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_00A]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00A]; + } else { + callbackSegment = 0; + } + callbackSkip = (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD) && !callbackSkip) { + u32 int1; + u32 int2; + int1 = (u32) ((*(renderState->currentCmd + 1)) | (*(renderState->currentCmd + 2) << 8) | + (*(renderState->currentCmd + 3) << 16) | (*(renderState->currentCmd + 4) << 24)); + + int2 = (u32) ((*(renderState->currentCmd + 5) << 0) | (*(renderState->currentCmd + 6) << 8) | + (*(renderState->currentCmd + 7) << 16) | (*(renderState->currentCmd + 8) << 24)); + + func_01ffa94c(renderState->currentCmd + int1, int2); + } + + if (callbackSegment == 3) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00A])(renderState); + callbackSkip = renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK; + } else { + callbackSkip = 0; + } + + renderState->currentCmd += 1 + sizeof(u32) + sizeof(u32); +} + +// Renders the Scale SBC command +void G3d_SBCRender_SCL(G3d_RenderState *renderState, u32 opCode) { + Vec3p scaleVector; + + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_CMD) && !(renderState->flag & G3D_RENDERST_FLAG_SKIP_SBC_RENDER)) { + if (opCode == 0) { + scaleVector.x = scaleVector.y = scaleVector.z = renderState->upScale; + } else { + scaleVector.x = scaleVector.y = scaleVector.z = renderState->downScale; + } + PushGeometryCommand(0x1b, &scaleVector.x, 3); // MTX_SCALE + } + renderState->currentCmd += 1; +} + +// Renders the SBC command 0xC (unknown) +void G3d_SBCRender_00C(G3d_RenderState *renderState, u32) { + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_SBC_RENDER) && (renderState->flag & G3D_RENDERST_FLAG_BONE_VISIBLE)) { + u32 callbackSkip; + u32 callbackSegment; + u32 mtxModeTex; + + if ((renderState->matAnim->teximage_params & G3D_TEXIMAGE_PARM_TEX_COORD_MODE) != 0x80000000) { // Normal source + static u32 funcArgs[] = {0x2a, 0}; + renderState->matAnim->teximage_params &= ~G3D_TEXIMAGE_PARM_TEX_COORD_MODE; + renderState->matAnim->teximage_params |= 0x80000000; // Normal source + + funcArgs[1] = renderState->matAnim->teximage_params; + PushGeometryCommand(funcArgs[0], &funcArgs[1], 1); + } + + mtxModeTex = 3; + PushGeometryCommand(0x10, &mtxModeTex, 1); + + if (renderState->callbackFuncs[G3D_SBC_CMD_00C]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00C]; + } else { + callbackSegment = 0; + } + + if (callbackSegment == 1) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00C])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_00C]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00C]; + } else { + callbackSegment = 0; + } + callbackSkip = (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!callbackSkip) { + s32 width = renderState->matAnim->width; + s32 height = renderState->matAnim->height; + Vec3p vec; + u32 tmp; + + G3d_Scale_inline(width << 15, -height << 15, INT_TO_Q20(1) << 4); + + tmp = GX_PACK_TEXCOORD_PARAM(width << 11, height << 11); + PushGeometryCommand(0x22, (u32 *) &tmp, 1); // TEXCOORD + } + + if (callbackSegment == 2) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00C])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_00C]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00C]; + } else { + callbackSegment = 0; + } + callbackSkip = (u32) (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!callbackSkip) { + u32 matIndex = *(renderState->currentCmd + 1); + G3d_NameList_Header *h = (G3d_NameList_Header *) ((u8 *) &renderState->materialList->materials + + renderState->materialList->materials.ofsHeader); + u32 *materialOffset = (u32 *) (&h->data[0] + h->element_size * matIndex); + const G3d_Material *mat = (G3d_Material *) ((u8 *) renderState->materialList + *materialOffset); + + if (mat->flag & 0x2000) { + const u8 *p = (const u8 *) mat + sizeof(G3d_Material); + + if (!(mat->flag & 2)) { + p += 8; + } + + if (!(mat->flag & 4)) { + p += 4; + } + + if (!(mat->flag & 8)) { + p += 8; + } + + G3d_MtxMult44_inline((const Mat4p *) p); // MTX_MULT_4x4 + } + } + + if (callbackSegment == 3) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00C])(renderState); + callbackSkip = renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK; + } else { + callbackSkip = 0; + } + + if (!callbackSkip) { + Mat3p m; + G3d_SetMtxMode_inline(2); // MTX_MODE = Position + Vector + G3d_GetCurrentMtx(0, &m); + G3d_SetMtxMode_inline(3); // MTX_MODE = Texture + + if (data_027e037c.flags & 1) { + G3d_MtxMult33_inline((const Mat3p *) &data_027e037c.mUnk_04c); // MTX_MULT_3x3 + G3d_MtxMult33_inline(&gGeomMatrix); // MTX_MULT_3x3 + G3d_MtxMult33_inline(&m); // MTX_MULT_3x3 + } else if (data_027e037c.flags & 2) { + G3d_MtxMult33_inline((const Mat3p *) &data_027e037c.mUnk_04c); // MTX_MULT_3x3 + G3d_MtxMult33_inline(&m); // MTX_MULT_3x3 + } else { + G3d_MtxMult33_inline(&m); // MTX_MULT_3x3 + } + } + + G3d_SetMtxMode_inline(2); // MTX_MODE = Position + Vector + } + renderState->currentCmd += 3; +} + +// Renders the SBC command 0xD (unknown) +void G3d_SBCRender_00D(G3d_RenderState *renderState, u32) { + if (!(renderState->flag & G3D_RENDERST_FLAG_SKIP_SBC_RENDER) && (renderState->flag & G3D_RENDERST_FLAG_BONE_VISIBLE)) { + u32 callbackSkip; + u32 callbackSegment; + u32 num; + Mat4x3p m; + + G3d_GetCurrentMtx(&m, 0); + num = 30; + PushGeometryCommand(0x13, &num, 1); // MTX_STORE + + if ((renderState->matAnim->teximage_params & 0xc0000000) != (3 << 30)) { + static u32 cmd[] = {0x2a, 0}; + renderState->matAnim->teximage_params &= ~0xc0000000; + renderState->matAnim->teximage_params |= 3 << 30; + + cmd[1] = renderState->matAnim->teximage_params; + PushGeometryCommand(cmd[0], &cmd[1], 1); + } + + if (renderState->callbackFuncs[G3D_SBC_CMD_00D]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00D]; + } else { + callbackSegment = 0; + } + + if (callbackSegment == 1) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00D])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_00D]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00D]; + } else { + callbackSegment = 0; + } + callbackSkip = (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!callbackSkip) { + s32 w, h; + w = (s32) renderState->matAnim->width; + h = (s32) renderState->matAnim->height; + + { + static Mat4p mtx = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000}; + + mtx.xColumn.x = w << 15; + mtx.yColumn.y = -h << 15; + mtx.wColumn.x = w << 15; + mtx.wColumn.y = h << 15; + + PushGeometryCommand(0x16, &mtx, 0x10); + } + } + + if (callbackSegment == 2) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00D])(renderState); + if (renderState->callbackFuncs[G3D_SBC_CMD_00D]) { + callbackSegment = renderState->callbackSegment[G3D_SBC_CMD_00D]; + } else { + callbackSegment = 0; + } + callbackSkip = (u32) (renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK); + } else { + callbackSkip = 0; + } + + if (!callbackSkip) { + u32 idxMat = *(renderState->currentCmd + 1); + u32 matIndex = *(renderState->currentCmd + 1); + G3d_NameList_Header *h = (G3d_NameList_Header *) ((u8 *) &renderState->materialList->materials + + renderState->materialList->materials.ofsHeader); + u32 *materialOffset = (u32 *) (&h->data[0] + h->element_size * matIndex); + const G3d_Material *mat = (G3d_Material *) ((u8 *) renderState->materialList + *materialOffset); + + if (mat->flag & 0x2000) { + const Mat4p *effect_mtx; + const u8 *p = (const u8 *) mat + sizeof(G3d_Material); + + if (!(mat->flag & 2)) { + p += 8; + } + + if (!(mat->flag & 4)) { + p += 4; + } + + if (!(mat->flag & 8)) { + p += 8; + } + + G3d_MtxMult44_inline((const Mat4p *) p); // MTX_MULT_4x4 + } + } + + if (callbackSegment == 3) { + renderState->flag &= ~G3D_RENDERST_FLAG_SKIP_CALLBACK; + (*renderState->callbackFuncs[G3D_SBC_CMD_00D])(renderState); + callbackSkip = renderState->flag & G3D_RENDERST_FLAG_SKIP_CALLBACK; + } else { + callbackSkip = 0; + } + + if (!callbackSkip) { + Mat4p mtx; + u32 tmp; + + if (data_027e037c.flags & 1) { + PushGeometryCommand(0x1c, &gGeomTranslation, 3); // MTX_TRANS + G3d_MtxMult33_inline(&gGeomMatrix); // MTX_MULT_3x3 + G3d_MtxMult43_inline(&m); // MTX_MULT_4x3 + + } else if (data_027e037c.flags & 2) { + G3d_MtxMult43_inline(&m); + } else { + G3d_MtxMult43_inline(func_02018450()); + G3d_MtxMult43_inline(&m); + } + + { + FlushGfxQueue(); + + GFX_FIFO_MTX_MODE = 0; // Projection + GFX_FIFO_MTX_PUSH = 0; + GFX_FIFO_MTX_IDENTITY = 0; + + while (func_0200598c(&mtx)) + ; + + GFX_FIFO_MTX_POP = 1; + GFX_FIFO_MTX_MODE = 3; // Texture + } + + PushGeometryCommand(0x16, &mtx, 0x10); + tmp = GX_PACK_TEXCOORD_PARAM((q20) (mtx.wColumn.x >> 4), (q20) (mtx.wColumn.y >> 4)); + PushGeometryCommand(0x22, (u32 *) &tmp, 1); // TEXCOORD + } + + G3d_SetMtxMode_inline(2); // MTX_MODE = Position + Vector + G3d_RestoreMtx_inline(30); + } + renderState->currentCmd += 3; +}
\ No newline at end of file |
