From 8a307d7802e9f8689622fac2beeab926ebbc9669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo?= Date: Thu, 25 Dec 2025 19:47:03 -0300 Subject: [PATCH] Add interpolation to almost every 2D element in the game. (#20) * Add interpolation to almost every 2D element in the game. * Add comments. * Fix interpolation on life icon. Also fix text interpolation. * Fix interpolation for more 2D elements and disable vertex interpolation on them. --- patches/hud_transform_tagging.c | 660 ++++++++++++++++++++++++- patches/projection_transform_tagging.c | 83 ++++ patches/text_transform_tagging.c | 483 ++++++++++++++++++ patches/transform_ids.h | 44 +- 4 files changed, 1260 insertions(+), 10 deletions(-) create mode 100644 patches/text_transform_tagging.c diff --git a/patches/hud_transform_tagging.c b/patches/hud_transform_tagging.c index a4d4bd9..55302ab 100644 --- a/patches/hud_transform_tagging.c +++ b/patches/hud_transform_tagging.c @@ -1,11 +1,22 @@ #include "patches.h" #include "transform_ids.h" #include "functions.h" +#include "../src/core2/gc/zoombox.h" +#define AIRSCORE_COUNT (6) + +extern u8 D_80381E58[5]; +extern u16 D_80381620[0xD][5][0x10]; +extern u16 gScissorBoxLeft; +extern u16 gScissorBoxRight; +extern u16 gScissorBoxTop; +extern u16 gScissorBoxBottom; extern s32 D_803815C0; extern s32 D_803815E4; extern s32 D_803815EC; extern s32 D_8036A018[]; +extern s32 D_80381EC4; +extern s32 gTotalHealth; extern f32 D_803815C8; extern f32 D_803815CC; extern f32 D_803815D0; @@ -13,19 +24,49 @@ extern f32 D_803815D4; extern f32 D_803815D8; extern f32 D_803815DC; extern f32 D_803815E0; +extern f32 D_80381E54; +extern f32 D_80381E60[5]; +extern f32 D_80381E78[5]; +extern f32 D_80381EB8; +extern f32 D_80381EBC; +extern f32 D_80381EFC; +extern f32 D_80381F08[8]; +extern f32 D_80381F68[AIRSCORE_COUNT]; +extern f32 s_texture_scale; +extern f32 s_active_count; extern s32 D_803815E8; +extern f32 gHealth; extern void *D_8036A010; extern void *D_8036A014; +extern Gfx D_80369920[]; extern Gfx D_8036A030[]; +extern Gfx D_8036A228[]; +extern Gfx D_8036A278[]; +extern Gfx D_8036A918[]; +extern Gfx s_fxairscore_context[]; +extern void *D_80381EB0[2]; +extern char code_78E50_ItemValueString[8]; +extern BKSprite *D_80381E40[5]; +extern BKSprite *gSpriteHealth; +extern BKSprite *gSpriteRedHealth; +extern BKSprite *s_sprite; +extern struct1Cs_1 D_8036C58C[0xD]; extern void func_80347FC0(Gfx **gfx, BKSprite *sprite, s32 frame, s32 tmem, s32 rtile, s32 uls, s32 ult, s32 cms, s32 cmt, s32 *width, s32 *height); +extern void func_80348044(Gfx **gfx, BKSprite *sprite, s32 frame, s32 tmem, s32 rtile, s32 uls, s32 ult, s32 cms, s32 cmt, s32 *width, s32 *height, s32 *frame_width, s32 *frame_height, s32 *texture_x, s32 *texture_y, s32 *textureCount); extern f32 func_802FDE60(f32 arg0); extern f32 func_802FB0E4(struct8s *this); extern s32 func_802FB0D4(struct8s *this); +extern f32 func_802FB0DC(struct8s *this); +extern void func_802FD360(struct8s *arg0, Gfx **gfx, Mtx **mtx, Vtx **vtx); extern s32 itemPrint_getValue(s32 item_id); +extern s32 level_get(void); +extern s32 itemscore_noteScores_getTotal(void); extern s32 getGameMode(void); extern f32 vtxList_getGlobalNorm(BKVertexList *); +s32 itemPrint_lastValues[0x2C]; + typedef struct { u8 pad0[0x14]; s32 unk14; @@ -51,6 +92,58 @@ typedef struct { AnimCtrl *anim_ctrl; }Struct_core2_79830_0; +extern struct { + u8 state; + u8 menu; + u8 selection; //menu page + u8 exit_pause : 1; + u8 unk3_6 : 1; //busy? + u8 unk3_5 : 1; + u8 unk3_4 : 1; + u8 left_joystick_visible : 1; + u8 right_joystick_visible : 1; + u8 b_button_visible : 1; + u8 unk3_0 : 1; + s8 zoombox_opening_count; + s8 zoombox_closing_count; + u8 unk6; + u8 unk7; + s8 unk8; //header position + s8 page; + s8 joystick_frame; + u8 joystick_frame_count; + f32 unkC; + GcZoombox *zoombox[4]; + f32 unk20; + BKSprite *joystick_sprite; + f32 unk28; + BKSprite *b_button_sprite; + u8 b_button_frame; + u8 b_button_frame_count; //B-button total frames + s16 b_button_alpha; //B-button alpha + s16 left_joystick_alpha; //left joystick alpha + s16 right_joystick_alpha; //right joystick alpha + u8 page_cnt; + u8 sns_items; + u8 sns_visible; + // u8 pad3B[1]; + s16 sns_alpha; //sns opacity + s16 unk3E[7]; + s16 unk4C[7]; + // u8 pad5A[0x3]; + BKModelBin *sns_egg_model; //SnS Egg Model + BKModelBin *ice_key_model; //Ice key model + u8 pad64[12]; + u32 unk70_31 : 1; + u32 unk70_30 : 1; + u32 return_to_lair_disabled : 1; + u32 pad70_28 : 29; +} D_80383010; + +extern u32 cur_pushed_text_transform_id; +extern u32 cur_pushed_text_transform_origin; +extern u32 cur_pushed_text_transform_skip_interpolation; + // @recomp Tag the matrices for each honeycomb piece. RECOMP_PATCH void fxhoneycarrierscore_draw(s32 arg0, struct8s *arg1, Gfx **arg2, Mtx **arg3, Vtx **arg4) { f64 var_f24; @@ -70,6 +163,13 @@ RECOMP_PATCH void fxhoneycarrierscore_draw(s32 arg0, struct8s *arg1, Gfx **arg2, sp118 = D_803815C0 == 2; if (D_8036A010 != 0) { func_80347FC0(arg2, (sp118) ? (D_8036A014 != 0) ? D_8036A014 : D_8036A010 : D_8036A010, 0, 0, 0, 0, 0, 2, 2, &sp13C, &sp138); + + // @recomp Align the honeycomb pieces to the right side of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + gEXPushScissor((*arg2)++); + gEXSetScissor((*arg2)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_RIGHT, G_EX_ORIGIN_RIGHT, gScissorBoxLeft - gScissorBoxTop, gScissorBoxRight, 0, gScissorBoxBottom); + gEXSetViewportAlign((*arg2)++, G_EX_ORIGIN_RIGHT, -gScissorBoxTop * 4, 0); + viewport_setRenderViewportAndOrthoMatrix(arg2, arg3); gSPDisplayList((*arg2)++, D_8036A030); for (sp134 = 0; sp134 < ((sp118) ? ((D_8036A014 != 0) ? 2 : 1) : 6); sp134++) { @@ -131,6 +231,11 @@ RECOMP_PATCH void fxhoneycarrierscore_draw(s32 arg0, struct8s *arg1, Gfx **arg2, // @recomp Clear the matrix group. gEXPopMatrixGroup((*arg2)++, G_MTX_MODELVIEW); } + + // @recomp Clear the matrix group. + gEXSetViewportAlign((*arg2)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*arg2)++); + gDPPipeSync((*arg2)++); gDPSetTextureLUT((*arg2)++, G_TT_NONE); gDPPipelineMode((*arg2)++, G_PM_NPRIMITIVE); @@ -138,6 +243,507 @@ RECOMP_PATCH void fxhoneycarrierscore_draw(s32 arg0, struct8s *arg1, Gfx **arg2, } } +// @recomp Patched to tag the Jinjos on the HUD. +RECOMP_PATCH void fxjinjoscore_draw(s32 arg0, struct8s *arg1, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + BKSprite *sprite; // s1 + s32 draw_index; // s5 + s32 texture_width; // sp11C + s32 texture_height; // sp118 + s32 jinjo_id; // sp114 + f32 center_y; // f14 (sp110) + f32 center_x; // f20 (sp10C) + f32 x_offset; // f26 (sp108) + f32 y_offset; // f28 (sp104) + f32 pos_x; // f30 (sp100) + s32 i; // v1 (spFC) + s32 j; // v0_2 (spF8) + + // @recomp Align the Jinjos to the left side of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT, gScissorBoxLeft, gScissorBoxRight, gScissorBoxTop, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_LEFT, 0, 0); + + gSPDisplayList((*gfx)++, D_8036A228); + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + + pos_x = 44.0f; + // Draw all jinjo heads + for (jinjo_id = 0; jinjo_id < 5; jinjo_id++) { + s32 jinjo_collected; // spF0 <---- + sprite = D_80381E40[jinjo_id]; + jinjo_collected = (D_80381E58[jinjo_id] != 0) ? 1 : 0; + if (sprite != NULL) { + func_80347FC0(gfx, sprite, (s32)D_80381E60[jinjo_id], 0, 0, 0, 0, 2, 2, &texture_width, &texture_height); + // Load the palette for the corresponding jinjo color + gDPLoadTLUT_pal16((*gfx)++, 0, D_80381620[(s32)D_80381E60[jinjo_id]][jinjo_id]); + x_offset = 0.0f; + y_offset = 0.0f; + // Draw the jinjo head, once if uncollected and twice if collected + // If the head is drawn twice then the first draw will be the drop shadow + for (draw_index = jinjo_collected; draw_index >= 0; draw_index--) { + gDPPipeSync((*gfx)++); + // Draw 0 is the jinjo's head, anything else is a shadow + if (draw_index != 0) { + // Use only primitive color as the color input in order to make a solid color shadow + gDPSetCombineLERP((*gfx)++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0); + // Set up a translucent black for primitive color to draw the shadow + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0x8C); + } + else { + // Use the texture as the color input + gDPSetCombineLERP((*gfx)++, 0, 0, 0, TEXEL0, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0, TEXEL0, 0, PRIMITIVE, 0); + // If the jinjo is collected then it's drawn fully opaque, otherwise it's drawn with partial alpha + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, jinjo_collected ? 0xFF : 0x6E); + } + center_x = pos_x - (f32)gFramebufferWidth / 2 + x_offset; + + // @recomp Remove vertical translation from the vertices. + center_y = (f32)gFramebufferHeight / 2 - 266.0f + 40.0f + y_offset; + //center_y = (f32)gFramebufferHeight / 2 + func_802FB0E4(arg1) - 266.0f + 40.0f + y_offset - D_80381E78[jinjo_id]; + + // @recomp Assign the matrix group for each Jinjo and its shadow separately. + gEXMatrixGroupSimpleNormal((*gfx)++, HUD_JINJOSCORE_TRANSFORM_ID_START + jinjo_id * 2 + draw_index, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + // @recomp Add vertical translation to matrix. + guTranslate(*mtx, 0.0f, (func_802FB0E4(arg1) - D_80381E78[jinjo_id]) * 4.0f, 0.0f); + gSPMatrix((*gfx)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + gSPVertex((*gfx)++, *vtx, 4, 0); + // Set up the positions of the four vertices + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + (*vtx)->v.ob[0] = ((texture_width * D_80381E54 * j) - (texture_width * D_80381E54 / 2) + center_x) * 4; + (*vtx)->v.ob[1] = ((texture_height * D_80381E54 / 2) - (texture_height * D_80381E54 * i) + center_y) * 4; + (*vtx)->v.ob[2] = -20; + (*vtx)->v.tc[0] = ((texture_width - 1) * j) << 6; + (*vtx)->v.tc[1] = ((texture_height - 1) * i) << 6; + (*vtx)++; + } + } + // Draw a quad made of the four vertices + gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); + + // @recomp Clear the matrix group. + gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + + x_offset += -2; + y_offset += 2; + } + } + // Move the next jinjo head over by 32 pixels + pos_x += 32.0f; + } + + // @recomp Clear the matrix group. + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + + gDPPipeSync((*gfx)++); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); +} + +// @recomp Patched to tag the pieces of air and also align them to the left side of the screen. +RECOMP_PATCH void fxairscore_draw(enum item_e item_id, struct8s *arg1, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + f32 y; + f32 x; + s32 texture_width; + s32 texture_height; + s32 i_part; + s32 var_s6; + s32 v_x; + s32 v_y; + + if (s_sprite != 0) { + gSPDisplayList((*gfx)++, s_fxairscore_context); + func_80347FC0(gfx, s_sprite, 0, 0, 0, 0, 0, 2, 2, &texture_width, &texture_height); + + // @recomp Align the pieces of air to the left side of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT, gScissorBoxLeft, gScissorBoxRight, gScissorBoxTop, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_LEFT, 0, 0); + + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + //render all 6 air pieces + for (i_part = 0; i_part < AIRSCORE_COUNT; i_part++) { + if ((i_part != 0) && (i_part != 5)) { + var_s6 = (i_part & 1) ? i_part + 1 : i_part - 1; + } + else { + var_s6 = i_part; + } + gDPPipeSync((*gfx)++); + if ((f32)(5 - i_part) < s_active_count) { + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0xFF); + } + else { + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0x78); + } + x = func_802FB0E4(arg1); + x = ((-40 + x) + D_80381F68[var_s6]) - ((f32)gFramebufferWidth / 2); + y = ((78 + (i_part * 15.5)) - ((f32)gFramebufferHeight / 2)); + + // @recomp Assign a matrix group to each piece of air. + gEXMatrixGroupSimpleVerts((*gfx)++, HUD_AIRSCORE_TRANSFORM_ID_START + i_part, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + //stagger x position + x = (i_part & 1) ? x + 5.0f : x - 5.0f; + gSPVertex((*gfx)++, *vtx, 4, 0); + for (v_y = 0; v_y < 2; v_y++) { + for (v_x = 0; v_x < 2; v_x++) { + (*vtx)->v.ob[0] = (x + (((texture_width * s_texture_scale) * v_x) - ((texture_width * s_texture_scale) / 2))) * 4.0f; + (*vtx)->v.ob[1] = (y + (((texture_height * s_texture_scale) / 2) - (texture_height * s_texture_scale) * v_y)) * 4.0f; + (*vtx)->v.ob[2] = -0x14; + (*vtx)->v.tc[0] = ((texture_width - 1) * v_x) << 6; + (*vtx)->v.tc[1] = ((texture_height - 1) * v_y) << 6; + (*vtx)++; + } + } + gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); + + // @recomp Clear the matrix group. + gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + } + + // @recomp Clear the matrix group. + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + + gDPPipeSync((*gfx)++); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); + } +} + +// @recomp Patched to tag the health bar and align it to the left side of the screen. +RECOMP_PATCH void fxhealthscore_draw(enum item_e item_id, struct8s *arg1, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + int i; + int tmp_v1; + s32 honeycomb_width; + s32 honeycomb_height; + int tmp_v0; + f32 f18; + f32 f14; + f32 f20; + s32 is_red_health_initialized = FALSE; + s32 s6; + + if (gSpriteHealth == NULL) { + return; + } + + gSPDisplayList((*gfx)++, D_8036A918); + func_80347FC0(gfx, gSpriteHealth, 0, 0, 0, 0, 0, 2, 2, &honeycomb_width, &honeycomb_height); + + // @recomp Align the health bar to the left side of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT, gScissorBoxLeft, gScissorBoxRight, gScissorBoxTop, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_LEFT, 0, 0); + + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + + //loop over each honeycomb piece + for (i = gTotalHealth - 1; i >= 0; i--) {//L80300E40 + if (i != 0 && (i + 1 != gTotalHealth || gTotalHealth & 1)) { + s6 = (i & 1) ? i + 1 : i - 1; + } + else {//L80300E84 + s6 = i; + } + + gDPPipeSync((*gfx)++); + + if (gHealth > i) { + if (0 < (gHealth - 8.0f) && (gHealth - 8.0f) > i) { + if (!is_red_health_initialized) { + func_80347FC0(gfx, gSpriteRedHealth, 0, 0, 0, 0, 0, 2, 2, &honeycomb_width, &honeycomb_height); + is_red_health_initialized = TRUE; + } + }//L80300F38 + + gDPSetPrimColor((*gfx)++, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); + } + else {//L80300F58 + gDPSetPrimColor((*gfx)++, 0, 0, 0xFF, 0xFF, 0xFF, 0x78); + } + + f20 = 96.0f - (f32)gFramebufferWidth / 2 + (i * 13); + f14 = (f32)gFramebufferHeight / 2 - func_802FB0E4(arg1) - D_80381F08[s6] - -48.0f; + f14 = (i & 1) ? f14 + 5.75 : f14 - 5.75; + + // @recomp Assign a matrix group to each piece of health. + gEXMatrixGroupSimpleVerts((*gfx)++, HUD_HEALTHSCORE_TRANSFORM_ID_START + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + gSPVertex((*gfx)++, *vtx, 4, 0); + + for (tmp_v1 = 0; tmp_v1 < 2; tmp_v1++) {//L8030101C + for (tmp_v0 = 0; tmp_v0 < 2; tmp_v0++) {//L80301030 + (*vtx)->v.ob[0] = (((honeycomb_width * D_80381EFC) * tmp_v0 - (honeycomb_width * D_80381EFC) / 2) + f20) * 4.0f; + (*vtx)->v.ob[1] = (((honeycomb_height * D_80381EFC) / 2 - (honeycomb_height * D_80381EFC) * tmp_v1) + f14) * 4.0f; + (*vtx)->v.ob[2] = -0x14; + + (*vtx)->v.tc[0] = ((honeycomb_width - 1) * tmp_v0) << 6; + (*vtx)->v.tc[1] = ((honeycomb_height - 1) * tmp_v1) << 6; + (*vtx)++; + } + } + + gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); + + // @recomp Clear the matrix group. + gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + } + + // @recomp Clear the matrix group. + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + + gDPPipeSync((*gfx)++); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); +} + +// @recomp Patched to tag the life icon and align it to the left side of the screen. +RECOMP_PATCH void fxlifescore_draw(enum item_e item_id, struct8s *arg1, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + s32 sp10C; + Vtx *sp108; + s32 sp104; + s32 var_v0; + s32 var_v1; + s32 var_s5; + s32 var_s4; + s32 spF0; + s32 spEC; + s32 spE8; + s32 spE4; + s32 spE0; + s32 spDC; + + sp10C = -1; + sp108 = *vtx; + code_78E50_ItemValueString[0] = '\0'; + strIToA(code_78E50_ItemValueString, MIN(9, itemPrint_getValue(item_id))); + + // @recomp Assign an ID to the text and align it to the left side of the screen. + cur_pushed_text_transform_id = HUD_LIFESCORE_TRANSFORM_PRINT_ID_START; + cur_pushed_text_transform_origin = G_EX_ORIGIN_LEFT; + + // @recomp Keep track of the last item value. If the value has changed, skip vertex interpolation this frame. + if (itemPrint_lastValues[item_id] != itemPrint_getValue(item_id)) { + cur_pushed_text_transform_skip_interpolation = TRUE; + itemPrint_lastValues[item_id] = itemPrint_getValue(item_id); + } + + print_bold_spaced(0x4E, (s32)(func_802FB0E4(arg1) + -16.0f + 4.0f), (char *)&code_78E50_ItemValueString); + + // @recomp Clear the ID and alignment for the text. + cur_pushed_text_transform_id = 0; + cur_pushed_text_transform_origin = G_EX_ORIGIN_NONE; + cur_pushed_text_transform_skip_interpolation = FALSE; + + if (1); //fake + if (D_80381EB0[D_80381EC4] != NULL) { + // @recomp Align the life icon to the left side of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_LEFT, gScissorBoxLeft, gScissorBoxRight, gScissorBoxTop, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_LEFT, 0, 0); + + gSPDisplayList((*gfx)++, D_8036A278); + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + if (gfx); + + // @recomp Assign a matrix group to the life icon. + gEXMatrixGroupSimpleNormal((*gfx)++, HUD_LIFESCORE_TRANSFORM_ID_START, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + gDPPipeSync((*gfx)++); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, TEXEL0, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0xFF); + do { + func_80348044(gfx, D_80381EB0[D_80381EC4], (s32)D_80381EBC % 4, 0, 0, 0, 0, 2, 2, &spF0, &spEC, &spE8, &spE4, &spE0, &spDC, &sp10C); + + if (((*vtx - sp108) & 0xF) == 0) { + gSPVertex((*gfx)++, *vtx, MIN(0x10, (1 + sp10C) << 2), 0); + sp104 = 0; + } + else { + sp104 = sp104 + 4; + } + + var_s5 = (40.0f - ((f32)gFramebufferWidth / 2)) + spE0; + var_s4 = (((((f32)gFramebufferHeight / 2) - func_802FB0E4(arg1)) - -16.0f) - spDC); + + // @recomp Assign the vertical translation of the life icon to the matrix. + guTranslate(*mtx - 1, 0.0f, -func_802FB0E4(arg1) * 4.0f, 0.0f); + var_s4 += func_802FB0E4(arg1); + + for (var_v1 = 0; var_v1 < 2; var_v1++) { + for (var_v0 = 0; var_v0 < 2; var_v0++) { + (*vtx)->v.ob[0] = (s16)(s32)(((((f32)spF0 * D_80381EB8 * (f32)var_v0) - (((f32)spE8 * D_80381EB8) / 2)) + var_s5) * 4.0f); + (*vtx)->v.ob[1] = (s16)(s32)((((((f32)spE4 * D_80381EB8) / 2) - ((f32)spEC * D_80381EB8 * var_v1)) + var_s4) * 4.0f); + (*vtx)->v.ob[2] = -0x14; + (*vtx)->v.tc[0] = ((spF0 - 1) * var_v0) << 6; + (*vtx)->v.tc[1] = ((spEC - 1) * var_v1) << 6; + (*vtx)++; + } + } + gSP1Quadrangle((*gfx)++, sp104, sp104 + 1, sp104 + 3, sp104 + 2, 0); + } while (sp10C != 0); + + // @recomp Clear the matrix group and the viewport alignment. + gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + + gDPPipeSync((*gfx)++); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); + } +} + +// @recomp Patched to remove translation of the score element from the vertices and move it to the matrix. +RECOMP_PATCH void func_802FD360(struct8s *arg0, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + s32 tmp_s2 = 0; + s32 tmp_s4; + s32 texture_width; + s32 texture_height; + f32 tmp_f26; + f32 f2; + + + if (arg0->unk50 == NULL) return; + + gSPDisplayList((*gfx)++, &D_80369920); + if (arg0->unk20 == ITEM_C_NOTE) { + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA, G_CC_MODULATEIA); + } + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + + // @recomp Add vertical animation component to the matrix. + guTranslate(*mtx - 1, 0.0f, -func_802FB0E4(arg0) * arg0->unk4C * 4.0f, 0.0f); + + gSPVertex((*gfx)++, *vtx, 4, 0); + if (arg0->unk20 == ITEM_0_HOURGLASS_TIMER) { + tmp_s2 = 0xC; + } + func_80347FC0(gfx, (BKSprite *)(arg0->unk50), ((s32)arg0->unk60 + tmp_s2) % arg0->unk2C, 0, 0, 0, 0, 2, 2, &texture_width, &texture_height); + tmp_f26 = (arg0->unk20 == ITEM_0_HOURGLASS_TIMER && texture_width == 0x10) ? 1.0f : 0.0f; + for (tmp_s4 = 0; tmp_s4 < 2; tmp_s4++) {//L802FD528 + for (tmp_s2 = 0; tmp_s2 < 2; tmp_s2++) {// + (*vtx)->v.ob[0] = ((func_802FB0DC(arg0) + (((texture_width * arg0->unk40 * tmp_s2 - texture_width * arg0->unk40 / 2) - (f32)gFramebufferWidth / 2) + arg0->unk38)) + tmp_f26) * 4.0f; + // @recomp Removed vertical animation component from the vertices. + //(*vtx)->v.ob[1] = ((((texture_height * arg0->unk40 / 2 - texture_height * arg0->unk40 * tmp_s4) + (f32)gFramebufferHeight / 2) - arg0->unk3C) - func_802FB0E4(arg0) * arg0->unk4C) * 4.0f; + (*vtx)->v.ob[1] = ((((texture_height * arg0->unk40 / 2 - texture_height * arg0->unk40 * tmp_s4) + (f32)gFramebufferHeight / 2) - arg0->unk3C)) * 4.0f; + (*vtx)->v.ob[2] = -0x14; + (*vtx)->v.tc[0] = ((texture_width - 1) * tmp_s2) << 6; + (*vtx)->v.tc[1] = ((texture_height - 1) * tmp_s4) << 6; + if (arg0->unk20 == ITEM_C_NOTE) { + if (tmp_s4 == 0) { + (*vtx)->v.cn[0] = 0xff; + (*vtx)->v.cn[1] = 0xff; + (*vtx)->v.cn[2] = 0x0; + (*vtx)->v.cn[3] = 0xff; + } + else if (tmp_s2 != 0) { + (*vtx)->v.cn[0] = 0xff; + (*vtx)->v.cn[1] = 100; + (*vtx)->v.cn[2] = 0x0; + (*vtx)->v.cn[3] = 0xff; + } + else { + (*vtx)->v.cn[0] = 0xff; + (*vtx)->v.cn[1] = 200; + (*vtx)->v.cn[2] = 0x0; + (*vtx)->v.cn[3] = 0xff; + } + } + (*vtx)++; + } + } + gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); + gDPPipeSync((*gfx)++); + gDPSetTextureLUT((*gfx)++, G_TT_NONE); + gDPPipelineMode((*gfx)++, G_PM_NPRIMITIVE); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); +} + +// @recomp Patch to tag any 2D score elements and align them to the right side of the screen. +RECOMP_PATCH void fxcommon2score_draw(enum item_e item_id, struct8s *arg1, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + f32 pad; + s32 sp38; + f32 sp34; + + + sp38 = itemPrint_getValue(item_id); + sp34 = 0.0f; + if (item_id == ITEM_C_NOTE) { + if (level_get() == LEVEL_6_LAIR || level_get() == LEVEL_C_BOSS) { + sp38 = itemscore_noteScores_getTotal(); + } + } + if (item_id < 6) { + sp38 = ((sp38) ? 1 : 0) + sp38 / 60; + }//L802FDBA8 + if (item_id == ITEM_1B_VILE_VILE_SCORE && 9 < sp38) { + sp34 = -16.0f; + } + if (item_id == ITEM_1C_MUMBO_TOKEN || item_id == ITEM_25_MUMBO_TOKEN_TOTAL) { + if (sp38 >= 100) { + sp38 = 99; + } + } + arg1->string_54[0] = 0; + //convert to string + strIToA(arg1->string_54, sp38); + + // @recomp Assign an ID to the text and align it to the left or the right side of the screen. + bool left_alignment = arg1->unk38 < (gFramebufferWidth * 1.0f / 3.0f); + cur_pushed_text_transform_id = HUD_SCORE2_TRANSFORM_PRINT_ID_START + item_id * HUD_SCORE2_TRANSFORM_PRINT_ID_COUNT; + cur_pushed_text_transform_origin = left_alignment ? G_EX_ORIGIN_LEFT : G_EX_ORIGIN_RIGHT; + + // @recomp Keep track of the last item value. If the value has changed, skip vertex interpolation this frame. + if (itemPrint_lastValues[item_id] != sp38) { + cur_pushed_text_transform_skip_interpolation = TRUE; + itemPrint_lastValues[item_id] = sp38; + } + + //print text (blue egg font) + print_bold_spaced( + (s32)(func_802FB0DC(arg1) + arg1->unk38 + arg1->unk44 + sp34), + (s32)(func_802FB0E4(arg1) * arg1->unk4C + (arg1->unk3C + arg1->unk48)), + arg1->string_54 + ); + + // @recomp Clear the ID and alignment for the text. + cur_pushed_text_transform_id = 0; + cur_pushed_text_transform_origin = G_EX_ORIGIN_NONE; + cur_pushed_text_transform_skip_interpolation = FALSE; + + // @recomp Align the score element to either the left or the right side of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_RIGHT, 0, gScissorBoxRight, 0, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, left_alignment ? G_EX_ORIGIN_LEFT : G_EX_ORIGIN_RIGHT, left_alignment ? 0 : gScissorBoxTop * -4, 0); + + // @recomp Assign a matrix group to the score element. + gEXMatrixGroupSimpleNormal((*gfx)++, HUD_SCORE2_TRANSFORM_ID_START + item_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + //draw sprite? + func_802FD360(arg1, gfx, mtx, vtx); + + // @recomp Clear the matrix group. + gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); +} + #define RM_DEPTH_SET(clk) \ Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | FORCE_BL | G_ZS_PRIM | \ ZMODE_OPA | \ @@ -157,7 +763,25 @@ RECOMP_PATCH void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx if (a1->model != NULL && func_802FB0D4(arg1)) { a1->value_string[0] = '\0'; strIToA(a1->value_string, itemPrint_getValue(item_id)); + + // @recomp Align the score element's text to the right or use its default alignment. + bool aligned_to_the_right = a1->unk30 > (gFramebufferWidth * 2 / 3); + cur_pushed_text_transform_id = HUD_SCORE3_TRANSFORM_PRINT_ID_START + item_id * HUD_SCORE3_TRANSFORM_PRINT_ID_COUNT; + cur_pushed_text_transform_origin = aligned_to_the_right ? G_EX_ORIGIN_RIGHT : G_EX_ORIGIN_NONE; + + // @recomp Keep track of the last item value. If the value has changed, skip vertex interpolation this frame. + if (itemPrint_lastValues[item_id] != itemPrint_getValue(item_id)) { + cur_pushed_text_transform_skip_interpolation = TRUE; + itemPrint_lastValues[item_id] = itemPrint_getValue(item_id); + } + print_bold_spaced(a1->unk30 + a1->unk40, sp40 + a1->unk44, a1->value_string); + + // @recomp Clear the ID and alignment for the text. + cur_pushed_text_transform_id = 0; + cur_pushed_text_transform_origin = G_EX_ORIGIN_NONE; + cur_pushed_text_transform_skip_interpolation = FALSE; + sp3C = viewport_transformCoordinate(a1->unk30, sp40, sp5C, sp68); sp44[0] = 0.0f; @@ -176,6 +800,20 @@ RECOMP_PATCH void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx a1->unk6C = 1.1 * (vtxList_getGlobalNorm(model_getVtxList(a1->model)) * a1->unk3C); } + if (a1->anim_ctrl != NULL) { + anctrl_drawSetup(a1->anim_ctrl, sp5C, 1); + } + + // @recomp If necessary, align the score element to the right of the screen. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + if (aligned_to_the_right) { + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_RIGHT, G_EX_ORIGIN_RIGHT, gScissorBoxLeft - gScissorBoxTop, gScissorBoxRight, 0, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_RIGHT, gScissorBoxTop * -4, 0); + } + + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); + // @recomp Draw a rectangle that clears the depth and gets interpolated along with the 3D model. // This fixes an issue where the rectangle would teleport ahead of the movement of the model in HFR // and it also provides a minor performance boost by skipping the need to switch render targets. @@ -215,10 +853,6 @@ RECOMP_PATCH void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx gEXPopCombineMode((*gfx)++); } - if (a1->anim_ctrl != NULL) { - anctrl_drawSetup(a1->anim_ctrl, sp5C, 1); - } - // @recomp Set the model transform ID. cur_drawn_model_transform_id = HUD_SCORE3_TRANSFORM_ID_START + item_id * MARKER_TRANSFORM_ID_COUNT; @@ -226,5 +860,23 @@ RECOMP_PATCH void fxcommon3score_draw(enum item_e item_id, void *arg1, Gfx **gfx // @recomp Clear the model transform ID. cur_drawn_model_transform_id = 0; + + if (aligned_to_the_right) { + // @recomp Clear the matrix group. + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + } }//L80300BA4 +} + +// @recomp: Patched to interpolate the header of the totals screen on the pause menu. +RECOMP_PATCH void gcpausemenu_printTotalsHeader(s32 page_id) { + // @recomp Assign an ID for the totals text. + cur_pushed_text_transform_id = HUD_TOTALS_PRINT_TRANSFORM_ID_START; + + struct1Cs_1 *v0 = D_8036C58C + page_id; + print_bold_overlapping(v0->x, D_80383010.unk8, -1.05f, v0->string); + + // @recomp Clear the ID text. + cur_pushed_text_transform_id = 0; } \ No newline at end of file diff --git a/patches/projection_transform_tagging.c b/patches/projection_transform_tagging.c index e15abdb..e1c35a2 100644 --- a/patches/projection_transform_tagging.c +++ b/patches/projection_transform_tagging.c @@ -4,6 +4,10 @@ #include "functions.h" #include "../src/core2/gc/zoombox.h" +extern u16 gScissorBoxLeft; +extern u16 gScissorBoxRight; +extern u16 gScissorBoxTop; +extern u16 gScissorBoxBottom; extern MtxF sViewportMatrix; extern f32 sViewportLookVector[3]; extern u32 D_803835E0; @@ -41,6 +45,8 @@ void func_803382E4(s32); void func_8033687C(Gfx **); void func_80335D30(Gfx **); void func_80344090(BKSpriteDisplayData *self, s32 frame, Gfx **gfx); +void func_802F7B90(s32 arg0, s32 arg1, s32 arg2); +void gcpausemenu_zoombox_callback(s32 portrait_id, s32 zoombox_state); void actor_predrawMethod(Actor *); void actor_postdrawMethod(ActorMarker *); @@ -77,6 +83,9 @@ extern void gcdialog_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); extern void itemPrint_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr); extern void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); +extern u32 cur_pushed_text_transform_id; +extern u32 cur_pushed_text_transform_origin; + // @recomp Patched to set the projection transform ID for the main projection. RECOMP_PATCH void func_802E39D0(Gfx **gdl, Mtx **mptr, Vtx **vptr, s32 framebuffer_idx, s32 arg4) { // @recomp Set the perspective projection transform ID. @@ -309,6 +318,10 @@ RECOMP_PATCH Actor *func_802DC320(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx return this; } +bool left_aligned_zoombox(GcZoombox *this) { + return !this->unk1A4_15 && this->callback == &gcpausemenu_zoombox_callback; +} + // @recomp Patched to set the zoombox's model transform ID. RECOMP_PATCH void func_803163A8(GcZoombox *this, Gfx **gfx, Mtx **mtx) { f32 sp5C[3]; @@ -317,6 +330,16 @@ RECOMP_PATCH void func_803163A8(GcZoombox *this, Gfx **gfx, Mtx **mtx) { f32 sp38[3]; f32 sp34; + // @recomp Align the zoombox to the left of the screen if necessary. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + if (left_aligned_zoombox(this)) { + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_RIGHT, 0, gScissorBoxRight, 0, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_LEFT, 0, 0); + } + + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); + sp34 = viewport_transformCoordinate(this->unk170, this->unk172, sp50, sp5C); if (this->unk1A4_24) { sp5C[1] += 180.0f; @@ -338,6 +361,12 @@ RECOMP_PATCH void func_803163A8(GcZoombox *this, Gfx **gfx, Mtx **mtx) { // @recomp Reset the model transform ID. cur_drawn_model_transform_id = prev_transform_id; + + // @recomp Clear the matrix group. + if (left_aligned_zoombox(this)) { + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + } } // @recomp Patched to set the zoombox portrait's model and ortho projection transform IDs. @@ -357,6 +386,14 @@ RECOMP_PATCH void func_803164B0(GcZoombox *this, Gfx **gfx, Mtx **mtx, s32 arg3, u32 prev_ortho_id = cur_ortho_projection_transform_id; cur_ortho_projection_transform_id = PROJECTION_PORTRAIT_TRANSFORM_ID_START + this->portrait_id; + // @recomp Align the zoombox's portrait to the left of the screen if necessary. + // NOTE: gScissorBoxRight/gScissorBoxTop are incorrectly named in the decompilation and must be swapped. + if (left_aligned_zoombox(this)) { + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_RIGHT, 0, gScissorBoxRight, 0, gScissorBoxBottom); + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_LEFT, 0, 0); + } + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); // @recomp Reset the ortho projection transform ID. @@ -387,4 +424,50 @@ RECOMP_PATCH void func_803164B0(GcZoombox *this, Gfx **gfx, Mtx **mtx, s32 arg3, // @recomp Pop the model matrix group. gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + + if (left_aligned_zoombox(this)) { + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXPopScissor((*gfx)++); + } +} + +// @recomp Patched to assign an ID to the text drawn by the zoombox. +RECOMP_PATCH void func_803162B4(GcZoombox *this) { + // @recomp Align the zoombox to the left of the screen if necessary. + if (left_aligned_zoombox(this)) { + cur_pushed_text_transform_origin = G_EX_ORIGIN_LEFT; + } + + // FIXME: Text inside the zoombox can be tagged but suffers from interpolation errors when scrolling + // to the next line. This can probably be fixed by assigning IDs in a more clever way. + //cur_pushed_text_transform_id = ZOOMBOX_PRINT_TRANSFORM_ID_START + this->portrait_id * ZOOMBOX_PRINT_TRANSFORM_ID_COUNT; + + func_802F7B90(this->unk168, this->unk168, this->unk168); + if (this->unk1A4_30) { + if (this->unk1A4_17) { + func_802F79D0(this->unk16A, this->unk16C, this->unk0, this->unk166, -1); + } + else if (this->unk1A4_15) { + print_bold_spaced(this->unk16A, this->unk16C, this->unk0); + } + else { + print_dialog(this->unk16A, this->unk16C, this->unk0); + } + } + if (this->unk1A4_29) { + if (this->unk1A4_15) { + print_bold_spaced(this->unk16A, this->unk16E, this->unk30); + } + else { + print_dialog(this->unk16A, this->unk16E, this->unk30); + } + } + func_802F7B90(0xff, 0xff, 0xff); + + if (left_aligned_zoombox(this)) { + cur_pushed_text_transform_origin = G_EX_ORIGIN_NONE; + } + + // @recomp If IDs were assigned to the zoombox's text, it would get cleared here. + //cur_pushed_text_transform_id = 0; } diff --git a/patches/text_transform_tagging.c b/patches/text_transform_tagging.c new file mode 100644 index 0000000..ad43bd3 --- /dev/null +++ b/patches/text_transform_tagging.c @@ -0,0 +1,483 @@ +#include "patches.h" +#include "transform_ids.h" +#include "functions.h" + +typedef struct { + u8 unk0; + u8 unk1; + s8 unk2; + s8 unk3; +}Struct_6DA30_0_s; + +typedef struct { + s16 x; + s16 y; + s16 unk4; + s16 unk6; + u8 fmtString[8]; + f32 unk10; + u8 *string; + u8 rgba[4]; +} PrintBuffer; + +extern char D_80380AB0; +extern s8 D_80380F20[0x80]; +extern u16 gScissorBoxLeft; +extern u16 gScissorBoxRight; +extern u16 gScissorBoxTop; +extern u16 gScissorBoxBottom; +extern s32 D_80369068[]; +extern s32 D_80380B04; +extern s32 D_80380AE8; +extern s32 D_80380AEC; +extern s32 D_80380AF0; +extern s32 D_80380AF4; +extern s32 D_80380AF8; +extern s32 D_80380AFC; +extern s32 D_80380B00; +extern s32 D_80380B0C; +extern s32 D_80380B10; +extern s32 D_80380B14; +extern s8 D_80380B20[0x400]; +extern bool print_sInFontFormatMode; +extern Struct_6DA30_0_s D_80369000[]; +extern PrintBuffer *print_sPrintBuffer; +extern PrintBuffer *print_sCurrentPtr; +extern Gfx D_80369238[]; + +extern BKSpriteTextureBlock *func_802F5494(s32 letterId, s32 *fontType); +extern void *func_802F55A8(u8 arg0); +extern f32 func_802F6C90(u8 letter, f32 *xPtr, f32 *yPtr, f32 arg3); + +extern struct { + u8 unk0; + u8 unk1; + u8 unk2; + u8 unk3; +} D_80369078; + +// @recomp This ID plus the index of the character in the string will be used to tag each letter if it's assigned before printing text. +u32 cur_pushed_text_transform_id = 0; +u32 cur_pushed_text_transform_origin = G_EX_ORIGIN_NONE; +u32 cur_pushed_text_transform_skip_interpolation = FALSE; +u32 cur_drawn_text_transform_id = 0; +u32 cur_drawn_text_transform_skip_interpolation = 0; +Mtx *cur_drawn_text_mtx = NULL; +u32 print_sPrintBufferIDs[0x20]; +u32 print_sPrintBufferOrigins[0x20]; +u32 print_sPrintBufferSkipInterpolationFlags[0x20]; + +// @recomp Patched to assign the current ID and origin from the global variables to the print buffer array. +RECOMP_PATCH void _printbuffer_push_new(s32 x, s32 y, u8 *string) { + for (print_sCurrentPtr = print_sPrintBuffer; print_sCurrentPtr < print_sPrintBuffer + 0x20 && print_sCurrentPtr->string; print_sCurrentPtr++) { + } + if (print_sCurrentPtr == print_sPrintBuffer + 0x20) { + print_sCurrentPtr = NULL; + return; + } + print_sCurrentPtr->x = x; + print_sCurrentPtr->y = y; + print_sCurrentPtr->fmtString[0] = (u8)0; + print_sCurrentPtr->string = string; + print_sCurrentPtr->unk10 = 1.0f; + print_sCurrentPtr->rgba[0] = (u8)D_80369078.unk0; + print_sCurrentPtr->rgba[1] = (u8)D_80369078.unk1; + print_sCurrentPtr->rgba[2] = (u8)D_80369078.unk2; + print_sCurrentPtr->rgba[3] = (u8)D_80369078.unk3; + + // @recomp Store the current ID and origin in the arrays that run parallel to the print buffer. + u32 bufferIndex = print_sCurrentPtr - print_sPrintBuffer; + print_sPrintBufferIDs[bufferIndex] = cur_pushed_text_transform_id; + print_sPrintBufferOrigins[bufferIndex] = cur_pushed_text_transform_origin; + print_sPrintBufferSkipInterpolationFlags[bufferIndex] = cur_pushed_text_transform_skip_interpolation; +} + +// @recomp Patched to force orthographic projections to be used for all letters. +RECOMP_PATCH void _printbuffer_draw_letter(char letter, f32 *xPtr, f32 *yPtr, f32 arg3, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + static f32 D_80380FA0; + + // u8 letter = arg0; + BKSpriteTextureBlock *sp214; + s32 sp210; + s32 sp20C; + s32 t0; + s8 t1; + f32 sp200; + f32 f28; + f32 sp1F8; + s32 sp1F4; //font_type; + + int i; + + + + t0 = 0; + sp200 = *xPtr; + f28 = *yPtr; + t1 = 0; + + if (!D_80380B04 && !letter) { + D_80380FA0 = 0.0f; + }//L802F563C + + switch (D_80380AE8) { + case 0: //L802F5678 + if (letter >= '\x21' && letter < '\x5f') { + sp20C = letter - '\x21'; + t0 = 1; + } + break; + case 1: //L802F56A0 + if (letter < '\x80' && D_80380F20[letter] >= 0) { + for (i = 0; D_80369000[i].unk0 != 0; i++) { + if (letter == D_80369000[i].unk1 && D_80380AB0 == D_80369000[i].unk0) { + t1 = D_80369000[i].unk3; + break; + } + }//L802F5710 + sp20C = D_80380F20[letter]; + t0 = 1; + D_80380AB0 = letter; + f28 += (f32)t1 * arg3; + }//L802F5738 + break; + case 2: //L802F5740 + sp20C = letter; + if (D_80380B04) { + t0 = 1; + sp20C += (D_80380B04 << 8) - 0x100; + D_80380B04 = 0; + } + else {//L802F5764 + if (sp20C > 0 && sp20C < 0xfD) + t0 = 1; + } + break; + }//L802F5778 + + if (!t0 || print_sInFontFormatMode) { + print_sInFontFormatMode = FALSE; + switch (letter) { + case ' '://802F5818 + *xPtr += ((D_80380AF0) ? D_80369068[D_80380AE8] : D_80369068[D_80380AE8] * 0.8) * arg3; + break; + + case 'b': //L802F5890 + //toggle background + D_80380B00 = D_80380B00 ^ 1; + break; + + case 'f': //L802F58A8 + D_80380AEC = D_80380AE8 = D_80380AE8 ^ 1; + break; + + case 'l': //L802F58BC + D_80380B10 = 0; + break; + + case 'h': //L802F58C8 + D_80380B10 = 1; + break; + + case 'j': //L802F58D4 + if (D_80380AFC == 0) { + D_80380AFC = 1; + D_80380AEC = D_80380AE8; + D_80380AE8 = 2; + // D_80380AE8 = 2; + } + break; + + case 'e': //L802F58FC + if (D_80380AFC) { + D_80380AFC = 0; + D_80380AE8 = D_80380AEC; + } + break; + + case 'p': //L802F5924 + D_80380AF0 = D_80380AF0 ^ 1; + break; + + case 'q': //L802F593C + D_80380B14 = D_80380B14 ^ 1; + if (D_80380B14) { + gDPSetTextureFilter((*gfx)++, G_TF_POINT); + } + else {//L802F5978 + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + } + break; + + case 'v': //L802F59A0 + //toggle letter gradient + D_80380AF4 ^= 1; + if (D_80380AF4) { + // @recomp Comment these lines out, as the viewport is now set in the parent function. + //viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + //gDPPipeSync((*gfx)++); + //gDPSetTexturePersp((*gfx)++, G_TP_PERSP); + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0xFF); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, TEXEL0, TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0, TEXEL0, 0, SHADE, 0); + } + else {//L802F5A44 + gDPSetCombineMode((*gfx)++, G_CC_DECALRGBA, G_CC_DECALRGBA); + // @recomp Comment this line out, as texture rectangle letters are no longer possible. + //gDPSetTexturePersp((*gfx)++, G_TP_NONE); + } + break; + + case 'd': //L802F5A8C + D_80380AF8 ^= 1; + if (D_80380AF8) { + gDPPipeSync((*gfx)++); + gDPSetCycleType((*gfx)++, G_CYC_2CYCLE); + gDPSetRenderMode((*gfx)++, G_RM_PASS, G_RM_XLU_SURF2); + gDPSetTextureLOD((*gfx)++, G_TL_TILE); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, TEXEL0, TEXEL0, 0, TEXEL1, 0, 0, 0, 0, COMBINED, 0, 0, 0, COMBINED); + } + else {//L802F5B48 + gDPPipeSync((*gfx)++); + gDPSetCombineMode((*gfx)++, G_CC_DECALRGBA, G_CC_DECALRGBA); + gDPSetCycleType((*gfx)++, G_CYC_1CYCLE); + gDPSetTextureLOD((*gfx)++, G_TL_LOD); + gDPSetRenderMode((*gfx)++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + } + break; + + case 0xfd: //L802F5BEC + print_sInFontFormatMode = TRUE; + break; + + case 0xfe://L802F5BF4 + D_80380B04 = 1; + break; + + case 0xff://L802F5BFC + D_80380B04 = 2; + break; + default: + break; + } + } + else {//L802F5C08 + sp214 = func_802F5494(sp20C, &sp1F4); + if (D_80380B10 != 0) { + sp200 += randf2(-2.0f, 2.0f); + f28 += randf2(-2.0f, 2.0f); + } + sp1F8 = (D_80380AF0 != 0) ? D_80369068[D_80380AE8] : sp214->x; + + // temp_f2 = D_80380FA0; + // phi_f2 = temp_f2; + if (D_80380FA0 == 0.0f) { + D_80380FA0 = -sp1F8 * 0.5; + } + + sp200 += (D_80380FA0 + (sp1F8 - sp214->x) * 0.5); + f28 -= sp214->h * 0.5; + sp210 = (s32)(sp214 + 1); + while (sp210 % 8) { + sp210++; + } + if (sp1F4 == SPRITE_TYPE_RGBA32) { + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_RGBA, G_IM_SIZ_32b, sp214->w, sp214->h, 0, 0, sp214->x - 1, sp214->y - 1, NULL, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } + else if (sp1F4 == SPRITE_TYPE_IA8) { + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_IA, G_IM_SIZ_8b, sp214->w, sp214->h, 0, 0, sp214->x - 1, sp214->y - 1, NULL, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } + else if (sp1F4 == SPRITE_TYPE_I8) { + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_I, G_IM_SIZ_8b, sp214->w, sp214->h, 0, 0, sp214->x - 1, sp214->y - 1, NULL, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } + else if (sp1F4 == SPRITE_TYPE_I4) { + gDPLoadTextureTile_4b((*gfx)++, sp210, G_IM_FMT_I, sp214->w, sp214->h, 0, 0, sp214->x - 1, sp214->y - 1, NULL, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + } + else if (sp1F4 == SPRITE_TYPE_CI8) { + void *pal = func_802F55A8(sp20C); + gDPLoadTLUT_pal256((*gfx)++, pal); + gDPLoadTextureTile((*gfx)++, sp210, G_IM_FMT_CI, G_IM_SIZ_8b, sp214->w, sp214->h, 0, 0, sp214->x - 1, sp214->y - 1, NULL, G_TX_CLAMP, G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPSetTextureLUT((*gfx)++, G_TT_RGBA16); + }//L802F6570 + if (D_80380AF8 != 0) { + s32 temp_t1; + s32 phi_a0; + temp_t1 = ((print_sCurrentPtr->unk4 - print_sCurrentPtr->y) - D_80380B0C) + 1; + phi_a0 = -MAX(1 - D_80380B0C, MIN(0, temp_t1)); + + gDPSetTextureImage((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, 32, &D_80380B20); + gDPSetTile((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, (sp214->x + 8) >> 3, 0x0100, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD); + gDPLoadSync((*gfx)++); + gDPLoadTile((*gfx)++, G_TX_LOADTILE, 0 << G_TEXTURE_IMAGE_FRAC, (phi_a0) << G_TEXTURE_IMAGE_FRAC, (sp214->x) << G_TEXTURE_IMAGE_FRAC, (D_80380B0C - 1) << G_TEXTURE_IMAGE_FRAC); + gDPPipeSync((*gfx)++); + gDPSetTile((*gfx)++, G_IM_FMT_I, G_IM_SIZ_8b, ((sp214->x - 0 + 1) * G_IM_SIZ_8b_LINE_BYTES + 7) >> 3, 0x0100, 1, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOLOD); + gDPSetTileSize((*gfx)++, 1, 0 << G_TEXTURE_IMAGE_FRAC, (MAX(0, temp_t1) + phi_a0) << G_TEXTURE_IMAGE_FRAC, (sp214->x) << G_TEXTURE_IMAGE_FRAC, (MAX(0, temp_t1) - (1 - D_80380B0C)) << G_TEXTURE_IMAGE_FRAC); + + // gDPLoadMultiTile((*gfx)++, &D_80380B20,) + + }//L802F677C + + // @recomp Force orthographic projection rectangles to be used for all letters as it allows them to be interpolated. + if (TRUE) { //if (D_80380AF4 != 0) { + f32 temp_f24; + f32 spD0; + f32 ix; + f32 iy; + f32 temp_f26; + f32 spC0; + + temp_f24 = (sp214->x - 1.0); + spD0 = sp214->y - 1.0; + temp_f26 = (f64)sp200 - (f32)gFramebufferWidth * 0.5; + spC0 = (f64)f28 - (f32)gFramebufferHeight * 0.5 - 0.5f; + + // @recomp Assign a unique matrix and group to each letter drawn if an ID is currently assigned. + if (cur_drawn_text_transform_id != 0) { + gSPMatrix((*gfx)++, OS_K0_TO_PHYSICAL(cur_drawn_text_mtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + if (cur_drawn_text_transform_skip_interpolation) { + gEXMatrixGroupSkipAll((*gfx)++, cur_drawn_text_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + else { + gEXMatrixGroupSimpleVerts((*gfx)++, cur_drawn_text_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + + cur_drawn_text_transform_id++; + } + + gSPVertex((*gfx)++, *vtx, 4, 0); + for (iy = 0.0f; iy < 2.0; iy += 1.0) { + for (ix = 0.0f; ix < 2.0; ix += 1.0) { + s32 s = (ix * temp_f24 * 64.0f); + (*vtx)->v.ob[0] = (s16)(s32)((f64)(temp_f26 + (temp_f24 * arg3 * ix)) * 4.0); + { + s32 t = (iy * spD0 * 64.0f); + (*vtx)->v.ob[1] = (s16)(s32)((f64)(spC0 + (spD0 * arg3 * iy)) * -4.0); + (*vtx)->v.ob[2] = -0x14; + (*vtx)->v.tc[0] = s; + (*vtx)->v.tc[1] = t; + } + (*vtx)->v.cn[3] = (iy != 0.0f) ? print_sCurrentPtr->unk6 : print_sCurrentPtr->unk4; + + (*vtx)++; + } + } + + gSP1Quadrangle((*gfx)++, 0, 1, 3, 2, 0); + + // @recomp Clear the matrix group. + if (cur_drawn_text_transform_id != 0) { + gEXPopMatrixGroup((*gfx)++, G_MTX_MODELVIEW); + } + } + else { + gSPScisTextureRectangle((*gfx)++, (s32)(sp200 * 4.0f), (s32)(f28 * 4.0f), (s32)((sp200 + sp214->x * arg3) * 4.0f), (s32)((f28 + sp214->y * arg3) * 4.0f), 0, 0, 0, (s32)(1024.0f / arg3), (s32)(1024.0f / arg3)); + } + *xPtr += sp1F8 * arg3; + } +} + +// @recomp Patched to set up an orthographic projection for each print and align them to their corresponding side on the screen. +RECOMP_PATCH void printbuffer_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) { + static f32 D_80380FA8[0x20]; + + s32 j; + f32 _x; + f32 _y; + f32 width; + + gSPDisplayList((*gfx)++, D_80369238); + + // @recomp Set up a scissor that covers the entire screen. + gEXPushScissor((*gfx)++); + gEXSetScissor((*gfx)++, G_SC_NON_INTERLACE, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_RIGHT, 0, gScissorBoxRight, 0, gScissorBoxBottom); + + // @recomp Set up an orthographic projection that will be used for all letters by default. + u32 curOrigin = G_EX_ORIGIN_NONE; + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXSetRectAlign((*gfx)++, G_EX_ORIGIN_NONE, G_EX_ORIGIN_NONE, 0, 0, 0, 0); + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + cur_drawn_text_mtx = (*mtx - 1); + + // @recomp Set up some drawing parameters that were set up when changing between rectangle and orthographic mode. + gDPPipeSync((*gfx)++); + gDPSetTexturePersp((*gfx)++, G_TP_PERSP); + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0xFF); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, TEXEL0, TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0, TEXEL0, 0, SHADE, 0); + + for (print_sCurrentPtr = print_sPrintBuffer; print_sCurrentPtr < print_sPrintBuffer + 0x20; print_sCurrentPtr++) { + if (print_sCurrentPtr->string != 0) { + // @recomp When the origin changes, set up a new viewport with the alignment specified for the print buffer. + u32 bufferIndex = print_sCurrentPtr - print_sPrintBuffer; + cur_drawn_text_transform_id = print_sPrintBufferIDs[bufferIndex]; + cur_drawn_text_transform_skip_interpolation = print_sPrintBufferSkipInterpolationFlags[bufferIndex]; + if (curOrigin != print_sPrintBufferOrigins[bufferIndex]) { + curOrigin = print_sPrintBufferOrigins[bufferIndex]; + s32 viewportOffset = (gScissorBoxTop * curOrigin * -4) / G_EX_ORIGIN_RIGHT; + gEXSetViewportAlign((*gfx)++, curOrigin, viewportOffset, 0); + gEXSetRectAlign((*gfx)++, curOrigin, curOrigin, viewportOffset, 0, viewportOffset, 0); + viewport_setRenderViewportAndOrthoMatrix(gfx, mtx); + } + + _x = (f32)print_sCurrentPtr->x; + _y = (f32)print_sCurrentPtr->y; + //toggle on string format modifiers + for (j = 0; print_sCurrentPtr->fmtString[j] != 0; j++) { + _printbuffer_draw_letter(0xFD, &_x, &_y, 1.0f, gfx, mtx, vtx); + _printbuffer_draw_letter(print_sCurrentPtr->fmtString[j], &_x, &_y, 1.0f, gfx, mtx, vtx); + } + if (D_80380B00 != 0) { + width = (strlen(print_sCurrentPtr->string) - 1) * D_80369068[D_80380AE8]; + gDPPipeSync((*gfx)++); + gDPSetPrimColor((*gfx)++, 0, 0, 0x00, 0x00, 0x00, 0x64); + gDPSetCombineMode((*gfx)++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); + gDPScisFillRectangle((*gfx)++, _x - D_80369068[D_80380AE8] / 2 - 1.0f, _y - D_80369068[D_80380AE8] / 2 - 1.0f, _x + width + D_80369068[D_80380AE8] / 2, _y + D_80369068[D_80380AE8] / 2 + 1.0f); + gDPPipeSync((*gfx)++); + + }//L802F73E8 + // @recomp Ignore the condition for not setting up these parameters while on orthographic mode. + if (D_80380AF8 == 0) { //if ((D_80380AF8 == 0) && (D_80380AF4 == 0)) { + if (D_80380AE8 != 0) { + gDPSetCombineMode((*gfx)++, G_CC_DECALRGBA, G_CC_DECALRGBA); + gDPSetPrimColor((*gfx)++, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); + } + else { + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, print_sCurrentPtr->rgba[0], print_sCurrentPtr->rgba[1], print_sCurrentPtr->rgba[2], print_sCurrentPtr->rgba[3]); + } + } + if ((D_80380AE8 == 1) && ((f64)print_sCurrentPtr->unk10 < 0.0)) { + for (j = 0; print_sCurrentPtr->string[j]; j++) { + D_80380FA8[j] = func_802F6C90(print_sCurrentPtr->string[j], &_x, &_y, -print_sCurrentPtr->unk10); + } + while (j >= 0) { + _x = D_80380FA8[j]; + _printbuffer_draw_letter(print_sCurrentPtr->string[j], &_x, &_y, -print_sCurrentPtr->unk10, gfx, mtx, vtx); + j--; + } + } + else { + for (j = 0; (print_sCurrentPtr->string[j] != 0) || (D_80380B04 != 0); j++) { + _printbuffer_draw_letter(print_sCurrentPtr->string[j], &_x, &_y, print_sCurrentPtr->unk10, gfx, mtx, vtx); + } + } + //toggle off string format modifiers + for (j = 0; print_sCurrentPtr->fmtString[j] != 0; j++) { + _printbuffer_draw_letter(0xFD, &_x, &_y, 1.0f, gfx, mtx, vtx); + _printbuffer_draw_letter(print_sCurrentPtr->fmtString[j], &_x, &_y, 1.0f, gfx, mtx, vtx); + } + _printbuffer_draw_letter(0, &_x, &_y, 1.0f, gfx, mtx, vtx); + print_sCurrentPtr->string = NULL; + } + } + + // @recomp Clear the alignment and the scissor. Also clear the assigned transform group for the letters. + gEXSetViewportAlign((*gfx)++, G_EX_ORIGIN_NONE, 0, 0); + gEXSetRectAlign((*gfx)++, G_EX_ORIGIN_NONE, G_EX_ORIGIN_NONE, 0, 0, 0, 0); + gEXPopScissor((*gfx)++); + cur_drawn_text_transform_id = 0; + + gDPPipeSync((*gfx)++); + gDPSetTexturePersp((*gfx)++, G_TP_PERSP); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + viewport_setRenderViewportAndPerspectiveMatrix(gfx, mtx); +} diff --git a/patches/transform_ids.h b/patches/transform_ids.h index 2ec72a1..7b099ba 100644 --- a/patches/transform_ids.h +++ b/patches/transform_ids.h @@ -38,13 +38,38 @@ // HUD Honeycomb: 0x00F34000 - 0x00F3400F #define HUD_HONEYCOMB_TRANSFORM_ID_START 0x00F34000 -#define HUD_HONEYCOMB_TRANSFORM_ID_COUNT 6 -// HUD score item depth rects: 0x00F34010 - 0x00F340FF -#define HUD_SCORE3_DEPTH_RECT_TRANSFORM_ID_START 0x00F34010 +// HUD Life Score: 0x00F34010 - 0x00F34017 +#define HUD_LIFESCORE_TRANSFORM_PRINT_ID_START 0x00F34010 -// HUD score items: 0x00F34100 - 0x00F3FFFF -#define HUD_SCORE3_TRANSFORM_ID_START 0x00F34100 +// HUD Life Score: 0x00F34018 - 0x00F3401F +#define HUD_LIFESCORE_TRANSFORM_ID_START 0x00F34018 + +// HUD Health Score: 0x00F34020 - 0x00F3402F +#define HUD_HEALTHSCORE_TRANSFORM_ID_START 0x00F34020 + +// HUD Air Score: 0x00F34030 - 0x00F3403F +#define HUD_AIRSCORE_TRANSFORM_ID_START 0x00F34030 + +// HUD Jinjo Score: 0x00F34040 - 0x00F3404F +#define HUD_JINJOSCORE_TRANSFORM_ID_START 0x00F34040 + +// HUD Score 2 Print: 0x00F34050 - 0x00F3414F +#define HUD_SCORE2_TRANSFORM_PRINT_ID_START 0x00F34050 +#define HUD_SCORE2_TRANSFORM_PRINT_ID_COUNT 4 + +// HUD Score 2: 0x00F34150 - 0x00F3424F +#define HUD_SCORE2_TRANSFORM_ID_START 0x00F34150 + +// HUD Score 3 Print: 0x00F34250 - 0x00F3434F +#define HUD_SCORE3_TRANSFORM_PRINT_ID_START 0x00F34250 +#define HUD_SCORE3_TRANSFORM_PRINT_ID_COUNT 4 + +// HUD score item depth rects: 0x00F34350 - 0x00F343FF +#define HUD_SCORE3_DEPTH_RECT_TRANSFORM_ID_START 0x00F34350 + +// HUD Score 3: 0x00F34400 - 0x00F3FFFF +#define HUD_SCORE3_TRANSFORM_ID_START 0x00F34400 // Lens flare: 0x00F40000 - 0x00F40FFF #define LENS_FLARE_TRANSFORM_ID_START 0x00F40000 @@ -53,9 +78,16 @@ // Snow: 0x00F41000 - 0x00F410FF #define SNOW_TRANSFORM_ID_START 0x00F41000 -// Snow: 0x00F42000 - 0x00F420FF +// Clanker: 0x00F42000 - 0x00F420FF #define CLANKER_TRANSFORM_ID_START 0x00F42000 +// HUD Totals Print: 0x00F42100 - 0x00F421FF +#define HUD_TOTALS_PRINT_TRANSFORM_ID_START 0x00F42100 + +// Zoombox Print: 0x00F42200 - 0x00F520FF +#define ZOOMBOX_PRINT_TRANSFORM_ID_START 0x00F42200 +#define ZOOMBOX_PRINT_TRANSFORM_ID_COUNT 512 + // Normal Particles: 0x01000000 - 0x01FFFFFF #define NORMAL_PARTICLE_TRANSFORM_ID_START 0x01000000 #define NORMAL_PARTICLE_ID_MAX 0x01000000