sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

renderer.c (123507B)


      1 #include <ultra64.h>
      2 #include <stdarg.h>
      3 #include <stdio.h>
      4 
      5 #include "debug_utils.h"
      6 #include "draw_objects.h"
      7 #include "dynlist_proc.h"
      8 #include "dynlists/dynlists.h"
      9 #include "gd_macros.h"
     10 #include "gd_main.h"
     11 #include "gd_math.h"
     12 #include "gd_memory.h"
     13 #include "gd_types.h"
     14 #include "macros.h"
     15 #include "objects.h"
     16 #include "renderer.h"
     17 #include "sfx.h"
     18 #include "shape_helper.h"
     19 #include "skin.h"
     20 #include "types.h"
     21 
     22 #define MAX_GD_DLS 1000
     23 #define OS_MESG_SI_COMPLETE 0x33333333
     24 
     25 #ifndef NO_SEGMENTED_MEMORY
     26 #define GD_VIRTUAL_TO_PHYSICAL(addr) ((uintptr_t)(addr) &0x0FFFFFFF)
     27 #define GD_LOWER_24(addr) ((uintptr_t)(addr) &0x00FFFFFF)
     28 #define GD_LOWER_29(addr) (((uintptr_t)(addr)) & 0x1FFFFFFF)
     29 #else
     30 #define GD_VIRTUAL_TO_PHYSICAL(addr) (addr)
     31 #define GD_LOWER_24(addr) ((uintptr_t)(addr))
     32 #define GD_LOWER_29(addr) (((uintptr_t)(addr)))
     33 #endif
     34 
     35 #define MTX_INTPART_PACK(w1, w2) (((w1) &0xFFFF0000) | (((w2) >> 16) & 0xFFFF))
     36 #define MTX_FRACPART_PACK(w1, w2) ((((w1) << 16) & 0xFFFF0000) | ((w2) &0xFFFF))
     37 #define LOOKAT_PACK(c) ((s32) MIN(((c) * (128.0)), 127.0) & 0xff)
     38 
     39 // structs
     40 struct GdDisplayList {
     41     /* Vertices */
     42     /*0x00*/ s32 curVtxIdx;
     43     /*0x04*/ s32 totalVtx;
     44     /*0x08*/ Vtx *vtx;
     45     /* Matrices */
     46     /*0x0C*/ s32 curMtxIdx;
     47     /*0x10*/ s32 totalMtx;
     48     /*0x14*/ Mtx *mtx;
     49     /* Lights */
     50     /*0x18*/ s32 curLightIdx;
     51     /*0x1C*/ s32 totalLights;
     52     /*0x20*/ Lights4 *light;
     53     /* Gfx-es */
     54     /*0x24*/ s32 curGfxIdx;
     55     /*0x28*/ s32 totalGfx;
     56     /*0x2C*/ Gfx *gfx;    // active position in DL
     57     /*0x30*/ Gfx **dlptr; // pointer to list/array of display lists for each frame?
     58                           /* Viewports */
     59     /*0x34*/ s32 curVpIdx;
     60     /*0x38*/ s32 totalVp;
     61     /*0x3C*/ Vp *vp;
     62     /* GD DL Info */
     63     /*0x40*/ u32 id;     // user specified
     64     /*0x44*/ u32 number; // count
     65     /*0x48*/ u8 filler[4];
     66     /*0x4C*/ struct GdDisplayList *parent; // not quite sure?
     67 };                                         /* sizeof = 0x50 */
     68 // accessor macros for gd dl
     69 #define DL_CURRENT_VTX(dl)   ((dl)->vtx[(dl)->curVtxIdx])
     70 #define DL_CURRENT_MTX(dl)   ((dl)->mtx[(dl)->curMtxIdx])
     71 #define DL_CURRENT_LIGHT(dl) ((dl)->light[(dl)->curLightIdx])
     72 #define DL_CURRENT_GFX(dl)   ((dl)->gfx[(dl)->curGfxIdx])
     73 #define DL_CURRENT_VP(dl)    ((dl)->vp[(dl)->curVpIdx])
     74 
     75 struct LightDirVec {
     76     s32 x, y, z;
     77 };
     78 
     79 enum DynListBankFlag { TABLE_END = -1, STD_LIST_BANK = 3 };
     80 
     81 struct DynListBankInfo {
     82     /* 0x00 */ enum DynListBankFlag flag;
     83     /* 0x04 */ struct DynList *list;
     84 };
     85 
     86 // bss
     87 #if defined(VERSION_EU) || defined(VERSION_SH) || defined(VERSION_CN)
     88 static OSMesgQueue D_801BE830; // controller msg queue
     89 static OSMesg D_801BE848[10];
     90 u8 EUpad1[0x40];
     91 static OSMesgQueue D_801BE8B0;
     92 static OSMesgQueue sGdDMAQueue; // @ 801BE8C8
     93 // static u32 unref_801be870[16];
     94 // static u32 unref_801be8e0[25];
     95 // static u32 unref_801be948[13];
     96 u8 EUpad2[0x64];
     97 static OSMesg sGdMesgBuf[1]; // @ 801BE944
     98 u8 EUpad3[0x34];
     99 static OSMesg sGdDMACompleteMsg; // msg buf for D_801BE8B0 queue
    100 static OSIoMesg sGdDMAReqMesg;
    101 static struct ObjView *D_801BE994; // store if View flag 0x40 set
    102 
    103 u8 EUpad4[0x88];
    104 #endif
    105 static OSContStatus D_801BAE60[4];
    106 static OSContPad sGdContPads[4];    // @ 801BAE70
    107 static OSContPad sPrevFrameCont[4]; // @ 801BAE88
    108 static u8 D_801BAEA0;
    109 static struct ObjGadget *sTimerGadgets[GD_NUM_TIMERS]; // @ 801BAEA8
    110 static u32 D_801BAF28;                                 // RAM addr offset?
    111 static s16 sTriangleBuf[13][8];                          // [[s16; 8]; 13]? vert indices?
    112 UNUSED static u32 unref_801bb000[3];
    113 static u8 *sMemBlockPoolBase; // @ 801BB00C
    114 static u32 sAllocMemory;      // @ 801BB010; malloc-ed bytes
    115 UNUSED static u32 unref_801bb014;
    116 static s32 D_801BB018;
    117 static s32 D_801BB01C;
    118 static void *sLoadedTextures[0x10];          // texture pointers
    119 static s32 sTextureDisplayLists[0x10];            // gd_dl indices
    120 static s16 sVtxCvrtTCBuf[2];            // @ 801BB0A0
    121 static s32 sCarGdDlNum;                 // @ 801BB0A4
    122 static struct ObjGroup *sYoshiSceneGrp; // @ 801BB0A8
    123 static s32 unusedDl801BB0AC;                  // unused DL number
    124 static struct ObjGroup *sMarioSceneGrp; // @ 801BB0B0
    125 static s32 D_801BB0B4;                  // second offset into sTriangleBuf
    126 static struct ObjGroup *sCarSceneGrp;   // @ 801BB0B8
    127 static s32 sVertexBufCount; // vtx's to load into RPD? Vtx len in GD Dl and in the lower bank (AF30)
    128 static struct ObjView *sYoshiSceneView; // @ 801BB0C0
    129 static s32 sTriangleBufCount;                  // number of triangles in sTriangleBuf
    130 static struct ObjView *sMSceneView;     // @ 801BB0C8; Mario scene view
    131 static s32 sVertexBufStartIndex;                  // Vtx start in GD Dl
    132 static struct ObjView *sCarSceneView;   // @ 801BB0D0
    133 static s32 sUpdateYoshiScene;           // @ 801BB0D4; update dl Vtx from ObjVertex?
    134 static s32 sUpdateMarioScene;           // @ 801BB0D8; update dl Vtx from ObjVertex?
    135 UNUSED static u32 unref_801bb0dc;
    136 static s32 sUpdateCarScene; // @ 801BB0E0; guess, not really used
    137 UNUSED static u32 unref_801bb0e4;
    138 static struct GdVec3f sTextDrawPos;  // position to draw text? only set in one function, never used
    139 UNUSED static u32 unref_801bb0f8[2];
    140 static Mtx sIdnMtx;           // @ 801BB100
    141 static Mat4f sInitIdnMat4;    // @ 801BB140
    142 static s8 sVtxCvrtNormBuf[3]; // @ 801BB180
    143 static s16 sAlpha;
    144 static s32 sNumLights;
    145 static struct GdColour sAmbScaleColour;       // @ 801BB190
    146 static struct GdColour sLightScaleColours[2]; // @ 801BB1A0
    147 static struct LightDirVec sLightDirections[2];
    148 static s32 sLightId;
    149 static Hilite sHilites[600];
    150 static struct GdVec3f D_801BD758;
    151 static struct GdVec3f D_801BD768; // had to migrate earlier
    152 static u32 D_801BD774;
    153 static struct GdObj *sMenuGadgets[9]; // @ 801BD778; d_obj ptr storage? menu?
    154 static struct ObjView *sDebugViews[2];  // Seems to be a list of ObjViews for displaying debug info
    155 static struct GdDisplayList *sStaticDl;     // @ 801BD7A8
    156 static struct GdDisplayList *sDynamicMainDls[2]; // @ 801BD7B0
    157 static struct GdDisplayList *sGdDlStash;    // @ 801BD7B8
    158 static struct GdDisplayList *sMHeadMainDls[2]; // @ 801BD7C0; two DLs, double buffered one per frame - seem to be basic dls that branch to actual lists?
    159 static struct GdDisplayList *sViewDls[3][2];       // I guess? 801BD7C8 -> 801BD7E0?
    160 static struct GdDisplayList *sGdDLArray[MAX_GD_DLS]; // @ 801BD7E0; indexed by dl number (gddl+0x44)
    161 static s32 sPickBufLen;                              // @ 801BE780
    162 static s32 sPickBufPosition;                         // @ 801BE784
    163 static s16 *sPickBuf;                                // @ 801BE788
    164 static LookAt D_801BE790[2];
    165 static LookAt D_801BE7D0[3];
    166 #if defined(VERSION_JP) || defined(VERSION_US)
    167 static OSMesgQueue D_801BE830; // controller msg queue
    168 static OSMesg D_801BE848[10];
    169 UNUSED static u32 unref_801be870[16];
    170 static OSMesgQueue D_801BE8B0;
    171 static OSMesgQueue sGdDMAQueue; // @ 801BE8C8
    172 UNUSED static u32 unref_801be8e0[25];
    173 static OSMesg sGdMesgBuf[1]; // @ 801BE944
    174 UNUSED static u32 unref_801be948[13];
    175 static OSMesg sGdDMACompleteMsg; // msg buf for D_801BE8B0 queue
    176 static OSIoMesg sGdDMAReqMesg;
    177 static struct ObjView *D_801BE994; // store if View flag 0x40 set
    178 #endif
    179 
    180 // data
    181 UNUSED static u32 unref_801a8670 = 0;
    182 static s32 D_801A8674 = 0;
    183 UNUSED static u32 unref_801a8678 = 0;
    184 static s32 D_801A867C = 0;
    185 static s32 D_801A8680 = 0;
    186 static f32 sTracked1FrameTime = 0.0f; // @ 801A8684
    187 static f32 sDynamicsTime = 0.0f;      // @ 801A8688
    188 static f32 sDLGenTime = 0.0f;         // @ 801A868C
    189 static f32 sRCPTime = 0.0f;           // @ 801A8690
    190 static f32 sTimeScaleFactor = 1.0f;   // @ D_801A8694
    191 static u32 sMemBlockPoolSize = 1;     // @ 801A8698
    192 static s32 sMemBlockPoolUsed = 0;     // @ 801A869C
    193 static s32 sTextureCount = 0;  // maybe?
    194 static struct GdTimer *D_801A86A4 = NULL; // timer for dlgen, dynamics, or rcp
    195 static struct GdTimer *D_801A86A8 = NULL; // timer for dlgen, dynamics, or rcp
    196 static struct GdTimer *D_801A86AC = NULL; // timer for dlgen, dynamics, or rcp
    197 s32 gGdFrameBufNum = 0;                      // @ 801A86B0
    198 UNUSED static u32 unref_801a86B4 = 0;
    199 static struct ObjShape *sHandShape = NULL; // @ 801A86B8
    200 static s32 D_801A86BC = 1;
    201 static s32 D_801A86C0 = 0; // gd_dl id for something?
    202 UNUSED static u32 unref_801a86C4 = 10;
    203 static s32 sMtxParamType = G_MTX_PROJECTION;
    204 static struct GdVec3f D_801A86CC = { 1.0f, 1.0f, 1.0f };
    205 static struct ObjView *sActiveView = NULL;  // @ 801A86D8 current view? used when drawing dl
    206 static struct ObjView *sScreenView = NULL; // @ 801A86DC
    207 static struct ObjView *D_801A86E0 = NULL;
    208 static struct ObjView *sHandView = NULL; // @ 801A86E4
    209 static struct ObjView *sMenuView = NULL; // @ 801A86E8
    210 static u32 sItemsInMenu = 0;             // @ 801A86EC
    211 static s32 sDebugViewsCount = 0;               // number of elements in the sDebugViews array
    212 static s32 sCurrDebugViewIndex = 0;             // @ 801A86F4; timing activate cool down counter?
    213 UNUSED static u32 unref_801a86F8 = 0;
    214 static struct GdDisplayList *sCurrentGdDl = NULL; // @ 801A86FC
    215 static u32 sGdDlCount = 0;                        // @ 801A8700
    216 static struct DynListBankInfo sDynLists[] = {     // @ 801A8704
    217     { STD_LIST_BANK, dynlist_test_cube },
    218     { STD_LIST_BANK, dynlist_spot_shape },
    219     { STD_LIST_BANK, dynlist_mario_master },
    220     { TABLE_END, NULL }
    221 };
    222 
    223 // textures and display list data
    224 UNUSED static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728
    225     gsSPEndDisplayList(),
    226 };
    227 
    228 ALIGNED8 static Texture gd_texture_hand_open[] = {
    229 #include "textures/intro_raw/hand_open.rgba16.inc.c"
    230 };
    231 
    232 UNUSED static Gfx gd_texture2_dummy_aligner1[] = {
    233     gsSPEndDisplayList()
    234 };
    235 
    236 ALIGNED8 static Texture gd_texture_hand_closed[] = {
    237 #include "textures/intro_raw/hand_closed.rgba16.inc.c"
    238 };
    239 
    240 ALIGNED8 static Texture gd_texture_red_star_0[] = {
    241 #include "textures/intro_raw/red_star_0.rgba16.inc.c"
    242 };
    243 
    244 ALIGNED8 static Texture gd_texture_red_star_1[] = {
    245 #include "textures/intro_raw/red_star_1.rgba16.inc.c"
    246 };
    247 
    248 ALIGNED8 static Texture gd_texture_red_star_2[] = {
    249 #include "textures/intro_raw/red_star_2.rgba16.inc.c"
    250 };
    251 
    252 ALIGNED8 static Texture gd_texture_red_star_3[] = {
    253 #include "textures/intro_raw/red_star_3.rgba16.inc.c"
    254 };
    255 
    256 ALIGNED8 static Texture gd_texture_red_star_4[] = {
    257 #include "textures/intro_raw/red_star_4.rgba16.inc.c"
    258 };
    259 
    260 ALIGNED8 static Texture gd_texture_red_star_5[] = {
    261 #include "textures/intro_raw/red_star_5.rgba16.inc.c"
    262 };
    263 
    264 ALIGNED8 static Texture gd_texture_red_star_6[] = {
    265 #include "textures/intro_raw/red_star_6.rgba16.inc.c"
    266 };
    267 
    268 ALIGNED8 static Texture gd_texture_red_star_7[] = {
    269 #include "textures/intro_raw/red_star_7.rgba16.inc.c"
    270 };
    271 
    272 ALIGNED8 static Texture gd_texture_white_star_0[] = {
    273 #include "textures/intro_raw/white_star_0.rgba16.inc.c"
    274 };
    275 
    276 ALIGNED8 static Texture gd_texture_white_star_1[] = {
    277 #include "textures/intro_raw/white_star_1.rgba16.inc.c"
    278 };
    279 
    280 ALIGNED8 static Texture gd_texture_white_star_2[] = {
    281 #include "textures/intro_raw/white_star_2.rgba16.inc.c"
    282 };
    283 
    284 ALIGNED8 static Texture gd_texture_white_star_3[] = {
    285 #include "textures/intro_raw/white_star_3.rgba16.inc.c"
    286 };
    287 
    288 ALIGNED8 static Texture gd_texture_white_star_4[] = {
    289 #include "textures/intro_raw/white_star_4.rgba16.inc.c"
    290 };
    291 
    292 ALIGNED8 static Texture gd_texture_white_star_5[] = {
    293 #include "textures/intro_raw/white_star_5.rgba16.inc.c"
    294 };
    295 
    296 ALIGNED8 static Texture gd_texture_white_star_6[] = {
    297 #include "textures/intro_raw/white_star_6.rgba16.inc.c"
    298 };
    299 
    300 ALIGNED8 static Texture gd_texture_white_star_7[] = {
    301 #include "textures/intro_raw/white_star_7.rgba16.inc.c"
    302 };
    303 
    304 static Vtx_t gd_vertex_star[] = {
    305     {{-64,   0, 0}, 0, {  0, 992}, {0x00, 0x00, 0x7F}},
    306     {{ 64,   0, 0}, 0, {992, 992}, {0x00, 0x00, 0x7F}},
    307     {{ 64, 128, 0}, 0, {992,   0}, {0x00, 0x00, 0x7F}},
    308     {{-64, 128, 0}, 0, {  0,   0}, {0x00, 0x00, 0x7F}},
    309 };
    310 
    311 //! no references to these vertices
    312 UNUSED static Vtx_t gd_unused_vertex[] = {
    313     {{16384, 0,     0}, 0, {0, 16384}, {0x00, 0x00, 0x00}},
    314     {{    0, 0, 16384}, 0, {0,     0}, {0x00, 0x00, 0x40}},
    315     {{    0, 0,     0}, 0, {0,     0}, {0x00, 0x00, 0x00}},
    316     {{    0, 0,     0}, 0, {0,     0}, {0x00, 0x00, 0x00}},
    317 };
    318 
    319 static Gfx gd_dl_star_common[] = {
    320     gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA),
    321     gsSPClearGeometryMode(G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR),
    322     gsDPSetRenderMode(G_RM_AA_ZB_TEX_EDGE, G_RM_NOOP2),
    323     gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
    324     gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_CLAMP, 5, G_TX_NOLOD, G_TX_CLAMP, 5, G_TX_NOLOD),
    325     gsDPLoadSync(),
    326     gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)),
    327     gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 5, G_TX_NOLOD, G_TX_CLAMP, 5, G_TX_NOLOD),
    328     gsDPSetTileSize(0, 0, 0, (32 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC),
    329     gsSPVertex(gd_vertex_star, 4, 0),
    330     gsSP2Triangles( 0,  1,  2, 0x0,  0,  2,  3, 0x0),
    331     gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF),
    332     gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
    333     gsDPSetRenderMode(G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2),
    334     gsSPEndDisplayList(),
    335 };
    336 
    337 static Gfx gd_dl_red_star_0[] = {
    338     gsDPPipeSync(),
    339     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_0),
    340     gsSPBranchList(gd_dl_star_common),
    341 };
    342 
    343 static Gfx gd_dl_red_star_1[] = {
    344     gsDPPipeSync(),
    345     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_1),
    346     gsSPBranchList(gd_dl_star_common),
    347 };
    348 
    349 static Gfx gd_dl_red_star_2[] = {
    350     gsDPPipeSync(),
    351     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_2),
    352     gsSPBranchList(gd_dl_star_common),
    353 };
    354 
    355 static Gfx gd_dl_red_star_3[] = {
    356     gsDPPipeSync(),
    357     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_3),
    358     gsSPBranchList(gd_dl_star_common),
    359 };
    360 
    361 static Gfx gd_dl_red_star_4[] = {
    362     gsDPPipeSync(),
    363     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_4),
    364     gsSPBranchList(gd_dl_star_common),
    365 };
    366 
    367 static Gfx gd_dl_red_star_5[] = {
    368     gsDPPipeSync(),
    369     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_5),
    370     gsSPBranchList(gd_dl_star_common),
    371 };
    372 
    373 static Gfx gd_dl_red_star_6[] = {
    374     gsDPPipeSync(),
    375     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_6),
    376     gsSPBranchList(gd_dl_star_common),
    377 };
    378 
    379 static Gfx gd_dl_red_star_7[] = {
    380     gsDPPipeSync(),
    381     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_red_star_7),
    382     gsSPBranchList(gd_dl_star_common),
    383 };
    384 
    385 static Gfx gd_dl_silver_star_0[] = {
    386     gsDPPipeSync(),
    387     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_0),
    388     gsSPBranchList(gd_dl_star_common),
    389 };
    390 
    391 static Gfx gd_dl_silver_star_1[] = {
    392     gsDPPipeSync(),
    393     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_1),
    394     gsSPBranchList(gd_dl_star_common),
    395 };
    396 
    397 static Gfx gd_dl_silver_star_2[] = {
    398     gsDPPipeSync(),
    399     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_2),
    400     gsSPBranchList(gd_dl_star_common),
    401 };
    402 
    403 static Gfx gd_dl_silver_star_3[] = {
    404     gsDPPipeSync(),
    405     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_3),
    406     gsSPBranchList(gd_dl_star_common),
    407 };
    408 
    409 static Gfx gd_dl_silver_star_4[] = {
    410     gsDPPipeSync(),
    411     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_4),
    412     gsSPBranchList(gd_dl_star_common),
    413 };
    414 
    415 static Gfx gd_dl_silver_star_5[] = {
    416     gsDPPipeSync(),
    417     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_5),
    418     gsSPBranchList(gd_dl_star_common),
    419 };
    420 
    421 static Gfx gd_dl_silver_star_6[] = {
    422     gsDPPipeSync(),
    423     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_6),
    424     gsSPBranchList(gd_dl_star_common),
    425 };
    426 
    427 static Gfx gd_dl_silver_star_7[] = {
    428     gsDPPipeSync(),
    429     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_white_star_7),
    430     gsSPBranchList(gd_dl_star_common),
    431 };
    432 
    433 static Gfx *gd_red_star_dl_array[] = {
    434     gd_dl_red_star_0,
    435     gd_dl_red_star_0,
    436     gd_dl_red_star_1,
    437     gd_dl_red_star_1,
    438     gd_dl_red_star_2,
    439     gd_dl_red_star_2,
    440     gd_dl_red_star_3,
    441     gd_dl_red_star_3,
    442     gd_dl_red_star_4,
    443     gd_dl_red_star_4,
    444     gd_dl_red_star_5,
    445     gd_dl_red_star_5,
    446     gd_dl_red_star_6,
    447     gd_dl_red_star_6,
    448     gd_dl_red_star_7,
    449     gd_dl_red_star_7,
    450 };
    451 
    452 static Gfx *gd_silver_star_dl_array[] = {
    453     gd_dl_silver_star_0,
    454     gd_dl_silver_star_0,
    455     gd_dl_silver_star_1,
    456     gd_dl_silver_star_1,
    457     gd_dl_silver_star_2,
    458     gd_dl_silver_star_2,
    459     gd_dl_silver_star_3,
    460     gd_dl_silver_star_3,
    461     gd_dl_silver_star_4,
    462     gd_dl_silver_star_4,
    463     gd_dl_silver_star_5,
    464     gd_dl_silver_star_5,
    465     gd_dl_silver_star_6,
    466     gd_dl_silver_star_6,
    467     gd_dl_silver_star_7,
    468     gd_dl_silver_star_7,
    469 };
    470 
    471 ALIGNED8 static Texture gd_texture_sparkle_0[] = {
    472 #include "textures/intro_raw/sparkle_0.rgba16.inc.c"
    473 };
    474 
    475 ALIGNED8 static Texture gd_texture_sparkle_1[] = {
    476 #include "textures/intro_raw/sparkle_1.rgba16.inc.c"
    477 };
    478 
    479 ALIGNED8 static Texture gd_texture_sparkle_2[] = {
    480 #include "textures/intro_raw/sparkle_2.rgba16.inc.c"
    481 };
    482 
    483 ALIGNED8 static Texture gd_texture_sparkle_3[] = {
    484 #include "textures/intro_raw/sparkle_3.rgba16.inc.c"
    485 };
    486 
    487 ALIGNED8 static Texture gd_texture_sparkle_4[] = {
    488 #include "textures/intro_raw/sparkle_4.rgba16.inc.c"
    489 };
    490 
    491 //! No reference to this texture. Two DL's uses the same previous texture
    492 //  instead of using this texture.
    493 UNUSED ALIGNED8 static Texture gd_texture_sparkle_5[] = {
    494 #include "textures/intro_raw/sparkle_5.rgba16.inc.c"
    495 };
    496 
    497 static Vtx_t gd_vertex_sparkle[] = {
    498     {{   -32,      0,      0}, 0, {      0,   1984}, {  0x00, 0x00, 0x7F, 0x00}},
    499     {{    32,      0,      0}, 0, {   1984,   1984}, {  0x00, 0x00, 0x7F, 0x00}},
    500     {{    32,     64,      0}, 0, {   1984,      0}, {  0x00, 0x00, 0x7F, 0x00}},
    501     {{   -32,     64,      0}, 0, {      0,      0}, {  0x00, 0x00, 0x7F, 0x00}},
    502 };
    503 
    504 static Gfx gd_dl_sparkle[] = {
    505     gsDPSetCombineMode(G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM),
    506     gsSPClearGeometryMode(G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR),
    507     gsDPSetRenderMode(G_RM_AA_ZB_TEX_EDGE, G_RM_NOOP2),
    508     gsSPTexture(0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON),
    509     gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD,
    510                 G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD),
    511     gsDPLoadSync(),
    512     gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)),
    513     gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD,
    514                 G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD),
    515     gsDPSetTileSize(0, 0, 0, (32 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC),
    516     gsSPVertex(gd_vertex_sparkle, 4, 0),
    517     gsSP2Triangles(0,  1,  2, 0x0,  0,  2,  3, 0x0),
    518     gsSPTexture(0x0001, 0x0001, 0, G_TX_RENDERTILE, G_OFF),
    519     gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
    520     gsDPSetRenderMode(G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2),
    521     gsSPEndDisplayList(),
    522 };
    523 
    524 static Gfx gd_dl_sparkle_red_color[] = {
    525     gsDPSetPrimColor(0, 0, 255, 0, 0, 255),
    526     gsSPEndDisplayList(),
    527 };
    528 
    529 static Gfx gd_dl_sparkle_white_color[] = {
    530     gsDPSetPrimColor(0, 0, 255, 255, 255, 255),
    531     gsSPEndDisplayList(),
    532 };
    533 
    534 static Gfx gd_dl_red_sparkle_0[] = {
    535     gsDPPipeSync(),
    536     gsSPDisplayList(gd_dl_sparkle_red_color),
    537     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_0),
    538     gsSPBranchList(gd_dl_sparkle),
    539 };
    540 
    541 static Gfx gd_dl_red_sparkle_1[] = {
    542     gsDPPipeSync(),
    543     gsSPDisplayList(gd_dl_sparkle_red_color),
    544     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_1),
    545     gsSPBranchList(gd_dl_sparkle),
    546 };
    547 
    548 static Gfx gd_dl_red_sparkle_2[] = {
    549     gsDPPipeSync(),
    550     gsSPDisplayList(gd_dl_sparkle_red_color),
    551     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_2),
    552     gsSPBranchList(gd_dl_sparkle),
    553 };
    554 
    555 static Gfx gd_dl_red_sparkle_3[] = {
    556     gsDPPipeSync(),
    557     gsSPDisplayList(gd_dl_sparkle_red_color),
    558     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_3),
    559     gsSPBranchList(gd_dl_sparkle),
    560 };
    561 
    562 static Gfx gd_dl_red_sparkle_4[] = {
    563     gsDPPipeSync(),
    564     gsSPDisplayList(gd_dl_sparkle_red_color),
    565     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_4),
    566     gsSPBranchList(gd_dl_sparkle),
    567 };
    568 
    569 static Gfx gd_dl_red_sparkle_4_dup[] ={
    570     gsDPPipeSync(),
    571     gsSPDisplayList(gd_dl_sparkle_red_color),
    572     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_4), // 4 again, correct texture would be 5
    573     gsSPBranchList(gd_dl_sparkle),
    574 };
    575 
    576 static Gfx gd_dl_silver_sparkle_0[] = {
    577     gsDPPipeSync(),
    578     gsSPDisplayList(gd_dl_sparkle_white_color),
    579     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_0),
    580     gsSPBranchList(gd_dl_sparkle),
    581 };
    582 
    583 static Gfx gd_dl_silver_sparkle_1[] = {
    584     gsDPPipeSync(),
    585     gsSPDisplayList(gd_dl_sparkle_white_color),
    586     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_1),
    587     gsSPBranchList(gd_dl_sparkle),
    588 };
    589 
    590 static Gfx gd_dl_silver_sparkle_2[] = {
    591     gsDPPipeSync(),
    592     gsSPDisplayList(gd_dl_sparkle_white_color),
    593     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_2),
    594     gsSPBranchList(gd_dl_sparkle),
    595 };
    596 
    597 static Gfx gd_dl_silver_sparkle_3[] = {
    598     gsDPPipeSync(),
    599     gsSPDisplayList(gd_dl_sparkle_white_color),
    600     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_3),
    601     gsSPBranchList(gd_dl_sparkle),
    602 };
    603 
    604 static Gfx gd_dl_silver_sparkle_4[] = {
    605     gsDPPipeSync(),
    606     gsSPDisplayList(gd_dl_sparkle_white_color),
    607     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_4),
    608     gsSPBranchList(gd_dl_sparkle),
    609 };
    610 
    611 static Gfx gd_dl_silver_sparkle_4_dup[] = {
    612     gsDPPipeSync(),
    613     gsSPDisplayList(gd_dl_sparkle_white_color),
    614     gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_4), // 4 again, correct texture would be 5
    615     gsSPBranchList(gd_dl_sparkle),
    616 };
    617 
    618 static Gfx *gd_red_sparkle_dl_array[] = {
    619     gd_dl_red_sparkle_4,
    620     gd_dl_red_sparkle_4,
    621     gd_dl_red_sparkle_3,
    622     gd_dl_red_sparkle_3,
    623     gd_dl_red_sparkle_2,
    624     gd_dl_red_sparkle_2,
    625     gd_dl_red_sparkle_1,
    626     gd_dl_red_sparkle_1,
    627     gd_dl_red_sparkle_0,
    628     gd_dl_red_sparkle_0,
    629     gd_dl_red_sparkle_4_dup,
    630     gd_dl_red_sparkle_4_dup,
    631 };
    632 
    633 static Gfx *gd_silver_sparkle_dl_array[] = {
    634     gd_dl_silver_sparkle_4,
    635     gd_dl_silver_sparkle_4,
    636     gd_dl_silver_sparkle_3,
    637     gd_dl_silver_sparkle_3,
    638     gd_dl_silver_sparkle_2,
    639     gd_dl_silver_sparkle_2,
    640     gd_dl_silver_sparkle_1,
    641     gd_dl_silver_sparkle_1,
    642     gd_dl_silver_sparkle_0,
    643     gd_dl_silver_sparkle_0,
    644     gd_dl_silver_sparkle_4_dup,
    645     gd_dl_silver_sparkle_4_dup,
    646 };
    647 
    648 UNUSED static Gfx gd_texture3_dummy_aligner1[] = {
    649     gsSPEndDisplayList(),
    650 };
    651 
    652 ALIGNED8 static Texture gd_texture_mario_face_shine[] = {
    653 #include "textures/intro_raw/mario_face_shine.ia8.inc.c"
    654 };
    655 
    656 static Gfx gd_dl_mario_face_shine[] = {
    657     gsSPSetGeometryMode(G_TEXTURE_GEN),
    658     gsSPTexture(0x07C0, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
    659     gsDPSetTexturePersp(G_TP_PERSP),
    660     gsDPSetTextureFilter(G_TF_BILERP),
    661     gsDPSetCombineMode(G_CC_HILITERGBA, G_CC_HILITERGBA),
    662     gsDPLoadTextureBlock(gd_texture_mario_face_shine, G_IM_FMT_IA, G_IM_SIZ_8b, 32, 32, 0,
    663                         G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 5, G_TX_NOLOD, G_TX_NOLOD),
    664     gsDPPipeSync(),
    665     gsSPEndDisplayList(),
    666 };
    667 
    668 static Gfx gd_dl_rsp_init[] = {
    669     gsSPClearGeometryMode(0xFFFFFFFF),
    670     gsSPSetGeometryMode(G_SHADING_SMOOTH | G_SHADE),
    671     gsSPEndDisplayList(),
    672 };
    673 
    674 static Gfx gd_dl_rdp_init[] = {
    675     gsDPPipeSync(),
    676     gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
    677     gsDPSetCycleType(G_CYC_1CYCLE),
    678     gsDPSetTextureLOD(G_TL_TILE),
    679     gsDPSetTextureLUT(G_TT_NONE),
    680     gsDPSetTextureDetail(G_TD_CLAMP),
    681     gsDPSetTexturePersp(G_TP_PERSP),
    682     gsDPSetTextureFilter(G_TF_BILERP),
    683     gsDPSetTextureConvert(G_TC_FILT),
    684     gsDPSetCombineKey(G_CK_NONE),
    685     gsDPSetAlphaCompare(G_AC_NONE),
    686     gsDPSetRenderMode(G_RM_OPA_SURF, G_RM_OPA_SURF2),
    687     gsDPNoOp(),
    688     gsDPSetColorDither(G_CD_MAGICSQ),
    689     gsDPPipeSync(),
    690     gsSPEndDisplayList(),
    691 };
    692 
    693 UNUSED static u32 gd_unused_pad1 = 0;
    694 
    695 float sGdPerspTimer = 1.0;
    696 
    697 UNUSED static u32 gd_unused_pad2 = 0;
    698 
    699 UNUSED static Gfx gd_texture4_dummy_aligner1[] = {
    700     gsDPPipeSync(),
    701     gsSPEndDisplayList(),
    702 };
    703 
    704 static Vtx_t gd_unused_mesh_vertex_group1[] = {
    705     {{-8,  8,  0}, 0, {  0,  0}, {  0x00, 0x00, 0x00, 0xFF}},
    706     {{ 8, -2,  0}, 0, {  0,  0}, {  0x00, 0x00, 0x00, 0xFF}},
    707     {{ 2, -8,  0}, 0, {  0,  0}, {  0x00, 0x00, 0x00, 0xFF}},
    708 };
    709 
    710 static Vtx_t gd_unused_mesh_vertex_group2[] = {
    711     {{-6,  6,  0}, 0, {  0,  0}, {  0xFF, 0xFF, 0xFF, 0xFF}},
    712     {{ 7, -3,  0}, 0, {  0,  0}, {  0xFF, 0x00, 0x00, 0xFF}},
    713     {{ 3, -7,  0}, 0, {  0,  0}, {  0xFF, 0x00, 0x00, 0xFF}},
    714 };
    715 
    716 UNUSED static Gfx gd_dl_unused_mesh[] = {
    717     gsDPPipeSync(),
    718     gsDPSetRenderMode(G_RM_OPA_SURF, G_RM_OPA_SURF2),
    719     gsSPClearGeometryMode(0xFFFFFFFF),
    720     gsSPSetGeometryMode(G_SHADING_SMOOTH | G_SHADE),
    721     gsDPPipeSync(),
    722     gsSPVertex(gd_unused_mesh_vertex_group1, 3, 0),
    723     gsSP1Triangle(0,  1,  2, 0x0),
    724     gsSPVertex(gd_unused_mesh_vertex_group2, 3, 0),
    725     gsSP1Triangle(0,  1,  2, 0x0),
    726     gsSPEndDisplayList(),
    727 };
    728 
    729 static Gfx gd_dl_sprite_start_tex_block[] = {
    730     gsDPPipeSync(),
    731     gsDPSetCycleType(G_CYC_1CYCLE),
    732     gsSPTexture(0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON),
    733     gsDPSetAlphaCompare(G_AC_THRESHOLD),
    734     gsDPSetBlendColor(0, 0, 0, 1),
    735     gsDPSetRenderMode(G_RM_AA_ZB_TEX_EDGE, G_RM_NOOP2),
    736     gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA),
    737     gsDPSetTextureFilter(G_TF_BILERP),
    738     gsDPSetTexturePersp(G_TP_NONE),
    739     gsSPEndDisplayList(),
    740 };
    741 
    742 // linker (ROM addresses)
    743 extern u8 _gd_dynlistsSegmentRomStart[];
    744 extern u8 _gd_dynlistsSegmentRomEnd[];
    745 
    746 // forward declarations
    747 u32 new_gddl_from(Gfx *, s32);
    748 void gd_setup_cursor(struct ObjGroup *);
    749 void parse_p1_controller(void);
    750 void update_cursor(void);
    751 void update_view_and_dl(struct ObjView *);
    752 static void update_render_mode(void);
    753 void gddl_is_loading_shine_dl(s32);
    754 void func_801A3370(f32, f32, f32);
    755 void gd_put_sprite(u16 *, s32, s32, s32, s32);
    756 void reset_cur_dl_indices(void);
    757 
    758 // TODO: make a gddl_num_t?
    759 
    760 u32 get_alloc_mem_amt(void) {
    761     return sAllocMemory;
    762 }
    763 
    764 /**
    765  * Returns the current time
    766  */
    767 s32 gd_get_ostime(void) {
    768     return osGetTime();
    769 }
    770 
    771 f32 get_time_scale(void) {
    772     return sTimeScaleFactor;
    773 }
    774 
    775 void dump_disp_list(void) {
    776     gd_printf("%d\n", sCurrentGdDl->id);
    777     gd_printf("Vtx=%d/%d, Mtx=%d/%d, Light=%d/%d, Gfx=%d/%d\n", sCurrentGdDl->curVtxIdx,
    778               sCurrentGdDl->totalVtx, sCurrentGdDl->curMtxIdx, sCurrentGdDl->totalMtx,
    779               sCurrentGdDl->curLightIdx, sCurrentGdDl->totalLights, sCurrentGdDl->curGfxIdx,
    780               sCurrentGdDl->totalGfx);
    781 }
    782 
    783 /**
    784  * Increments the current display list's Gfx index list and returns a pointer to the next Gfx element
    785  */
    786 static Gfx *next_gfx(void) {
    787     if (sCurrentGdDl->curGfxIdx >= sCurrentGdDl->totalGfx) {
    788         dump_disp_list();
    789         fatal_printf("Gfx list overflow");
    790     }
    791 
    792     return &sCurrentGdDl->gfx[sCurrentGdDl->curGfxIdx++];
    793 }
    794 
    795 /**
    796  * Increments the current display list's Light index list and returns a pointer to the next Light element
    797  */
    798 static Lights4 *next_light(void) {
    799     if (sCurrentGdDl->curLightIdx >= sCurrentGdDl->totalLights) {
    800         dump_disp_list();
    801         fatal_printf("Light list overflow");
    802     }
    803 
    804     return &sCurrentGdDl->light[sCurrentGdDl->curLightIdx++];
    805 }
    806 
    807 /**
    808  * Increments the current display list's matrix index list and returns a pointer to the next matrix element
    809  */
    810 static Mtx *next_mtx(void) {
    811     if (sCurrentGdDl->curMtxIdx >= sCurrentGdDl->totalMtx) {
    812         dump_disp_list();
    813         fatal_printf("Mtx list overflow");
    814     }
    815 
    816     return &sCurrentGdDl->mtx[sCurrentGdDl->curMtxIdx++];
    817 }
    818 
    819 /**
    820  * Increments the current display list's vertex index list and returns a pointer to the next vertex element
    821  */
    822 static Vtx *next_vtx(void) {
    823     if (sCurrentGdDl->curVtxIdx >= sCurrentGdDl->totalVtx) {
    824         dump_disp_list();
    825         fatal_printf("Vtx list overflow");
    826     }
    827 
    828     return &sCurrentGdDl->vtx[sCurrentGdDl->curVtxIdx++];
    829 }
    830 
    831 /**
    832  * Increments the current display list's viewport list and returns a pointer to the next viewport element
    833  */
    834 static Vp *next_vp(void) {
    835     if (sCurrentGdDl->curVpIdx >= sCurrentGdDl->totalVp) {
    836         dump_disp_list();
    837         fatal_printf("Vp list overflow");
    838     }
    839 
    840     return &sCurrentGdDl->vp[sCurrentGdDl->curVpIdx++];
    841 }
    842 
    843 /* 249AAC -> 249AEC */
    844 f64 gd_sin_d(f64 x) {
    845     return sinf(x);
    846 }
    847 
    848 /* 249AEC -> 249B2C */
    849 f64 gd_cos_d(f64 x) {
    850     return cosf(x);
    851 }
    852 
    853 /* 249B2C -> 249BA4 */
    854 f64 gd_sqrt_d(f64 x) {
    855     if (x < 1.0e-7) {
    856         return 0.0;
    857     }
    858     return sqrtf(x);
    859 }
    860 
    861 /**
    862  * Unused
    863  */
    864 f64 stub_renderer_1(UNUSED f64 x) {
    865     return 0.0;
    866 }
    867 
    868 /* 249BCC -> 24A19C */
    869 void gd_printf(const char *format, ...) {
    870     s32 i;
    871     UNUSED u8 filler1[4];
    872     char c;
    873     char f;
    874     UNUSED u8 filler2[4];
    875     char buf[0x100];
    876     char *csr = buf;
    877     char spec[8];    // specifier string
    878     UNUSED u8 filler3[4];
    879     union PrintVal val;
    880     va_list args;
    881 
    882     *csr = '\0';
    883     va_start(args, format);
    884     while ((c = *format++)) {
    885         switch (c) {
    886             case '%':
    887                 f = *format++;
    888                 i = 0;
    889                 // handle f32 precision formatter (N.Mf)
    890                 if (f >= '0' && f <= '9') {
    891                     for (i = 0; i < 3; i++) {
    892                         if ((f >= '0' && f <= '9') || f == '.') {
    893                             spec[i] = f;
    894                         } else {
    895                             break;
    896                         }
    897 
    898                         f = *format++;
    899                     }
    900                 }
    901 
    902                 spec[i] = f;
    903                 i++;
    904                 spec[i] = '\0';
    905 
    906                 switch ((c = spec[0])) {
    907                     case 'd':
    908                         val.i = va_arg(args, s32);
    909                         csr = sprint_val_withspecifiers(csr, val, spec);
    910                         break;
    911                     case 'x':
    912                         val.i = va_arg(args, u32);
    913                         csr = sprint_val_withspecifiers(csr, val, spec);
    914                         break;
    915                     case '%':
    916                         *csr = '%';
    917                         csr++;
    918                         *csr = '\0';
    919                         break;
    920                         break; // needed to match
    921                     case 'f':
    922                         val.f = (f32) va_arg(args, double);
    923                         csr = sprint_val_withspecifiers(csr, val, spec);
    924                         break;
    925                     case 's':
    926                         csr = gd_strcat(csr, va_arg(args, char *));
    927                         break;
    928                     case 'c':
    929                         //! @bug formatter 'c' uses `s32` for va_arg instead of `char`
    930                         *csr = va_arg(args, s32);
    931                         csr++;
    932                         *csr = '\0';
    933                         break;
    934                     default:
    935                         if (spec[3] == 'f') {
    936                             val.f = (f32) va_arg(args, double);
    937                             csr = sprint_val_withspecifiers(csr, val, spec);
    938                         }
    939                         break;
    940                 }
    941                 break;
    942             case '\\':
    943                 *csr = '\\';
    944                 csr++;
    945                 *csr = '\0';
    946                 break;
    947             case '\n':
    948                 *csr = '\n';
    949                 csr++;
    950                 *csr = '\0';
    951                 break;
    952             default:
    953                 *csr = c;
    954                 csr++;
    955                 *csr = '\0';
    956                 break;
    957         }
    958     }
    959     va_end(args);
    960 
    961     *csr = '\0';
    962     if (csr - buf >= ARRAY_COUNT(buf) - 1) {
    963         fatal_printf("printf too long");
    964     }
    965 }
    966 
    967 /* 24A19C -> 24A1D4 */
    968 void gd_exit(UNUSED s32 code) {
    969     gd_printf("exit\n");
    970     while (TRUE) {
    971     }
    972 }
    973 
    974 /* 24A1D4 -> 24A220; orig name: func_8019BA04 */
    975 void gd_free(void *ptr) {
    976     sAllocMemory -= gd_free_mem(ptr);
    977 }
    978 
    979 /* 24A220 -> 24A318 */
    980 void *gd_allocblock(u32 size) {
    981     void *block; // 1c
    982 
    983     size = ALIGN(size, 8);
    984     if ((sMemBlockPoolUsed + size) > sMemBlockPoolSize) {
    985         gd_printf("gd_allocblock(): Failed request: %dk (%d bytes)\n", size / 1024, size);
    986         gd_printf("gd_allocblock(): Heap usage: %dk (%d bytes) \n", sMemBlockPoolUsed / 1024,
    987                   sMemBlockPoolUsed);
    988         print_all_memtrackers();
    989         mem_stats();
    990         fatal_printf("exit");
    991     }
    992 
    993     block = sMemBlockPoolBase + sMemBlockPoolUsed;
    994     sMemBlockPoolUsed += size;
    995     return block;
    996 }
    997 
    998 /* 24A318 -> 24A3E8 */
    999 void *gd_malloc(u32 size, u8 perm) {
   1000     void *ptr; // 1c
   1001     size = ALIGN(size, 8);
   1002     ptr = gd_request_mem(size, perm);
   1003 
   1004     if (ptr == NULL) {
   1005         gd_printf("gd_malloc(): Failed request: %dk (%d bytes)\n", size / 1024, size);
   1006         gd_printf("gd_malloc(): Heap usage: %dk (%d bytes) \n", sAllocMemory / 1024, sAllocMemory);
   1007         print_all_memtrackers();
   1008         mem_stats();
   1009         return NULL;
   1010     }
   1011 
   1012     sAllocMemory += size;
   1013 
   1014     return ptr;
   1015 }
   1016 
   1017 /* 24A3E8 -> 24A420; orig name: func_8019BC18 */
   1018 void *gd_malloc_perm(u32 size) {
   1019     return gd_malloc(size, PERM_G_MEM_BLOCK);
   1020 }
   1021 
   1022 /* 24A420 -> 24A458; orig name: func_8019BC50 */
   1023 void *gd_malloc_temp(u32 size) {
   1024     return gd_malloc(size, TEMP_G_MEM_BLOCK);
   1025 }
   1026 
   1027 /* 24A458 -> 24A4A4 */
   1028 void *Unknown8019BC88(u32 size, u32 count) {
   1029     return gd_malloc_perm(size * count);
   1030 }
   1031 
   1032 /* 24A4A4 -> 24A4DC */
   1033 void *Unknown8019BCD4(u32 size) {
   1034     return gd_malloc_perm(size);
   1035 }
   1036 
   1037 /* 24A4DC -> 24A598 */
   1038 void draw_indexed_dl(s32 dlNum, s32 gfxIdx) {
   1039     Gfx *dl;
   1040 
   1041     if (gfxIdx != 0) {
   1042         dl = sGdDLArray[dlNum]->dlptr[gfxIdx - 1];  // multiple display lists (determined by frame)
   1043     } else {
   1044         dl = sGdDLArray[dlNum]->gfx;  // only one display list
   1045     }
   1046     gSPDisplayList(next_gfx(), GD_VIRTUAL_TO_PHYSICAL(dl));
   1047 }
   1048 
   1049 /* 24A598 -> 24A610; orig name: func_8019BDC8 */
   1050 void branch_cur_dl_to_num(s32 dlNum) {
   1051     Gfx *dl;
   1052     UNUSED u8 filler[8];
   1053 
   1054     dl = sGdDLArray[dlNum]->gfx;
   1055     gSPDisplayList(next_gfx(), GD_VIRTUAL_TO_PHYSICAL(dl));
   1056 }
   1057 
   1058 /**
   1059  * Unused (not called)
   1060  */
   1061 Gfx *get_dl_gfx(s32 num) {
   1062     return sGdDLArray[num]->gfx;
   1063 }
   1064 
   1065 /**
   1066  * Creates `ObjShape`s for the stars and sparkles
   1067  */
   1068 void setup_stars(void) {
   1069     gShapeRedStar = make_shape(0, "redstar");
   1070     gShapeRedStar->dlNums[0] = new_gddl_from(NULL, 0);
   1071     gShapeRedStar->dlNums[1] = gShapeRedStar->dlNums[0];
   1072     sGdDLArray[gShapeRedStar->dlNums[0]]->dlptr = gd_red_star_dl_array;
   1073     sGdDLArray[gShapeRedStar->dlNums[1]]->dlptr = gd_red_star_dl_array;
   1074 
   1075     gShapeSilverStar = make_shape(0, "silverstar");
   1076     gShapeSilverStar->dlNums[0] = new_gddl_from(NULL, 0);
   1077     gShapeSilverStar->dlNums[1] = gShapeSilverStar->dlNums[0];
   1078     sGdDLArray[gShapeSilverStar->dlNums[0]]->dlptr = gd_silver_star_dl_array;
   1079     sGdDLArray[gShapeSilverStar->dlNums[1]]->dlptr = gd_silver_star_dl_array;
   1080 
   1081     // make_shape names of the dl array they call are misnamed (swapped)
   1082     // "sspark" calls red sparkles and "rspark" calls silver sparkles
   1083     gShapeRedSpark = make_shape(0, "sspark");
   1084     gShapeRedSpark->dlNums[0] = new_gddl_from(NULL, 0);
   1085     gShapeRedSpark->dlNums[1] = gShapeRedSpark->dlNums[0];
   1086     sGdDLArray[gShapeRedSpark->dlNums[0]]->dlptr = gd_red_sparkle_dl_array;
   1087     sGdDLArray[gShapeRedSpark->dlNums[1]]->dlptr = gd_red_sparkle_dl_array;
   1088 
   1089     gShapeSilverSpark = make_shape(0, "rspark");
   1090     gShapeSilverSpark->dlNums[0] = new_gddl_from(NULL, 0);
   1091     gShapeSilverSpark->dlNums[1] = gShapeSilverSpark->dlNums[0];
   1092     sGdDLArray[gShapeSilverSpark->dlNums[0]]->dlptr = gd_silver_sparkle_dl_array;
   1093     sGdDLArray[gShapeSilverSpark->dlNums[1]]->dlptr = gd_silver_sparkle_dl_array;
   1094 }
   1095 
   1096 /* 24A8D0 -> 24AA40 */
   1097 void setup_timers(void) {
   1098     start_timer("updateshaders");
   1099     stop_timer("updateshaders");
   1100     start_timer("childpos");
   1101     stop_timer("childpos");
   1102     start_timer("netupd");
   1103     stop_timer("netupd");
   1104     start_timer("drawshape2d");
   1105     stop_timer("drawshape2d");
   1106 
   1107     start_timer("drawshape");
   1108     start_timer("drawobj");
   1109     start_timer("drawscene");
   1110     start_timer("camsearch");
   1111     start_timer("move_animators");
   1112     start_timer("move_nets");
   1113     stop_timer("move_animators");
   1114     stop_timer("move_nets");
   1115     stop_timer("drawshape");
   1116     stop_timer("drawobj");
   1117     stop_timer("drawscene");
   1118     stop_timer("camsearch");
   1119 
   1120     start_timer("move_bones");
   1121     stop_timer("move_bones");
   1122     start_timer("move_skin");
   1123     stop_timer("move_skin");
   1124     start_timer("draw1");
   1125     stop_timer("draw1");
   1126     start_timer("dynamics");
   1127     stop_timer("dynamics");
   1128 }
   1129 
   1130 /* 24AA40 -> 24AA58 */
   1131 void Unknown8019C270(u8 *buf) {
   1132     gGdStreamBuffer = buf;
   1133 }
   1134 
   1135 /* 24AA58 -> 24AAA8 */
   1136 void Unknown8019C288(s32 stickX, s32 stickY) {
   1137     struct GdControl *ctrl = &gGdCtrl; // 4
   1138 
   1139     ctrl->stickXf = (f32) stickX;
   1140     ctrl->stickYf = (f32)(stickY / 2);
   1141 }
   1142 
   1143 /* 24AAA8 -> 24AAE0; orig name: func_8019C2D8 */
   1144 void gd_add_to_heap(void *addr, u32 size) {
   1145     // TODO: is this `1` for permanence special?
   1146     gd_add_mem_to_heap(size, addr, 1);
   1147 }
   1148 
   1149 /* 24AAE0 -> 24AB7C */
   1150 void gdm_init(void *blockpool, u32 size) {
   1151     UNUSED u8 filler[4];
   1152 
   1153     imin("gdm_init");
   1154     // Align downwards?
   1155     size = (size - 8) & ~7;
   1156     // Align to next double word boundry?
   1157     blockpool = (void *) (((uintptr_t) blockpool + 8) & ~7);
   1158     sMemBlockPoolBase = blockpool;
   1159     sMemBlockPoolSize = size;
   1160     sMemBlockPoolUsed = 0;
   1161     sAllocMemory = 0;
   1162     init_mem_block_lists();
   1163     gd_reset_sfx();
   1164     imout();
   1165 }
   1166 
   1167 /**
   1168  * Initializes the Mario head demo
   1169  */
   1170 void gdm_setup(void) {
   1171     UNUSED u8 filler[4];
   1172 
   1173     imin("gdm_setup");
   1174     sYoshiSceneGrp = NULL;
   1175     sMarioSceneGrp = NULL;
   1176     sUpdateYoshiScene = FALSE;
   1177     sUpdateMarioScene = FALSE;
   1178     sCarGdDlNum = 0;
   1179     osViSetSpecialFeatures(OS_VI_GAMMA_OFF);
   1180     osCreateMesgQueue(&sGdDMAQueue, sGdMesgBuf, ARRAY_COUNT(sGdMesgBuf));
   1181     gd_init();
   1182     load_shapes2();
   1183     reset_cur_dl_indices();
   1184     setup_stars();
   1185     imout();
   1186 }
   1187 
   1188 /* 24AC18 -> 24AC2C */
   1189 void stub_renderer_2(UNUSED u32 a0) {
   1190 }
   1191 
   1192 /* 24AC2C -> 24AC80; not called; orig name: Unknown8019C45C */
   1193 void print_gdm_stats(void) {
   1194     stop_memtracker("total");
   1195     gd_printf("\ngdm stats:\n");
   1196     print_all_memtrackers();
   1197     mem_stats();
   1198     start_memtracker("total");
   1199 }
   1200 
   1201 /* 24AC80 -> 24AD14; orig name: func_8019C4B0 */
   1202 struct ObjView *make_view_withgrp(char *name, struct ObjGroup *grp) {
   1203     struct ObjView *view = make_view(name, (VIEW_DRAW | VIEW_ALLOC_ZBUF | VIEW_MOVEMENT), 1, 0, 0, 320, 240, grp);
   1204     UNUSED struct ObjGroup *viewgrp = make_group(2, grp, view);
   1205 
   1206     view->lights = gGdLightGroup;
   1207     return view;
   1208 }
   1209 
   1210 /* 24AD14 -> 24AEB8 */
   1211 void gdm_maketestdl(s32 id) {
   1212     UNUSED u8 filler[12];
   1213 
   1214     imin("gdm_maketestdl");
   1215     switch (id) {
   1216         case 0:
   1217             sYoshiSceneView = make_view_withgrp("yoshi_scene", sYoshiSceneGrp);
   1218             break;
   1219         case 1:
   1220             reset_nets_and_gadgets(sYoshiSceneGrp);
   1221             break;
   1222         case 2: // normal Mario head
   1223             if (sMarioSceneGrp == NULL) {
   1224                 load_mario_head(animate_mario_head_normal);
   1225                 sMarioSceneGrp = gMarioFaceGrp; // gMarioFaceGrp set by load_mario_head
   1226                 gd_setup_cursor(NULL);
   1227             }
   1228             sMSceneView = make_view_withgrp("mscene", sMarioSceneGrp);
   1229             break;
   1230         case 3: // game over Mario head
   1231             if (sMarioSceneGrp == NULL) {
   1232                 load_mario_head(animate_mario_head_gameover);
   1233                 sMarioSceneGrp = gMarioFaceGrp;
   1234                 gd_setup_cursor(NULL);
   1235             }
   1236             sMSceneView = make_view_withgrp("mscene", sMarioSceneGrp);
   1237             break;
   1238         case 4:
   1239             sCarSceneView = make_view_withgrp("car_scene", sCarSceneGrp);
   1240             break;
   1241         case 5:
   1242             reset_nets_and_gadgets(sCarSceneGrp);
   1243             break;
   1244         default:
   1245             fatal_printf("gdm_maketestdl(): unknown dl");
   1246     }
   1247     imout();
   1248 }
   1249 
   1250 /* 24AEB8 -> 24AED0 */
   1251 void set_time_scale(f32 factor) {
   1252     sTimeScaleFactor = factor;
   1253 }
   1254 
   1255 /* 24AED0 -> 24AF04 */
   1256 void Unknown8019C840(void) {
   1257     gd_printf("\n");
   1258     print_all_timers();
   1259 }
   1260 
   1261 /**
   1262  * Runs every frame at V-blank. Handles input and updates state.
   1263  */
   1264 void gd_vblank(void) {
   1265     gd_sfx_update();
   1266     if (sUpdateYoshiScene) {
   1267         apply_to_obj_types_in_group(OBJ_TYPE_NETS, (applyproc_t) convert_net_verts, sYoshiSceneGrp);
   1268     }
   1269     if (sUpdateMarioScene) {
   1270         apply_to_obj_types_in_group(OBJ_TYPE_NETS, (applyproc_t) convert_net_verts, sMarioSceneGrp);
   1271     }
   1272     sUpdateYoshiScene = FALSE;
   1273     sUpdateMarioScene = FALSE;
   1274     gGdFrameBufNum ^= 1;
   1275     reset_cur_dl_indices();
   1276     parse_p1_controller();
   1277     update_cursor();
   1278 }
   1279 
   1280 /**
   1281  * Copies the player1 controller data from p1cont to sGdContPads[0].
   1282  */
   1283 void gd_copy_p1_contpad(OSContPad *p1cont) {
   1284     u32 i;                                    // 24
   1285     u8 *src = (u8 *) p1cont;             // 20
   1286     u8 *dest = (u8 *) &sGdContPads[0]; // 1c
   1287 
   1288     for (i = 0; i < sizeof(OSContPad); i++) {
   1289         dest[i] = src[i];
   1290     }
   1291 
   1292     if (p1cont->button & Z_TRIG) {
   1293         print_all_timers();
   1294     }
   1295 }
   1296 
   1297 /* 24B058 -> 24B088; orig name: gd_sfx_to_play */
   1298 s32 gd_sfx_to_play(void) {
   1299     return gd_new_sfx_to_play();
   1300 }
   1301 
   1302 /* 24B088 -> 24B418 */
   1303 Gfx *gdm_gettestdl(s32 id) {
   1304     struct GdObj *dobj;
   1305     struct GdDisplayList *gddl;
   1306     UNUSED u8 filler[8];
   1307     struct GdVec3f vec;
   1308 
   1309     start_timer("dlgen");
   1310     vec.x = vec.y = vec.z = 0.0f;
   1311     gddl = NULL;
   1312 
   1313     switch (id) {
   1314         case 0:
   1315             if (sYoshiSceneView == NULL) {
   1316                 fatal_printf("gdm_gettestdl(): DL number %d undefined", id);
   1317             }
   1318             //! @bug Code treats `sYoshiSceneView` as group; not called in game though
   1319             apply_to_obj_types_in_group(OBJ_TYPE_VIEWS, (applyproc_t) update_view,
   1320                                         (struct ObjGroup *) sYoshiSceneView);
   1321             dobj = d_use_obj("yoshi_scene");
   1322             gddl = sGdDLArray[((struct ObjView *) dobj)->gdDlNum];
   1323             sUpdateYoshiScene = TRUE;
   1324             break;
   1325         case 1:
   1326             if (sYoshiSceneGrp == NULL) {
   1327                 fatal_printf("gdm_gettestdl(): DL number %d undefined", id);
   1328             }
   1329             dobj = d_use_obj("yoshi_sh_l1");
   1330             gddl = sGdDLArray[((struct ObjShape *) dobj)->dlNums[gGdFrameBufNum]];
   1331             sUpdateYoshiScene = TRUE;
   1332             break;
   1333         case GD_SCENE_REGULAR_MARIO:
   1334         case GD_SCENE_DIZZY_MARIO:
   1335             setup_timers();
   1336             update_view_and_dl(sMSceneView);
   1337             if (sHandView != NULL) {
   1338                 update_view_and_dl(sHandView);
   1339             }
   1340             sCurrentGdDl = sMHeadMainDls[gGdFrameBufNum];
   1341             gSPEndDisplayList(next_gfx());
   1342             gddl = sCurrentGdDl;
   1343             sUpdateMarioScene = TRUE;
   1344             break;
   1345         case 4:
   1346             if (sCarSceneView == NULL) {
   1347                 fatal_printf("gdm_gettestdl(): DL number %d undefined", id);
   1348             }
   1349             //! @bug Code treats `sCarSceneView` as group; not called in game though
   1350             apply_to_obj_types_in_group(OBJ_TYPE_VIEWS, (applyproc_t) update_view,
   1351                                         (struct ObjGroup *) sCarSceneView);
   1352             dobj = d_use_obj("car_scene");
   1353             gddl = sGdDLArray[((struct ObjView *) dobj)->gdDlNum];
   1354             sUpdateCarScene = TRUE;
   1355             break;
   1356         case 5:
   1357             sActiveView = sScreenView;
   1358             set_gd_mtx_parameters(G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH);
   1359             dobj = d_use_obj("testnet2");
   1360             sCarGdDlNum = gd_startdisplist(8);
   1361 
   1362             if (sCarGdDlNum == 0) {
   1363                 fatal_printf("no memory for car DL\n");
   1364             }
   1365             apply_obj_draw_fn(dobj);
   1366             gd_enddlsplist_parent();
   1367             gddl = sGdDLArray[sCarGdDlNum];
   1368             sUpdateCarScene = TRUE;
   1369             break;
   1370         default:
   1371             fatal_printf("gdm_gettestdl(): %d out of range", id);
   1372     }
   1373 
   1374     if (gddl == NULL) {
   1375         fatal_printf("no display list");
   1376     }
   1377     stop_timer("dlgen");
   1378     return (void *) osVirtualToPhysical(gddl->gfx);
   1379 }
   1380 
   1381 /* 24B418 -> 24B4CC; not called */
   1382 void gdm_getpos(s32 id, struct GdVec3f *dst) {
   1383     struct GdObj *dobj; // 1c
   1384     switch (id) {
   1385         case 5:
   1386             set_gd_mtx_parameters(G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH);
   1387             dobj = d_use_obj("testnet2");
   1388             dst->x = ((struct ObjNet *) dobj)->worldPos.x;
   1389             dst->y = ((struct ObjNet *) dobj)->worldPos.y;
   1390             dst->z = ((struct ObjNet *) dobj)->worldPos.z;
   1391             break;
   1392         default:
   1393             fatal_printf("gdm_getpos(): %d out of range", id);
   1394     }
   1395     return;
   1396 }
   1397 
   1398 /**
   1399  * Clamps the coordinates so that they are within the active view
   1400  */
   1401 static void clamp_coords_to_active_view(f32 *x, f32 *y) {
   1402     struct ObjView *view = sActiveView;
   1403 
   1404     if (*x < 0.0f) {
   1405         *x = 0.0f;
   1406     } else if (*x > view->lowerRight.x) {
   1407         *x = view->lowerRight.x;
   1408     }
   1409 
   1410     if (*y < 0.0f) {
   1411         *y = 0.0f;
   1412     } else if (*y > view->lowerRight.y) {
   1413         *y = view->lowerRight.y;
   1414     }
   1415 }
   1416 
   1417 /* 24B5A8 -> 24B5D4; orig name: func_8019CDD8 */
   1418 void fatal_no_dl_mem(void) {
   1419     fatal_printf("Out of DL mem\n");
   1420 }
   1421 
   1422 /* 24B5D4 -> 24B6AC */
   1423 struct GdDisplayList *alloc_displaylist(u32 id) {
   1424     struct GdDisplayList *gdDl;
   1425 
   1426     gdDl = gd_malloc_perm(sizeof(struct GdDisplayList));
   1427     if (gdDl == NULL) {
   1428         fatal_no_dl_mem();
   1429     }
   1430 
   1431     gdDl->number = sGdDlCount++;
   1432     if (sGdDlCount >= MAX_GD_DLS) {
   1433         fatal_printf("alloc_displaylist() too many display lists %d (MAX %d)", sGdDlCount + 1,
   1434                      MAX_GD_DLS);
   1435     }
   1436     sGdDLArray[gdDl->number] = gdDl;
   1437     gdDl->id = id;
   1438     return gdDl;
   1439 }
   1440 
   1441 /* 24B6AC -> 24B7A0; orig name: func_8019CEDC */
   1442 void cpy_remaining_gddl(struct GdDisplayList *dst, struct GdDisplayList *src) {
   1443     dst->vtx = &DL_CURRENT_VTX(src);
   1444     dst->mtx = &DL_CURRENT_MTX(src);
   1445     dst->light = &DL_CURRENT_LIGHT(src);
   1446     dst->gfx = &DL_CURRENT_GFX(src);
   1447     dst->vp = &DL_CURRENT_VP(src);
   1448     dst->totalVtx = src->totalVtx - src->curVtxIdx;
   1449     dst->totalMtx = src->totalMtx - src->curMtxIdx;
   1450     dst->totalLights = src->totalLights - src->curLightIdx;
   1451     dst->totalGfx = src->totalGfx - src->curGfxIdx;
   1452     dst->totalVp = src->totalVp - src->curVpIdx;
   1453     dst->curVtxIdx = 0;
   1454     dst->curMtxIdx = 0;
   1455     dst->curLightIdx = 0;
   1456     dst->curGfxIdx = 0;
   1457     dst->curVpIdx = 0;
   1458 }
   1459 
   1460 /* 24B7A0 -> 24B7F8; orig name: func_8019CFD0 */
   1461 struct GdDisplayList *create_child_gdl(s32 id, struct GdDisplayList *srcDl) {
   1462     struct GdDisplayList *newDl;
   1463 
   1464     newDl = alloc_displaylist(id);
   1465     newDl->parent = srcDl;
   1466     cpy_remaining_gddl(newDl, srcDl);
   1467 //! @bug No return statement, despite return value being used.
   1468 //!      Goddard lucked out that `v0` return from alloc_displaylist()
   1469 //!      is not overwriten, as that pointer is what should be returned
   1470 #ifdef AVOID_UB
   1471     return newDl;
   1472 #endif
   1473 }
   1474 
   1475 /* 24B7F8 -> 24BA48; orig name: func_8019D028 */
   1476 struct GdDisplayList *new_gd_dl(s32 id, s32 gfxs, s32 verts, s32 mtxs, s32 lights, s32 vps) {
   1477     struct GdDisplayList *dl; // 24
   1478 
   1479     dl = alloc_displaylist(id);
   1480     dl->parent = NULL;
   1481     if (verts == 0) {
   1482         verts = 1;
   1483     }
   1484     dl->curVtxIdx = 0;
   1485     dl->totalVtx = verts;
   1486     if ((dl->vtx = gd_malloc_perm(verts * sizeof(Vtx))) == NULL) {
   1487         fatal_no_dl_mem();
   1488     }
   1489 
   1490     if (mtxs == 0) {
   1491         mtxs = 1;
   1492     }
   1493     dl->curMtxIdx = 0;
   1494     dl->totalMtx = mtxs;
   1495     if ((dl->mtx = gd_malloc_perm(mtxs * sizeof(Mtx))) == NULL) {
   1496         fatal_no_dl_mem();
   1497     }
   1498 
   1499     if (lights == 0) {
   1500         lights = 1;
   1501     }
   1502     dl->curLightIdx = 0;
   1503     dl->totalLights = lights;
   1504     if ((dl->light = gd_malloc_perm(lights * sizeof(Lights4))) == NULL) {
   1505         fatal_no_dl_mem();
   1506     }
   1507 
   1508     if (gfxs == 0) {
   1509         gfxs = 1;
   1510     }
   1511     dl->curGfxIdx = 0;
   1512     dl->totalGfx = gfxs;
   1513     if ((dl->gfx = gd_malloc_perm(gfxs * sizeof(Gfx))) == NULL) {
   1514         fatal_no_dl_mem();
   1515     }
   1516 
   1517     if (vps == 0) {
   1518         vps = 1;
   1519     }
   1520     dl->curVpIdx = 0;
   1521     dl->totalVp = vps;
   1522     if ((dl->vp = gd_malloc_perm(vps * sizeof(Vp))) == NULL) {
   1523         fatal_no_dl_mem();
   1524     }
   1525 
   1526     dl->dlptr = NULL;
   1527     return dl;
   1528 }
   1529 
   1530 /* 24BA48 -> 24BABC; not called */
   1531 void gd_rsp_init(void) {
   1532     gSPDisplayList(next_gfx(), osVirtualToPhysical(&gd_dl_rsp_init));
   1533     gDPPipeSync(next_gfx());
   1534 }
   1535 
   1536 /* 24BABC -> 24BB30; not called */
   1537 void gd_rdp_init(void) {
   1538     gSPDisplayList(next_gfx(), osVirtualToPhysical(&gd_dl_rdp_init));
   1539     gDPPipeSync(next_gfx());
   1540 }
   1541 
   1542 /* 24BB30 -> 24BED8; orig name: func_8019D360 */
   1543 void gd_draw_rect(f32 ulx, f32 uly, f32 lrx, f32 lry) {
   1544     clamp_coords_to_active_view(&ulx, &uly);
   1545     clamp_coords_to_active_view(&lrx, &lry);
   1546 
   1547     if (lrx > ulx && lry > uly) {
   1548         gDPFillRectangle(next_gfx(), (u32)(sActiveView->upperLeft.x + ulx),
   1549                          (u32)(uly + sActiveView->upperLeft.y), (u32)(sActiveView->upperLeft.x + lrx),
   1550                          (u32)(lry + sActiveView->upperLeft.y));
   1551     }
   1552 
   1553     gDPPipeSync(next_gfx());
   1554     gDPSetCycleType(next_gfx(), G_CYC_1CYCLE);
   1555     gDPSetRenderMode(next_gfx(), G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2);
   1556 }
   1557 
   1558 /* 24BED8 -> 24CAC8; orig name: func_8019D708 */
   1559 void gd_draw_border_rect(f32 ulx, f32 uly, f32 lrx, f32 lry) {
   1560     clamp_coords_to_active_view(&ulx, &uly);
   1561     clamp_coords_to_active_view(&lrx, &lry);
   1562 
   1563     if (lrx > ulx && lry > uly) {
   1564         gDPFillRectangle(
   1565             next_gfx(), (u32)(sActiveView->upperLeft.x + ulx), (u32)(uly + sActiveView->upperLeft.y),
   1566             (u32)(sActiveView->upperLeft.x + ulx + 5.0f), (u32)(lry + sActiveView->upperLeft.y));
   1567         gDPFillRectangle(next_gfx(), (u32)(sActiveView->upperLeft.x + lrx - 5.0f),
   1568                          (u32)(uly + sActiveView->upperLeft.y), (u32)(sActiveView->upperLeft.x + lrx),
   1569                          (u32)(lry + sActiveView->upperLeft.y));
   1570         gDPFillRectangle(next_gfx(), (u32)(sActiveView->upperLeft.x + ulx),
   1571                          (u32)(uly + sActiveView->upperLeft.y), (u32)(sActiveView->upperLeft.x + lrx),
   1572                          (u32)(uly + sActiveView->upperLeft.y + 5.0f));
   1573         gDPFillRectangle(next_gfx(), (u32)(sActiveView->upperLeft.x + ulx),
   1574                          (u32)(lry + sActiveView->upperLeft.y - 5.0f),
   1575                          (u32)(sActiveView->upperLeft.x + lrx), (u32)(lry + sActiveView->upperLeft.y));
   1576     }
   1577 
   1578     gDPPipeSync(next_gfx());
   1579     gDPSetCycleType(next_gfx(), G_CYC_1CYCLE);
   1580     gDPSetRenderMode(next_gfx(), G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2);
   1581 }
   1582 
   1583 /* 24CAC8 -> 24CDB4; orig name: func_8019E2F8 */
   1584 void gd_dl_set_fill(struct GdColour *colour) {
   1585     u8 r, g, b;
   1586 
   1587     r = colour->r * 255.0f;
   1588     g = colour->g * 255.0f;
   1589     b = colour->b * 255.0f;
   1590 
   1591     gDPPipeSync(next_gfx());
   1592     gDPSetCycleType(next_gfx(), G_CYC_FILL);
   1593     gDPSetRenderMode(next_gfx(), G_RM_OPA_SURF, G_RM_OPA_SURF2);
   1594     gDPSetFillColor(next_gfx(), GPACK_RGBA5551(r, g, b, 1) << 16 | GPACK_RGBA5551(r, g, b, 1));
   1595 }
   1596 
   1597 /* 24CDB4 -> 24CE10; orig name: func_8019E5E4 */
   1598 void gd_dl_set_z_buffer_area(void) {
   1599     gDPSetDepthImage(next_gfx(), GD_LOWER_24(sActiveView->parent->zbuf));
   1600 }
   1601 
   1602 /* 24CE10 -> 24CF2C; orig name: func_8019E640 */
   1603 void gd_set_color_fb(void) {
   1604     gDPSetColorImage(next_gfx(), G_IM_FMT_RGBA, G_IM_SIZ_16b, sActiveView->parent->lowerRight.x,
   1605                      GD_LOWER_24(sActiveView->parent->colourBufs[gGdFrameBufNum]));
   1606 }
   1607 
   1608 /* 24CF2C -> 24CFCC; orig name: func_8019E75C */
   1609 void reset_cur_dl_indices(void) {
   1610     sMHeadMainDls[gGdFrameBufNum]->curGfxIdx = 0;
   1611     sCurrentGdDl = sDynamicMainDls[gGdFrameBufNum];
   1612     sCurrentGdDl->curVtxIdx = 0;
   1613     sCurrentGdDl->curMtxIdx = 0;
   1614     sCurrentGdDl->curLightIdx = 0;
   1615     sCurrentGdDl->curGfxIdx = 0;
   1616     sCurrentGdDl->curVpIdx = 0;
   1617 }
   1618 
   1619 /* 24CFCC -> 24D044; orig name: func_8019E7FC */
   1620 void begin_gddl(s32 num) {
   1621     sCurrentGdDl = sGdDLArray[num];
   1622     sCurrentGdDl->curVtxIdx = 0;
   1623     sCurrentGdDl->curMtxIdx = 0;
   1624     sCurrentGdDl->curLightIdx = 0;
   1625     sCurrentGdDl->curGfxIdx = 0;
   1626     sCurrentGdDl->curVpIdx = 0;
   1627 }
   1628 
   1629 /* 24D044 -> 24D064; orig name: func_8019E874 */
   1630 void stash_current_gddl(void) {
   1631     sGdDlStash = sCurrentGdDl;
   1632 }
   1633 
   1634 /* 24D064 -> 24D084; orig name: func_8019E894 */
   1635 void pop_gddl_stash(void) {
   1636     sCurrentGdDl = sGdDlStash;
   1637 }
   1638 
   1639 /* 24D084 -> 24D1D4 */
   1640 s32 gd_startdisplist(s32 memarea) {
   1641     D_801BB018 = 0;
   1642     D_801BB01C = 1;
   1643 
   1644     switch (memarea) {
   1645         case 7:  // Create new display list as a child of sStaticDl
   1646             sCurrentGdDl = create_child_gdl(0, sStaticDl);
   1647             break;
   1648         case 8:  // Use the active view's display list
   1649             if (sActiveView->id > 2) {
   1650                 fatal_printf("gd_startdisplist(): Too many views to display");
   1651             }
   1652 
   1653             sCurrentGdDl = sViewDls[sActiveView->id][gGdFrameBufNum];
   1654             cpy_remaining_gddl(sCurrentGdDl, sCurrentGdDl->parent);
   1655             break;
   1656         default:
   1657             fatal_printf("gd_startdisplist(): Unknown memory area");
   1658             break;
   1659     }
   1660     gDPPipeSync(next_gfx());
   1661 
   1662     return sCurrentGdDl->number;
   1663 }
   1664 
   1665 /* 24D1D4 -> 24D23C */
   1666 void gd_enddlsplist(void) {
   1667     gDPPipeSync(next_gfx());
   1668     gSPEndDisplayList(next_gfx());
   1669 }
   1670 
   1671 /* 24D23C -> 24D39C; orig name: func_8019EA6C */
   1672 s32 gd_enddlsplist_parent(void) {
   1673     s32 curDlIdx = 0; // 24
   1674 
   1675     gDPPipeSync(next_gfx());
   1676     gSPEndDisplayList(next_gfx());
   1677     if (sCurrentGdDl->parent != NULL) {
   1678         sCurrentGdDl->parent->curVtxIdx = (sCurrentGdDl->parent->curVtxIdx + sCurrentGdDl->curVtxIdx);
   1679         sCurrentGdDl->parent->curMtxIdx = (sCurrentGdDl->parent->curMtxIdx + sCurrentGdDl->curMtxIdx);
   1680         sCurrentGdDl->parent->curLightIdx =
   1681             (sCurrentGdDl->parent->curLightIdx + sCurrentGdDl->curLightIdx);
   1682         sCurrentGdDl->parent->curGfxIdx = (sCurrentGdDl->parent->curGfxIdx + sCurrentGdDl->curGfxIdx);
   1683         sCurrentGdDl->parent->curVpIdx = (sCurrentGdDl->parent->curVpIdx + sCurrentGdDl->curVpIdx);
   1684     }
   1685     curDlIdx = sCurrentGdDl->curGfxIdx;
   1686     return curDlIdx;
   1687 }
   1688 
   1689 /* 24D39C -> 24D3D8 */
   1690 void Unknown8019EBCC(s32 num, uintptr_t gfxptr) {
   1691     sGdDLArray[num]->gfx = (Gfx *) (GD_LOWER_24(gfxptr) + D_801BAF28);
   1692 }
   1693 
   1694 /* 24D3D8 -> 24D458; orig name: func_8019EC08 */
   1695 u32 new_gddl_from(Gfx *dl, UNUSED s32 arg1) {
   1696     struct GdDisplayList *gddl;
   1697 
   1698     gddl = new_gd_dl(0, 0, 0, 0, 0, 0);
   1699     gddl->gfx = (Gfx *) (GD_LOWER_24((uintptr_t) dl) + D_801BAF28);
   1700     return gddl->number;
   1701 }
   1702 
   1703 /* 24D458 -> 24D4C4 */
   1704 u32 Unknown8019EC88(Gfx *dl, UNUSED s32 arg1) {
   1705     struct GdDisplayList *gddl;
   1706 
   1707     gddl = new_gd_dl(0, 0, 0, 0, 0, 0);
   1708     gddl->gfx = dl;
   1709     return gddl->number;
   1710 }
   1711 
   1712 /* 24D4C4 -> 24D63C; orig name: func_8019ECF4 */
   1713 void mat4_to_mtx(Mat4f *src, Mtx *dst) {
   1714 #ifndef GBI_FLOATS
   1715     s32 i; // 14
   1716     s32 j; // 10
   1717     s32 w1;
   1718     s32 w2;
   1719     s32 *mtxInt = (s32 *) dst->m[0]; // s32 part
   1720     s32 *mtxFrc = (s32 *) dst->m[2]; // frac part
   1721 
   1722     for (i = 0; i < 4; i++) {
   1723         for (j = 0; j < 2; j++) {
   1724             w1 = (s32)((*src)[i][j * 2] * 65536.0f);
   1725             w2 = (s32)((*src)[i][j * 2 + 1] * 65536.0f);
   1726             *mtxInt = MTX_INTPART_PACK(w1, w2);
   1727             mtxInt++;
   1728             *mtxFrc = MTX_FRACPART_PACK(w1, w2);
   1729             mtxFrc++;
   1730         }
   1731     }
   1732 #else
   1733     guMtxF2L(*src, dst);
   1734 #endif
   1735 }
   1736 
   1737 /**
   1738  * Adds a display list operation that multiplies the current matrix with `mtx`.
   1739  */
   1740 void gd_dl_mul_matrix(Mat4f *mtx) {
   1741     mat4_to_mtx(mtx, &DL_CURRENT_MTX(sCurrentGdDl));
   1742     gSPMatrix(next_gfx(), osVirtualToPhysical(&DL_CURRENT_MTX(sCurrentGdDl)), sMtxParamType | G_MTX_MUL | G_MTX_NOPUSH);
   1743     next_mtx();
   1744 }
   1745 
   1746 /**
   1747  * Adds a display list operation that replaces the current matrix with `mtx`.
   1748  */
   1749 void gd_dl_load_matrix(Mat4f *mtx) {
   1750     mat4_to_mtx(mtx, &DL_CURRENT_MTX(sCurrentGdDl));
   1751     gSPMatrix(next_gfx(), osVirtualToPhysical(&DL_CURRENT_MTX(sCurrentGdDl)),
   1752               sMtxParamType | G_MTX_LOAD | G_MTX_NOPUSH);
   1753     next_mtx();
   1754 }
   1755 
   1756 /**
   1757  * Adds a display list operation that replaces the current matrix with the
   1758  * identity matrix.
   1759  */
   1760 void gd_dl_load_identity_matrix(void) {
   1761     gSPMatrix(next_gfx(), osVirtualToPhysical(&sIdnMtx), sMtxParamType | G_MTX_LOAD | G_MTX_NOPUSH);
   1762 }
   1763 
   1764 /**
   1765  * Adds a display list operation that pushes the current matrix onto the matrix
   1766  * stack.
   1767  */
   1768 void gd_dl_push_matrix(void) {
   1769     gSPMatrix(next_gfx(), osVirtualToPhysical(&sIdnMtx), sMtxParamType | G_MTX_MUL | G_MTX_PUSH);
   1770 }
   1771 
   1772 /**
   1773  * Adds a display list operation that pops a matrix from the matrix stack.
   1774  */
   1775 void gd_dl_pop_matrix(void) {
   1776     gSPPopMatrix(next_gfx(), sMtxParamType);
   1777 }
   1778 
   1779 /**
   1780  * Adds a display list operation that translates the current matrix by `x`, `y`, and `z`.
   1781  */
   1782 void gd_dl_mul_trans_matrix(f32 x, f32 y, f32 z) {
   1783     guTranslate(&DL_CURRENT_MTX(sCurrentGdDl), x, y, z);
   1784     gSPMatrix(next_gfx(), osVirtualToPhysical(&DL_CURRENT_MTX(sCurrentGdDl)), sMtxParamType | G_MTX_MUL | G_MTX_NOPUSH);
   1785     next_mtx();
   1786 }
   1787 
   1788 /**
   1789  * Adds a display list operation that loads a translation matrix.
   1790  */
   1791 void gd_dl_load_trans_matrix(f32 x, f32 y, f32 z) {
   1792     guTranslate(&DL_CURRENT_MTX(sCurrentGdDl), x, y, z);
   1793     gSPMatrix(next_gfx(), osVirtualToPhysical(&DL_CURRENT_MTX(sCurrentGdDl)),
   1794               sMtxParamType | G_MTX_LOAD | G_MTX_NOPUSH);
   1795     next_mtx();
   1796 }
   1797 
   1798 /**
   1799  * Adds a display list operation that scales the current matrix by `x`, `y`, and `z`.
   1800  */
   1801 void gd_dl_scale(f32 x, f32 y, f32 z) {
   1802     Mat4f mtx;
   1803     struct GdVec3f vec;
   1804 
   1805     vec.x = x;
   1806     vec.y = y;
   1807     vec.z = z;
   1808     gd_set_identity_mat4(&mtx);
   1809     gd_scale_mat4f_by_vec3f(&mtx, &vec);
   1810     gd_dl_mul_matrix(&mtx);
   1811 }
   1812 
   1813 /* 24DA94 -> 24DAE8 */
   1814 void func_8019F2C4(f32 arg0, s8 arg1) {
   1815     Mat4f mtx; // 18
   1816 
   1817     gd_set_identity_mat4(&mtx);
   1818     gd_absrot_mat4(&mtx, arg1 - 120, -arg0);
   1819     gd_dl_mul_matrix(&mtx);
   1820 }
   1821 
   1822 /* 24DAE8 -> 24E1A8 */
   1823 void gd_dl_lookat(struct ObjCamera *cam, f32 arg1, f32 arg2, f32 arg3, f32 arg4, f32 arg5, f32 arg6, f32 arg7) {
   1824     LookAt *lookat;
   1825 
   1826     arg7 *= RAD_PER_DEG;
   1827 
   1828     gd_mat4f_lookat(&cam->unkE8, arg1, arg2, arg3, arg4, arg5, arg6, gd_sin_d(arg7), gd_cos_d(arg7),
   1829                   0.0f);
   1830 
   1831     mat4_to_mtx(&cam->unkE8, &DL_CURRENT_MTX(sCurrentGdDl));
   1832     gSPMatrix(next_gfx(), osVirtualToPhysical(&DL_CURRENT_MTX(sCurrentGdDl)),
   1833             G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH);
   1834 
   1835     /*  col           colc          dir
   1836         0  1  2   3   4  5  6   7   8  9  10  11
   1837     { { 0, 0, 0}, _, {0, 0, 0}, _, {0, 0, 0}, _}
   1838        16 17 18  19  20 21  22 23  24 25  26  27
   1839     { { 0, 0, 0}, _, {0, 0, 0}, _, {0, 0, 0}, _}
   1840     */
   1841     lookat = &D_801BE7D0[gGdFrameBufNum];
   1842 
   1843     lookat->l[0].l.dir[0] = LOOKAT_PACK(cam->unkE8[0][0]);
   1844     lookat->l[0].l.dir[1] = LOOKAT_PACK(cam->unkE8[1][0]);
   1845     lookat->l[0].l.dir[2] = LOOKAT_PACK(cam->unkE8[2][0]);
   1846 
   1847     lookat->l[1].l.dir[0] = LOOKAT_PACK(cam->unkE8[0][1]);
   1848     lookat->l[1].l.dir[1] = LOOKAT_PACK(cam->unkE8[1][1]);
   1849     lookat->l[1].l.dir[2] = LOOKAT_PACK(cam->unkE8[2][1]);
   1850 
   1851     lookat->l[0].l.col[0] = 0;
   1852     lookat->l[0].l.col[1] = 0;
   1853     lookat->l[0].l.col[2] = 0;
   1854     lookat->l[0].l.pad1 = 0;
   1855     lookat->l[0].l.colc[0] = 0;
   1856     lookat->l[0].l.colc[1] = 0;
   1857     lookat->l[0].l.colc[2] = 0;
   1858     lookat->l[0].l.pad2 = 0;
   1859     lookat->l[1].l.col[0] = 0;
   1860     lookat->l[1].l.col[1] = 0x80;
   1861     lookat->l[1].l.col[2] = 0;
   1862     lookat->l[1].l.pad1 = 0;
   1863     lookat->l[1].l.colc[0] = 0;
   1864     lookat->l[1].l.colc[1] = 0x80;
   1865     lookat->l[1].l.colc[2] = 0;
   1866     lookat->l[1].l.pad2 = 0;
   1867 
   1868     lookat = &D_801BE790[0];
   1869     lookat->l[0].l.dir[0] = 1;
   1870     lookat->l[0].l.dir[1] = 0;
   1871     lookat->l[0].l.dir[2] = 0;
   1872 
   1873     lookat->l[1].l.dir[0] = 0;
   1874     lookat->l[1].l.dir[1] = 1;
   1875     lookat->l[1].l.dir[2] = 0;
   1876 
   1877     lookat->l[0].l.col[0] = 0;
   1878     lookat->l[0].l.col[1] = 0;
   1879     lookat->l[0].l.col[2] = 0;
   1880     lookat->l[0].l.pad1 = 0;
   1881     lookat->l[0].l.colc[0] = 0;
   1882     lookat->l[0].l.colc[1] = 0;
   1883     lookat->l[0].l.colc[2] = 0;
   1884     lookat->l[0].l.pad2 = 0;
   1885     lookat->l[1].l.col[0] = 0;
   1886     lookat->l[1].l.col[1] = 0x80;
   1887     lookat->l[1].l.col[2] = 0;
   1888     lookat->l[1].l.pad1 = 0;
   1889     lookat->l[1].l.colc[0] = 0;
   1890     lookat->l[1].l.colc[1] = 0x80;
   1891     lookat->l[1].l.colc[2] = 0;
   1892     lookat->l[1].l.pad2 = 0;
   1893 
   1894     gSPLookAt(next_gfx(), osVirtualToPhysical(&D_801BE7D0[gGdFrameBufNum]));
   1895     next_mtx();
   1896 }
   1897 
   1898 /* 24E1A8 -> 24E230; orig name: func_8019F9D8 */
   1899 void check_tri_display(s32 vtxcount) {
   1900     D_801A86C0 = sCurrentGdDl->curVtxIdx;
   1901     D_801BB0B4 = 0;
   1902     if (vtxcount != 3) {
   1903         fatal_printf("cant display no tris\n");
   1904     }
   1905     if (D_801BB018 != 0 || D_801BB01C != 0) {
   1906         ;
   1907     }
   1908 }
   1909 
   1910 /**
   1911  * Adds a vertex to the current display list. Returns a pointer to the vertex if
   1912  * it is new, or NULL if the vertex already exists.
   1913  */
   1914 Vtx *gd_dl_make_vertex(f32 x, f32 y, f32 z, f32 alpha) {
   1915     Vtx *vtx = NULL;
   1916     s32 i;
   1917 
   1918     // Add the vertex index to the buffer if it doesn't already exist
   1919     for (i = sVertexBufStartIndex; i < (sVertexBufStartIndex + sVertexBufCount); i++) {
   1920         // the ifs need to be separate to match...
   1921         if (sCurrentGdDl->vtx[i].n.ob[0] == (s16) x) {
   1922             if (sCurrentGdDl->vtx[i].n.ob[1] == (s16) y) {
   1923                 if (sCurrentGdDl->vtx[i].n.ob[2] == (s16) z) {
   1924                     sTriangleBuf[sTriangleBufCount][D_801BB0B4++] = (s16) i;
   1925                     return NULL;
   1926                 }
   1927             }
   1928         }
   1929     }
   1930 
   1931     sVertexBufCount++;
   1932     sTriangleBuf[sTriangleBufCount][D_801BB0B4++] = (s16) sCurrentGdDl->curVtxIdx;
   1933 
   1934     DL_CURRENT_VTX(sCurrentGdDl).n.ob[0] = (s16) x;
   1935     DL_CURRENT_VTX(sCurrentGdDl).n.ob[1] = (s16) y;
   1936     DL_CURRENT_VTX(sCurrentGdDl).n.ob[2] = (s16) z;
   1937     DL_CURRENT_VTX(sCurrentGdDl).n.flag = 0;
   1938     DL_CURRENT_VTX(sCurrentGdDl).n.tc[0] = sVtxCvrtTCBuf[0];
   1939     DL_CURRENT_VTX(sCurrentGdDl).n.tc[1] = sVtxCvrtTCBuf[1];
   1940     DL_CURRENT_VTX(sCurrentGdDl).n.n[0] = sVtxCvrtNormBuf[0];
   1941     DL_CURRENT_VTX(sCurrentGdDl).n.n[1] = sVtxCvrtNormBuf[1];
   1942     DL_CURRENT_VTX(sCurrentGdDl).n.n[2] = sVtxCvrtNormBuf[2];
   1943     DL_CURRENT_VTX(sCurrentGdDl).n.a = (u8)(alpha * 255.0f);
   1944 
   1945     vtx = &DL_CURRENT_VTX(sCurrentGdDl);
   1946     next_vtx();
   1947     return vtx;
   1948 }
   1949 
   1950 /* 24E6C0 -> 24E724 */
   1951 void func_8019FEF0(void) {
   1952     sTriangleBufCount++;
   1953     if (sVertexBufCount >= 12) {
   1954         gd_dl_flush_vertices();
   1955         func_801A0038();
   1956     }
   1957     D_801BB018 = 0;
   1958 }
   1959 
   1960 /**
   1961  * Adds a triange to the current display list.
   1962  */
   1963 void gd_dl_make_triangle(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2, f32 x3, f32 y3, f32 z3) {
   1964     Vtx *vtx;
   1965 
   1966     vtx = &DL_CURRENT_VTX(sCurrentGdDl);
   1967     gd_dl_make_vertex(x1, y1, z1, 1.0f);
   1968     gd_dl_make_vertex(x2, y2, z2, 1.0f);
   1969     gd_dl_make_vertex(x3, y3, z3, 1.0f);
   1970 
   1971     gSPVertex(next_gfx(), osVirtualToPhysical(vtx), 3, 0);
   1972     gSP1Triangle(next_gfx(), 0, 1, 2, 0);
   1973 }
   1974 
   1975 /* 24E808 -> 24E840 */
   1976 void func_801A0038(void) {
   1977     sVertexBufCount = 0;
   1978     sTriangleBufCount = 0;
   1979     sVertexBufStartIndex = sCurrentGdDl->curVtxIdx;
   1980 }
   1981 
   1982 /* 24E840 -> 24E9BC */
   1983 void gd_dl_flush_vertices(void) {
   1984     UNUSED u8 filler[4];
   1985     s32 i;
   1986     UNUSED s32 startvtx = sVertexBufStartIndex;
   1987 
   1988     if (sVertexBufCount != 0) {
   1989         // load vertex data
   1990         gSPVertex(next_gfx(), osVirtualToPhysical(&sCurrentGdDl->vtx[sVertexBufStartIndex]), sVertexBufCount, 0);
   1991         // load triangle data
   1992         for (i = 0; i < sTriangleBufCount; i++) {
   1993             gSP1Triangle(next_gfx(),
   1994                 sTriangleBuf[i][0] - sVertexBufStartIndex,
   1995                 sTriangleBuf[i][1] - sVertexBufStartIndex,
   1996                 sTriangleBuf[i][2] - sVertexBufStartIndex,
   1997                 0);
   1998         }
   1999     }
   2000     func_801A0038();
   2001 }
   2002 
   2003 /**
   2004  * Unused - called by func_801A520C
   2005  */
   2006 static void func_801A01EC(void) {
   2007     if (D_801BE8B0.validCount >= D_801BE8B0.msgCount) {
   2008         osRecvMesg(&D_801BE8B0, &sGdDMACompleteMsg, OS_MESG_BLOCK);
   2009     }
   2010     osRecvMesg(&D_801BE8B0, &sGdDMACompleteMsg, OS_MESG_BLOCK);
   2011 }
   2012 
   2013 /**
   2014  * Unused - called by func_801A520C
   2015  */
   2016 static void func_801A025C(void) {
   2017     gGdFrameBufNum ^= 1;
   2018     osViSwapBuffer(sScreenView->parent->colourBufs[gGdFrameBufNum]);
   2019 }
   2020 
   2021 /* 24EA88 -> 24EAF4 */
   2022 void set_render_alpha(f32 alpha) {
   2023     sAlpha = alpha * 255.0f;
   2024     update_render_mode();
   2025 }
   2026 
   2027 /* 24EAF4 -> 24EB0C */
   2028 // light id?
   2029 void set_light_id(s32 index) {
   2030     sLightId = index;
   2031 }
   2032 
   2033 /* 24EB0C -> 24EB24; orig name: func_801A033C */
   2034 void set_light_num(s32 n) {
   2035     sNumLights = n;
   2036 }
   2037 
   2038 /* 24EB24 -> 24EC18 */
   2039 s32 create_mtl_gddl(UNUSED s32 mtlType) {
   2040     s32 dlnum;            // 24
   2041     struct GdColour blue; // 18
   2042 
   2043     blue.r = 0.0f;
   2044     blue.g = 0.0f;
   2045     blue.b = 1.0f;
   2046     dlnum = gd_startdisplist(7);
   2047     gd_dl_material_lighting(dlnum, &blue, GD_MTL_TEX_OFF);
   2048     gd_enddlsplist_parent();
   2049     sCurrentGdDl->totalVtx = sCurrentGdDl->curVtxIdx;
   2050     sCurrentGdDl->totalMtx = sCurrentGdDl->curMtxIdx;
   2051     sCurrentGdDl->totalLights = sCurrentGdDl->curLightIdx;
   2052     sCurrentGdDl->totalGfx = sCurrentGdDl->curGfxIdx;
   2053     sCurrentGdDl->totalVp = sCurrentGdDl->curVpIdx;
   2054     return dlnum;
   2055 }
   2056 
   2057 /* 24EC18 -> 24EC48; orig name: func_801A0448 */
   2058 void branch_to_gddl(s32 dlNum) {
   2059     branch_cur_dl_to_num(dlNum);
   2060 }
   2061 
   2062 /* 24EC48 -> 24F03C */
   2063 // phong shading function?
   2064 void gd_dl_hilite(s32 idx, // material GdDl number; offsets into hilite array
   2065                    struct ObjCamera *cam, UNUSED struct GdVec3f *arg2, UNUSED struct GdVec3f *arg3,
   2066                    struct GdVec3f *arg4,   // vector to light source?
   2067                    struct GdColour *colour // light color
   2068 ) {
   2069     UNUSED u8 filler1[96];
   2070     Hilite *hilite; // 4c
   2071     struct GdVec3f sp40;
   2072     f32 sp3C; // magnitude of sp40
   2073     f32 sp38;
   2074     f32 sp34;
   2075     UNUSED u8 filler2[24];
   2076 
   2077     sp38 = 32.0f; // x scale factor?
   2078     sp34 = 32.0f; // y scale factor?
   2079     if (idx >= 0xc8) {
   2080         fatal_printf("too many hilites");
   2081     }
   2082     hilite = &sHilites[idx];
   2083 
   2084     gDPSetPrimColor(next_gfx(), 0, 0, (s32)(colour->r * 255.0f), (s32)(colour->g * 255.0f),
   2085                     (s32)(colour->b * 255.0f), 255);
   2086     sp40.z = cam->unkE8[0][2] + arg4->x;
   2087     sp40.y = cam->unkE8[1][2] + arg4->y;
   2088     sp40.x = cam->unkE8[2][2] + arg4->z;
   2089     sp3C = sqrtf(SQ(sp40.z) + SQ(sp40.y) + SQ(sp40.x));
   2090     if (sp3C > 0.1) {
   2091         sp3C = 1.0 / sp3C; //? 1.0f
   2092         sp40.z *= sp3C;
   2093         sp40.y *= sp3C;
   2094         sp40.x *= sp3C;
   2095 
   2096         hilite->h.x1 =
   2097             (((sp40.z * cam->unkE8[0][0]) + (sp40.y * cam->unkE8[1][0]) + (sp40.x * cam->unkE8[2][0]))
   2098              * sp38 * 2.0f)
   2099             + (sp38 * 4.0f);
   2100         hilite->h.y1 =
   2101             (((sp40.z * cam->unkE8[0][1]) + (sp40.y * cam->unkE8[1][1]) + (sp40.x * cam->unkE8[2][1]))
   2102              * sp34 * 2.0f)
   2103             + (sp34 * 4.0f);
   2104     } else {
   2105         hilite->h.x1 = sp38 * 2.0f;
   2106         hilite->h.y1 = sp34 * 2.0f;
   2107     }
   2108 }
   2109 
   2110 /**
   2111  * Adds some display list commands that perform lighting for a material
   2112  */
   2113 s32 gd_dl_material_lighting(s32 id, struct GdColour *colour, s32 material) {
   2114     UNUSED u8 filler[8];
   2115     s32 i;
   2116     s32 numLights = sNumLights;
   2117     s32 scaledColours[3];
   2118     s32 lightDir[3];
   2119 
   2120     if (id > 0) {
   2121         begin_gddl(id);
   2122     }
   2123     switch (material) {
   2124         case GD_MTL_TEX_OFF:
   2125             gddl_is_loading_stub_dl(FALSE);
   2126             gddl_is_loading_stub_dl(FALSE);
   2127             gddl_is_loading_stub_dl(FALSE);
   2128             gddl_is_loading_stub_dl(FALSE);
   2129             gddl_is_loading_shine_dl(FALSE);
   2130             gddl_is_loading_shine_dl(FALSE);
   2131             gddl_is_loading_shine_dl(FALSE);
   2132             gddl_is_loading_shine_dl(FALSE);
   2133             numLights = NUMLIGHTS_2;
   2134             break;
   2135         case GD_MTL_STUB_DL:
   2136             gddl_is_loading_stub_dl(TRUE);
   2137             break;
   2138         case GD_MTL_SHINE_DL:
   2139             gddl_is_loading_shine_dl(TRUE);
   2140             if (id >= 200) {
   2141                 fatal_printf("too many hilites");
   2142             }
   2143             gDPSetHilite1Tile(next_gfx(), G_TX_RENDERTILE, &sHilites[id], 32, 32);
   2144             break;
   2145         case GD_MTL_BREAK:
   2146             break;
   2147         default:
   2148             gddl_is_loading_stub_dl(FALSE);
   2149             gddl_is_loading_shine_dl(FALSE);
   2150 
   2151             DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[0] = colour->r * 255.0f;
   2152             DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[1] = colour->g * 255.0f;
   2153             DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[2] = colour->b * 255.0f;
   2154 
   2155             DL_CURRENT_LIGHT(sCurrentGdDl).a.l.colc[0] = DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[0];
   2156             DL_CURRENT_LIGHT(sCurrentGdDl).a.l.colc[1] = DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[1];
   2157             DL_CURRENT_LIGHT(sCurrentGdDl).a.l.colc[2] = DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[2];
   2158             // 801A0D04
   2159             DL_CURRENT_LIGHT(sCurrentGdDl).l[0].l.col[0] = 0;
   2160             DL_CURRENT_LIGHT(sCurrentGdDl).l[0].l.col[1] = 0;
   2161             DL_CURRENT_LIGHT(sCurrentGdDl).l[0].l.col[2] = 0;
   2162 
   2163             DL_CURRENT_LIGHT(sCurrentGdDl).l[0].l.colc[0] = 0;
   2164             DL_CURRENT_LIGHT(sCurrentGdDl).l[0].l.colc[1] = 0;
   2165             DL_CURRENT_LIGHT(sCurrentGdDl).l[0].l.colc[2] = 0;
   2166 
   2167             gSPNumLights(next_gfx(), NUMLIGHTS_1);
   2168             gSPLight(next_gfx(), osVirtualToPhysical(&DL_CURRENT_LIGHT(sCurrentGdDl).l), LIGHT_1);
   2169             gSPLight(next_gfx(), osVirtualToPhysical(&DL_CURRENT_LIGHT(sCurrentGdDl).a), LIGHT_2);
   2170             next_light();
   2171             if (id > 0) {
   2172                 gd_enddlsplist();
   2173             }
   2174             return 0;
   2175             break;
   2176     }
   2177     // L801A0EF4
   2178     scaledColours[0] = (s32)(colour->r * sAmbScaleColour.r * 255.0f);
   2179     scaledColours[1] = (s32)(colour->g * sAmbScaleColour.g * 255.0f);
   2180     scaledColours[2] = (s32)(colour->b * sAmbScaleColour.b * 255.0f);
   2181     // 801A0FE4
   2182     DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[0] = scaledColours[0];
   2183     DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[1] = scaledColours[1];
   2184     DL_CURRENT_LIGHT(sCurrentGdDl).a.l.col[2] = scaledColours[2];
   2185     // 801A1068
   2186     DL_CURRENT_LIGHT(sCurrentGdDl).a.l.colc[0] = scaledColours[0];
   2187     DL_CURRENT_LIGHT(sCurrentGdDl).a.l.colc[1] = scaledColours[1];
   2188     DL_CURRENT_LIGHT(sCurrentGdDl).a.l.colc[2] = scaledColours[2];
   2189     // 801A10EC
   2190     gSPNumLights(next_gfx(), numLights);
   2191     for (i = 0; i < numLights; i++) { // L801A1134
   2192         scaledColours[0] = colour->r * sLightScaleColours[i].r * 255.0f;
   2193         scaledColours[1] = colour->g * sLightScaleColours[i].g * 255.0f;
   2194         scaledColours[2] = colour->b * sLightScaleColours[i].b * 255.0f;
   2195         // 801A1260
   2196         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.col[0] = scaledColours[0];
   2197         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.col[1] = scaledColours[1];
   2198         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.col[2] = scaledColours[2];
   2199         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.colc[0] = scaledColours[0];
   2200         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.colc[1] = scaledColours[1];
   2201         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.colc[2] = scaledColours[2];
   2202 
   2203         // 801A13B0
   2204         lightDir[0] = (s8)sLightDirections[i].x;
   2205         lightDir[1] = (s8)sLightDirections[i].y;
   2206         lightDir[2] = (s8)sLightDirections[i].z;
   2207         // 801A141C
   2208         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.dir[0] = lightDir[0];
   2209         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.dir[1] = lightDir[1];
   2210         DL_CURRENT_LIGHT(sCurrentGdDl).l[i].l.dir[2] = lightDir[2];
   2211         // 801A14C4
   2212         gSPLight(next_gfx(), osVirtualToPhysical(&DL_CURRENT_LIGHT(sCurrentGdDl).l[i]), i + 1);
   2213     }
   2214     // L801A1550
   2215     gSPLight(next_gfx(), osVirtualToPhysical(&DL_CURRENT_LIGHT(sCurrentGdDl)), i + 1);
   2216     next_light();
   2217     gd_enddlsplist();
   2218     return 0;
   2219 }
   2220 
   2221 /* 24FDB8 -> 24FE94; orig name: func_801A15E8; only from faces? */
   2222 void set_Vtx_norm_buf_1(struct GdVec3f *norm) {
   2223     sVtxCvrtNormBuf[0] = (s8)(norm->x * 127.0f);
   2224     sVtxCvrtNormBuf[1] = (s8)(norm->y * 127.0f);
   2225     sVtxCvrtNormBuf[2] = (s8)(norm->z * 127.0f);
   2226 }
   2227 
   2228 /* 24FE94 -> 24FF80; orig name: func_801A16C4; only from verts? */
   2229 void set_Vtx_norm_buf_2(struct GdVec3f *norm) {
   2230     sVtxCvrtNormBuf[0] = (s8)(norm->x * 127.0f);
   2231     sVtxCvrtNormBuf[1] = (s8)(norm->y * 127.0f);
   2232     sVtxCvrtNormBuf[2] = (s8)(norm->z * 127.0f);
   2233 
   2234     //? are these stub functions?
   2235     return; // @ 801A17A0
   2236     return; // @ 801A17A8
   2237 }
   2238 
   2239 /* 24FF80 -> 24FFDC; orig name: func_801A17B0 */
   2240 void set_gd_mtx_parameters(s32 params) {
   2241     switch (params) {
   2242         case G_MTX_PROJECTION | G_MTX_MUL | G_MTX_PUSH:
   2243             sMtxParamType = G_MTX_PROJECTION;
   2244             break;
   2245         case G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH:
   2246             sMtxParamType = G_MTX_MODELVIEW;
   2247             break;
   2248     }
   2249 }
   2250 
   2251 /**
   2252  * Adds a viewport to the current display list based on the current active view
   2253  */
   2254 static void gd_dl_viewport(void) {
   2255     Vp *vp;
   2256 
   2257     vp = &DL_CURRENT_VP(sCurrentGdDl);
   2258 
   2259     vp->vp.vscale[0] = (s16)(sActiveView->lowerRight.x * 2.0f);  // x scale
   2260     vp->vp.vscale[1] = (s16)(sActiveView->lowerRight.y * 2.0f);  // y scale
   2261     vp->vp.vscale[2] = 0x1FF;  // z scale
   2262     vp->vp.vscale[3] = 0x000;
   2263 
   2264     vp->vp.vtrans[0] = (s16)((sActiveView->upperLeft.x * 4.0f) + (sActiveView->lowerRight.x * 2.0f));  // x offset
   2265     vp->vp.vtrans[1] = (s16)((sActiveView->upperLeft.y * 4.0f) + (sActiveView->lowerRight.y * 2.0f));  // y offset
   2266     vp->vp.vtrans[2] = 0x1FF;  // z offset
   2267     vp->vp.vtrans[3] = 0x000;
   2268 
   2269     gSPViewport(next_gfx(), osVirtualToPhysical(vp));
   2270     next_vp();
   2271 }
   2272 
   2273 /* 2501D0 -> 250300 */
   2274 static void update_render_mode(void) {
   2275     if ((sActiveView->flags & VIEW_ALLOC_ZBUF) != 0) {
   2276         if (sAlpha != 0xff) {
   2277             gDPSetRenderMode(next_gfx(), G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2);
   2278         } else {
   2279             gDPSetRenderMode(next_gfx(), G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2);
   2280         }
   2281     } else {
   2282         if (sAlpha != 0xff) {
   2283             gDPSetRenderMode(next_gfx(), G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
   2284         } else {
   2285             gDPSetRenderMode(next_gfx(), G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2);
   2286         }
   2287     }
   2288 }
   2289 
   2290 /* 250300 -> 250640 */
   2291 void Unknown801A1B30(void) {
   2292     gDPPipeSync(next_gfx());
   2293     gd_set_color_fb();
   2294     gd_dl_set_fill(&sActiveView->colour);
   2295     gDPFillRectangle(next_gfx(), (u32)(sActiveView->upperLeft.x), (u32)(sActiveView->upperLeft.y),
   2296                      (u32)(sActiveView->upperLeft.x + sActiveView->lowerRight.x - 1.0f),
   2297                      (u32)(sActiveView->upperLeft.y + sActiveView->lowerRight.y - 1.0f));
   2298     gDPPipeSync(next_gfx());
   2299 }
   2300 
   2301 /* 250640 -> 250AE0 */
   2302 void Unknown801A1E70(void) {
   2303     gDPPipeSync(next_gfx());
   2304     gDPSetCycleType(next_gfx(), G_CYC_FILL);
   2305     gDPSetRenderMode(next_gfx(), G_RM_OPA_SURF, G_RM_OPA_SURF2);
   2306     gd_dl_set_z_buffer_area();
   2307     gDPSetColorImage(next_gfx(), G_IM_FMT_RGBA, G_IM_SIZ_16b, sActiveView->parent->lowerRight.x,
   2308                      GD_LOWER_24(sActiveView->parent->zbuf));
   2309     gDPSetFillColor(next_gfx(), GPACK_ZDZ(G_MAXFBZ, 0) << 16 | GPACK_ZDZ(G_MAXFBZ, 0));
   2310     gDPFillRectangle(next_gfx(), (u32)(sActiveView->upperLeft.x), (u32)(sActiveView->upperLeft.y),
   2311                      (u32)(sActiveView->upperLeft.x + sActiveView->lowerRight.x - 1.0f),
   2312                      (u32)(sActiveView->upperLeft.y + sActiveView->lowerRight.y - 1.0f));
   2313     gDPPipeSync(next_gfx());
   2314     gd_set_color_fb();
   2315 }
   2316 
   2317 /* 250AE0 -> 250B30; orig name: func_801A2310 */
   2318 void gd_set_one_cycle(void) {
   2319     gDPSetCycleType(next_gfx(), G_CYC_1CYCLE);
   2320     update_render_mode();
   2321 }
   2322 
   2323 /* 250B30 -> 250B44 */
   2324 void stub_renderer_3(void) {
   2325     UNUSED u8 filler[16];
   2326 }
   2327 
   2328 /* 250B44 -> 250B58 */
   2329 void gddl_is_loading_stub_dl(UNUSED s32 dlLoad) {
   2330 }
   2331 
   2332 /* 250B58 -> 250C18 */
   2333 void gddl_is_loading_shine_dl(s32 dlLoad) {
   2334     if (dlLoad) {
   2335         gSPDisplayList(next_gfx(), osVirtualToPhysical(&gd_dl_mario_face_shine));
   2336     } else {
   2337         gSPTexture(next_gfx(), 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF);
   2338         gDPSetCombineMode(next_gfx(), G_CC_SHADE, G_CC_SHADE);
   2339     }
   2340 }
   2341 
   2342 /* 250C18 -> 251014; orig name: func_801A2448 */
   2343 void start_view_dl(struct ObjView *view) {
   2344     f32 ulx;
   2345     f32 uly;
   2346     f32 lrx;
   2347     f32 lry;
   2348 
   2349     if (view->upperLeft.x < view->parent->upperLeft.x) {
   2350         ulx = view->parent->upperLeft.x;
   2351     } else {
   2352         ulx = view->upperLeft.x;
   2353     }
   2354 
   2355     if (view->upperLeft.x + view->lowerRight.x
   2356         > view->parent->upperLeft.x + view->parent->lowerRight.x) {
   2357         lrx = view->parent->upperLeft.x + view->parent->lowerRight.x;
   2358     } else {
   2359         lrx = view->upperLeft.x + view->lowerRight.x;
   2360     }
   2361 
   2362     if (view->upperLeft.y < view->parent->upperLeft.y) {
   2363         uly = view->parent->upperLeft.y;
   2364     } else {
   2365         uly = view->upperLeft.y;
   2366     }
   2367 
   2368     if (view->upperLeft.y + view->lowerRight.y
   2369         > view->parent->upperLeft.y + view->parent->lowerRight.y) {
   2370         lry = view->parent->upperLeft.y + view->parent->lowerRight.y;
   2371     } else {
   2372         lry = view->upperLeft.y + view->lowerRight.y;
   2373     }
   2374 
   2375     if (ulx >= lrx) {
   2376         ulx = lrx - 1.0f;
   2377     }
   2378     if (uly >= lry) {
   2379         uly = lry - 1.0f;
   2380     }
   2381 
   2382     gDPSetScissor(next_gfx(), G_SC_NON_INTERLACE, ulx, uly, lrx, lry);
   2383     gSPClearGeometryMode(next_gfx(), 0xFFFFFFFF);
   2384     gSPSetGeometryMode(next_gfx(), G_LIGHTING | G_CULL_BACK | G_SHADING_SMOOTH | G_SHADE);
   2385     if (view->flags & VIEW_ALLOC_ZBUF) {
   2386         gSPSetGeometryMode(next_gfx(), G_ZBUFFER);
   2387     }
   2388     gd_dl_viewport();
   2389     update_render_mode();
   2390     gDPPipeSync(next_gfx());
   2391 }
   2392 
   2393 /* 251014 -> 251A1C; orig name: func_801A2844 */
   2394 void parse_p1_controller(void) {
   2395     u32 i;
   2396     struct GdControl *gdctrl = &gGdCtrl;
   2397     OSContPad *currInputs;
   2398     OSContPad *prevInputs;
   2399 
   2400     // Copy current inputs to previous
   2401     u8 *src = (u8 *) gdctrl;
   2402     u8 *dest = (u8 *) gdctrl->prevFrame;
   2403     for (i = 0; i < sizeof(struct GdControl); i++) {
   2404         *dest++ = *src++;
   2405     }
   2406 
   2407     gdctrl->unk50 = gdctrl->unk4C = gdctrl->dup = gdctrl->ddown = 0;
   2408 
   2409     currInputs = &sGdContPads[0];
   2410     prevInputs = &sPrevFrameCont[0];
   2411     // stick values
   2412     gdctrl->stickXf     = currInputs->stick_x;
   2413     gdctrl->stickYf     = currInputs->stick_y;
   2414     gdctrl->stickDeltaX = gdctrl->stickX;
   2415     gdctrl->stickDeltaY = gdctrl->stickY;
   2416     gdctrl->stickX      = currInputs->stick_x;
   2417     gdctrl->stickY      = currInputs->stick_y;
   2418     gdctrl->stickDeltaX -= gdctrl->stickX;
   2419     gdctrl->stickDeltaY -= gdctrl->stickY;
   2420     // button values (as bools)
   2421     gdctrl->trgL   = (currInputs->button & L_TRIG) != 0;
   2422     gdctrl->trgR   = (currInputs->button & R_TRIG) != 0;
   2423     gdctrl->btnA   = (currInputs->button & A_BUTTON) != 0;
   2424     gdctrl->btnB   = (currInputs->button & B_BUTTON) != 0;
   2425     gdctrl->cleft  = (currInputs->button & L_CBUTTONS) != 0;
   2426     gdctrl->cright = (currInputs->button & R_CBUTTONS) != 0;
   2427     gdctrl->cup    = (currInputs->button & U_CBUTTONS) != 0;
   2428     gdctrl->cdown  = (currInputs->button & D_CBUTTONS) != 0;
   2429     // but not these buttons??
   2430     gdctrl->dleft  = currInputs->button & L_JPAD;
   2431     gdctrl->dright = currInputs->button & R_JPAD;
   2432     gdctrl->dup    = currInputs->button & U_JPAD;
   2433     gdctrl->ddown  = currInputs->button & D_JPAD;
   2434 
   2435     if (gdctrl->btnA && !gdctrl->dragging) {
   2436         gdctrl->startedDragging = TRUE;
   2437     } else {
   2438         gdctrl->startedDragging = FALSE;
   2439     }
   2440     // toggle if A is pressed? or is this just some seed for an rng?
   2441     gdctrl->dragging = gdctrl->btnA;
   2442     gdctrl->unkD8b20 = gdctrl->unkD8b40 = FALSE;
   2443     gdctrl->AbtnPressWait = FALSE;
   2444 
   2445     if (gdctrl->startedDragging) {
   2446         gdctrl->dragStartX = gdctrl->csrX;
   2447         gdctrl->dragStartY = gdctrl->csrY;
   2448 
   2449         if (gdctrl->currFrame - gdctrl->dragStartFrame < 10) {
   2450             gdctrl->AbtnPressWait = TRUE;
   2451         }
   2452     }
   2453 
   2454     if (gdctrl->dragging) {
   2455         gdctrl->dragStartFrame = gdctrl->currFrame;
   2456     }
   2457     gdctrl->currFrame++;
   2458 
   2459     if (currInputs->button & START_BUTTON && !(prevInputs->button & START_BUTTON)) {
   2460         gdctrl->newStartPress ^= 1;
   2461     }
   2462 
   2463     if (currInputs->button & Z_TRIG && !(prevInputs->button & Z_TRIG)) {
   2464         sCurrDebugViewIndex++;
   2465     }
   2466 
   2467     if (sCurrDebugViewIndex > sDebugViewsCount) {
   2468         sCurrDebugViewIndex = 0;
   2469     } else if (sCurrDebugViewIndex < 0) {
   2470         sCurrDebugViewIndex = sDebugViewsCount;
   2471     }
   2472 
   2473     if (sCurrDebugViewIndex) {
   2474         deactivate_timing();
   2475     } else {
   2476         activate_timing();
   2477     }
   2478 
   2479     for (i = 0; ((s32) i) < sDebugViewsCount; i++) {
   2480         sDebugViews[i]->flags &= ~VIEW_UPDATE;
   2481     }
   2482 
   2483     if (sCurrDebugViewIndex) {
   2484         sDebugViews[sCurrDebugViewIndex - 1]->flags |= VIEW_UPDATE;
   2485     }
   2486 
   2487     // deadzone checks
   2488     if (ABS(gdctrl->stickX) >= 6) {
   2489         gdctrl->csrX += gdctrl->stickX * 0.1;
   2490     }
   2491     if (ABS(gdctrl->stickY) >= 6) {
   2492         gdctrl->csrY -= gdctrl->stickY * 0.1;
   2493     }
   2494 
   2495     // clamp cursor position within screen view bounds
   2496     if (gdctrl->csrX < sScreenView->parent->upperLeft.x + 16.0f) {
   2497         gdctrl->csrX = sScreenView->parent->upperLeft.x + 16.0f;
   2498     }
   2499     if (gdctrl->csrX > sScreenView->parent->upperLeft.x + sScreenView->parent->lowerRight.x - 48.0f) {
   2500         gdctrl->csrX = sScreenView->parent->upperLeft.x + sScreenView->parent->lowerRight.x - 48.0f;
   2501     }
   2502     if (gdctrl->csrY < sScreenView->parent->upperLeft.y + 16.0f) {
   2503         gdctrl->csrY = sScreenView->parent->upperLeft.y + 16.0f;
   2504     }
   2505     if (gdctrl->csrY > sScreenView->parent->upperLeft.y + sScreenView->parent->lowerRight.y - 32.0f) {
   2506         gdctrl->csrY = sScreenView->parent->upperLeft.y + sScreenView->parent->lowerRight.y - 32.0f;
   2507     }
   2508 
   2509     for (i = 0; i < sizeof(OSContPad); i++) {
   2510         ((u8 *) prevInputs)[i] = ((u8 *) currInputs)[i];
   2511     }
   2512 }
   2513 
   2514 void stub_renderer_4(f32 arg0) {
   2515     return;
   2516 
   2517     // dead code
   2518     if (D_801BD768.x * D_801A86CC.x + arg0 * 2.0f > 160.0) {
   2519         func_801A3370(D_801BD758.x - D_801BD768.x, -20.0f, 0.0f);
   2520         D_801BD768.x = D_801BD758.x;
   2521     }
   2522 }
   2523 
   2524 /**
   2525  * Unused
   2526  */
   2527 void Unknown801A32F4(s32 arg0) {
   2528     D_801BD774 = GD_LOWER_24(arg0) + D_801BAF28;
   2529 }
   2530 
   2531 /* 251AF4 -> 251B40 */
   2532 void func_801A3324(f32 x, f32 y, f32 z) {
   2533     D_801BD768.x = x;
   2534     D_801BD768.y = y;
   2535     D_801BD768.z = z;
   2536     D_801BD758.x = x;
   2537     D_801BD758.y = y;
   2538     D_801BD758.z = z;
   2539 }
   2540 
   2541 /* 251B40 -> 251BC8 */
   2542 void func_801A3370(f32 x, f32 y, f32 z) {
   2543     gd_dl_mul_trans_matrix(x, y, z);
   2544     D_801BD768.x += x;
   2545     D_801BD768.y += y;
   2546     D_801BD768.z += z;
   2547 }
   2548 
   2549 /**
   2550  * Unused
   2551  */
   2552 void Unknown801A33F8(f32 x, f32 y, f32 z) {
   2553     gd_dl_mul_trans_matrix(x - D_801BD768.x, y - D_801BD768.y, z - D_801BD768.z);
   2554 
   2555     D_801BD768.x = x;
   2556     D_801BD768.y = y;
   2557     D_801BD768.z = z;
   2558 }
   2559 
   2560 /**
   2561  * Unused
   2562  */
   2563 void Unknown801A347C(f32 x, f32 y, f32 z) {
   2564     D_801A86CC.x = x;
   2565     D_801A86CC.y = y;
   2566     D_801A86CC.z = z;
   2567     gd_dl_scale(x, y, z);
   2568 }
   2569 
   2570 /* 251CB0 -> 251D44; orig name: func_801A34E0 */
   2571 void border_active_view(void) {
   2572     if (sActiveView->flags & VIEW_BORDERED) {
   2573         gd_dl_set_fill(gd_get_colour(1));
   2574         gd_draw_border_rect(0.0f, 0.0f, (sActiveView->lowerRight.x - 1.0f),
   2575                             (sActiveView->lowerRight.y - 1.0f));
   2576     }
   2577 }
   2578 
   2579 /* 251D44 -> 251DAC */
   2580 void gd_shading(s32 model) {
   2581     switch (model) {
   2582         case 9:
   2583             break;
   2584         case 10:
   2585             break;
   2586         default:
   2587             fatal_printf("gd_shading(): Unknown shading model");
   2588     }
   2589 }
   2590 
   2591 /* 251DAC -> 251E18 */
   2592 s32 gd_getproperty(s32 prop, UNUSED void *arg1) {
   2593     s32 got = FALSE;
   2594 
   2595     switch (prop) {
   2596         case 3:
   2597             got = TRUE;
   2598             break;
   2599         default:
   2600             fatal_printf("gd_getproperty(): Unkown property");
   2601     }
   2602 
   2603     return got;
   2604 }
   2605 
   2606 /* 251E18 -> 2522B0 */
   2607 void gd_setproperty(enum GdProperty prop, f32 f1, f32 f2, f32 f3) {
   2608     UNUSED f32 sp3C = 1.0f;
   2609     s32 parm;
   2610 
   2611     switch (prop) {
   2612         case GD_PROP_LIGHTING:
   2613             parm = (s32) f1;
   2614             switch (parm) {
   2615                 case 1:
   2616                     gSPSetGeometryMode(next_gfx(), G_LIGHTING);
   2617                     break;
   2618                 case 0:
   2619                     gSPClearGeometryMode(next_gfx(), G_LIGHTING);
   2620                     break;
   2621             }
   2622             break;
   2623         case GD_PROP_AMB_COLOUR:
   2624             sAmbScaleColour.r = f1;
   2625             sAmbScaleColour.g = f2;
   2626             sAmbScaleColour.b = f3;
   2627             break;
   2628         case GD_PROP_LIGHT_DIR:
   2629             sLightDirections[sLightId].x = (s32)(f1 * 120.f);
   2630             sLightDirections[sLightId].y = (s32)(f2 * 120.f);
   2631             sLightDirections[sLightId].z = (s32)(f3 * 120.f);
   2632             break;
   2633         case GD_PROP_DIFUSE_COLOUR:
   2634             sLightScaleColours[sLightId].r = f1;
   2635             sLightScaleColours[sLightId].g = f2;
   2636             sLightScaleColours[sLightId].b = f3;
   2637             break;
   2638         case GD_PROP_CULLING:
   2639             parm = (s32) f1;
   2640             switch (parm) {
   2641                 case 1:
   2642                     gSPSetGeometryMode(next_gfx(), G_CULL_BACK);
   2643                     break;
   2644                 case 0:
   2645                     gSPClearGeometryMode(next_gfx(), G_CULL_BACK);
   2646                     break;
   2647             }
   2648             break;
   2649         case GD_PROP_OVERLAY:
   2650             parm = (s32) f1;
   2651             switch (parm) {
   2652                 case 1:
   2653                     break;
   2654                 case 0:
   2655                     break;
   2656                 default:
   2657                     fatal_printf("Bad GD_OVERLAY parm");
   2658             }
   2659             break;
   2660         case GD_PROP_ZBUF_FN:
   2661             parm = (s32) f1;
   2662             switch (parm) {
   2663                 case 23:
   2664                     break;
   2665                 case 24:
   2666                     break;
   2667                 case 25:
   2668                     break;
   2669                 default:
   2670                     fatal_printf("Bad zbuf function");
   2671             }
   2672             //? no break?
   2673         case GD_PROP_STUB17:
   2674             break;
   2675         case GD_PROP_STUB18:
   2676             break;
   2677         case GD_PROP_STUB19:
   2678             break;
   2679         case GD_PROP_STUB20:
   2680             break;
   2681         case GD_PROP_STUB21:
   2682             break;
   2683         default:
   2684             fatal_printf("gd_setproperty(): Unkown property");
   2685     }
   2686 }
   2687 
   2688 /* 2522B0 -> 2522C0 */
   2689 void stub_renderer_5(void) {
   2690 }
   2691 
   2692 /* 2522C0 -> 25245C */
   2693 void gd_create_ortho_matrix(f32 l, f32 r, f32 b, f32 t, f32 n, f32 f) {
   2694     uintptr_t orthoMtx;
   2695     uintptr_t rotMtx;
   2696 
   2697     // Should produce G_RDPHALF_1 in Fast3D
   2698     gSPPerspNormalize(next_gfx(), 0xFFFF);
   2699 
   2700     guOrtho(&DL_CURRENT_MTX(sCurrentGdDl), l, r, b, t, n, f, 1.0f);
   2701     orthoMtx = GD_LOWER_29(&DL_CURRENT_MTX(sCurrentGdDl));
   2702     gSPMatrix(next_gfx(), orthoMtx, G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
   2703 
   2704     next_mtx();
   2705     guRotate(&DL_CURRENT_MTX(sCurrentGdDl), 0.0f, 0.0f, 0.0f, 1.0f);
   2706     rotMtx = GD_LOWER_29(&DL_CURRENT_MTX(sCurrentGdDl));
   2707     gSPMatrix(next_gfx(), rotMtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
   2708 
   2709     func_801A3324(0.0f, 0.0f, 0.0f);
   2710     next_mtx();
   2711 }
   2712 
   2713 /* 25245C -> 25262C */
   2714 void gd_create_perspective_matrix(f32 fovy, f32 aspect, f32 near, f32 far) {
   2715     u16 perspNorm;
   2716     UNUSED u8 filler1[4];
   2717     uintptr_t perspecMtx;
   2718     uintptr_t rotMtx;
   2719     UNUSED u8 filler2[4];
   2720     UNUSED f32 unused = 0.0625f;
   2721 
   2722     sGdPerspTimer += 0.1;
   2723     guPerspective(&DL_CURRENT_MTX(sCurrentGdDl), &perspNorm, fovy, aspect, near, far, 1.0f);
   2724 
   2725     gSPPerspNormalize(next_gfx(), perspNorm);
   2726 
   2727     perspecMtx = GD_LOWER_29(&DL_CURRENT_MTX(sCurrentGdDl));
   2728     gSPMatrix(next_gfx(), perspecMtx, G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
   2729     next_mtx();
   2730 
   2731     guRotate(&DL_CURRENT_MTX(sCurrentGdDl), 0.0f, 0.0f, 0.0f, 1.0f);
   2732     rotMtx = GD_LOWER_29(&DL_CURRENT_MTX(sCurrentGdDl));
   2733     gSPMatrix(next_gfx(), rotMtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
   2734     func_801A3324(0.0f, 0.0f, 0.0f);
   2735     next_mtx();
   2736 }
   2737 
   2738 /* 25262C -> 252AF8 */
   2739 s32 setup_view_buffers(const char *name, struct ObjView *view, UNUSED s32 ulx, UNUSED s32 uly,
   2740                        UNUSED s32 lrx, UNUSED s32 lry) {
   2741     char memtrackerName[0x100];
   2742 
   2743     if (view->flags & (VIEW_Z_BUF | VIEW_COLOUR_BUF) && !(view->flags & VIEW_UNK_1000)) {
   2744         if (view->flags & VIEW_COLOUR_BUF) {
   2745             sprintf(memtrackerName, "%s CBuf", name);
   2746             start_memtracker(memtrackerName);
   2747             view->colourBufs[0] =
   2748                 gd_malloc((u32)(2.0f * view->lowerRight.x * view->lowerRight.y + 64.0f), 0x20);
   2749 
   2750             if (view->flags & VIEW_2_COL_BUF) {
   2751                 view->colourBufs[1] =
   2752                     gd_malloc((u32)(2.0f * view->lowerRight.x * view->lowerRight.y + 64.0f), 0x20);
   2753             } else {
   2754                 view->colourBufs[1] = view->colourBufs[0];
   2755             }
   2756 
   2757             view->colourBufs[0] = (void *) ALIGN((uintptr_t) view->colourBufs[0], 64);
   2758             view->colourBufs[1] = (void *) ALIGN((uintptr_t) view->colourBufs[1], 64);
   2759             stop_memtracker(memtrackerName);
   2760 
   2761             if (view->colourBufs[0] == NULL || view->colourBufs[1] == NULL) {
   2762                 fatal_printf("Not enough DRAM for colour buffers\n");
   2763             }
   2764             view->parent = view;
   2765         } else {
   2766             view->parent = sScreenView;
   2767         }
   2768 
   2769         if (view->flags & VIEW_Z_BUF) {
   2770             sprintf(memtrackerName, "%s ZBuf", name);
   2771             start_memtracker(memtrackerName);
   2772             if (view->flags & VIEW_ALLOC_ZBUF) {
   2773                 view->zbuf =
   2774                     gd_malloc((u32)(2.0f * view->lowerRight.x * view->lowerRight.y + 64.0f), 0x40);
   2775                 if (view->zbuf == NULL) {
   2776                     fatal_printf("Not enough DRAM for Z buffer\n");
   2777                 }
   2778                 view->zbuf = (void *) ALIGN((uintptr_t) view->zbuf, 64);
   2779             }
   2780             stop_memtracker(memtrackerName);
   2781         } else {
   2782             view->zbuf = sScreenView->zbuf;
   2783         }
   2784     } else {
   2785         view->parent = sScreenView;
   2786     }
   2787 
   2788     view->gdDlNum = 0;
   2789     view->unk74 = 0;
   2790 
   2791     if (view->flags & VIEW_DEFAULT_PARENT) {
   2792         view->parent = D_801A86E0;
   2793     }
   2794 
   2795 //! @bug No actual return, but the return value is used.
   2796 //!      There is no obvious value to return. Since the function
   2797 //!      doesn't use four of its parameters, this function may have
   2798 //!      had a fair amount of its code commented out. In game, the
   2799 //!      returned value is always 0, so the fix returns that value
   2800 #ifdef AVOID_UB
   2801     return 0;
   2802 #endif
   2803 }
   2804 
   2805 /* 252AF8 -> 252BAC; orig name: _InitControllers */
   2806 void gd_init_controllers(void) {
   2807     OSContPad *p1cont = &sPrevFrameCont[0]; // 1c
   2808     u32 i;                                  // 18
   2809 
   2810     osCreateMesgQueue(&D_801BE830, D_801BE848, ARRAY_COUNT(D_801BE848));
   2811     osSetEventMesg(OS_EVENT_SI, &D_801BE830, (OSMesg) OS_MESG_SI_COMPLETE);
   2812     osContInit(&D_801BE830, &D_801BAEA0, D_801BAE60);
   2813     osContStartReadData(&D_801BE830);
   2814 
   2815     for (i = 0; i < sizeof(OSContPad); i++) {
   2816         ((u8 *) p1cont)[i] = 0;
   2817     }
   2818 }
   2819 
   2820 /* 252BAC -> 252BC0 */
   2821 void stub_renderer_6(UNUSED struct GdObj *obj) {
   2822 }
   2823 
   2824 /**
   2825  * Unused - This is likely a stub version of the `defpup` function from the IRIX
   2826  * Graphics Library. It was used to define a popup menu. See the IRIX "Graphics
   2827  * Library Reference Manual, C Edition" for details.
   2828  *
   2829  * @param menufmt  a format string defining the menu items to be added to the
   2830  *                 popup menu.
   2831  * @return  an identifier of the menu just defined
   2832  */
   2833 long defpup(UNUSED const char *menufmt, ...) {
   2834     //! @bug no return; function was stubbed
   2835 #ifdef AVOID_UB
   2836    return 0;
   2837 #endif
   2838 }
   2839 
   2840 /**
   2841  * Unused - called when the user picks an item from the "Control Type" menu.
   2842  * Presumably, this would allow switching inputs between controller, keyboard,
   2843  * and mouse.
   2844  *
   2845  * @param itemId  ID of the menu item that was clicked
   2846  *                (1 = "U-64 Analogue Joystick", 2 = "Keyboard", 3 = "Mouse")
   2847  */
   2848 void menu_cb_control_type(UNUSED u32 itemId) {
   2849 }
   2850 
   2851 /**
   2852  * Unused - called when the user clicks the "Re-Calibrate Controller" item from
   2853  * the "Dynamics" menu.
   2854  */
   2855 void menu_cb_recalibrate_controller(UNUSED u32 itemId) {
   2856 }
   2857 
   2858 /* 252C08 -> 252C70 */
   2859 void func_801A4438(f32 x, f32 y, f32 z) {
   2860     sTextDrawPos.x = x - (sActiveView->lowerRight.x / 2.0f);
   2861     sTextDrawPos.y = (sActiveView->lowerRight.y / 2.0f) - y;
   2862     sTextDrawPos.z = z;
   2863 }
   2864 
   2865 /* 252C70 -> 252DB4 */
   2866 s32 gd_gentexture(void *texture, s32 fmt, s32 size, UNUSED u32 arg3, UNUSED u32 arg4) {
   2867     UNUSED s32 sp2C;
   2868     UNUSED s32 sp28 = 1;
   2869     s32 dl; // 24
   2870 
   2871     switch (fmt) {
   2872         case 29:
   2873             fmt = 0;
   2874             break;
   2875         case 31:
   2876             fmt = 3;
   2877             break;
   2878         default:
   2879             fatal_printf("gd_gentexture(): bad format");
   2880     }
   2881 
   2882     switch (size) {
   2883         case 33:
   2884             size = 2;
   2885             sp2C = 16;
   2886             break;
   2887         default:
   2888             fatal_printf("gd_gentexture(): bad size");
   2889     }
   2890 
   2891     sLoadedTextures[++sTextureCount] = texture;
   2892     dl = gd_startdisplist(7);
   2893 
   2894     if (dl == 0) {
   2895         fatal_printf("Cant generate DL for texture");
   2896     }
   2897     gd_enddlsplist_parent();
   2898     sTextureDisplayLists[sTextureCount] = dl;
   2899 
   2900     return dl;
   2901 }
   2902 
   2903 /**
   2904  * Unused (not called)
   2905  */
   2906 void *load_texture_from_file(const char *file, s32 fmt, s32 size, u32 arg3, u32 arg4) {
   2907     struct GdFile *txFile; // 3c
   2908     void *texture;         // 38
   2909     u32 txSize;            // 34
   2910     u32 i;                 // 30
   2911     u16 *txHalf;           // 2C
   2912     u8 buf[3];             // 28
   2913     u8 alpha;              // 27
   2914     s32 dl;                // 20
   2915 
   2916     txFile = gd_fopen(file, "r");
   2917     if (txFile == NULL) {
   2918         fatal_print("Cant load texture");
   2919     }
   2920     txSize = gd_get_file_size(txFile);
   2921     texture = gd_malloc_perm(txSize / 3 * 2);
   2922     if (texture == NULL) {
   2923         fatal_printf("Cant allocate memory for texture");
   2924     }
   2925     txHalf = (u16 *) texture;
   2926     for (i = 0; i < txSize / 3; i++) {
   2927         gd_fread((s8 *) buf, 3, 1, txFile);
   2928         alpha = 0xFF;
   2929         *txHalf = ((buf[2] >> 3) << 11) | ((buf[1] >> 3) << 6) | ((buf[0] >> 3) << 1) | (alpha >> 7);
   2930         txHalf++;
   2931     }
   2932     gd_printf("Loaded texture '%s' (%d bytes)\n", file, txSize);
   2933     gd_fclose(txFile);
   2934     dl = gd_gentexture(texture, fmt, size, arg3, arg4);
   2935     gd_printf("Generated '%s' (%d) display list ok.\n", file, dl);
   2936 
   2937     return texture;
   2938 }
   2939 
   2940 /* 252F88 -> 252FAC */
   2941 void Unknown801A47B8(struct ObjView *v) {
   2942     if (v->flags & VIEW_SAVE_TO_GLOBAL) {
   2943         D_801BE994 = v;
   2944     }
   2945 }
   2946 
   2947 void stub_renderer_7(void) {
   2948 }
   2949 
   2950 /* 252FC4 -> 252FD8 */
   2951 void stub_renderer_8(UNUSED u32 arg0) {
   2952 }
   2953 
   2954 /**
   2955  * Unused - called by func_801A520C and Unknown801A5344
   2956  */
   2957 void func_801A4808(void) {
   2958     while (D_801A8674 != 0) {
   2959         ;
   2960     }
   2961 
   2962     return;
   2963 }
   2964 
   2965 /* 253018 -> 253084 */
   2966 void func_801A4848(s32 linkDl) {
   2967     struct GdDisplayList *curDl;
   2968 
   2969     curDl = sCurrentGdDl;
   2970     sCurrentGdDl = sMHeadMainDls[gGdFrameBufNum];
   2971     branch_cur_dl_to_num(linkDl);
   2972     sCurrentGdDl = curDl;
   2973 }
   2974 
   2975 /**
   2976  * Unused - called by func_801A520C and Unknown801A5344
   2977  */
   2978 void stub_renderer_9(void) {
   2979 }
   2980 
   2981 /* 253094 -> 2530A8 */
   2982 void stub_renderer_10(UNUSED u32 arg0) {
   2983 }
   2984 
   2985 /* 2530A8 -> 2530C0 */
   2986 void stub_draw_label_text(UNUSED char *s) {
   2987     UNUSED u8 filler1[4];
   2988     UNUSED char *save = s;
   2989     UNUSED u8 filler2[24];
   2990 }
   2991 
   2992 /* 2530C0 -> 2530D8; orig name: func_801A48F0 */
   2993 void set_active_view(struct ObjView *v) {
   2994     sActiveView = v;
   2995 }
   2996 
   2997 void stub_renderer_11(void) {
   2998 }
   2999 
   3000 /**
   3001  * Unused - called by func_801A520C
   3002  */
   3003 void func_801A4918(void) {
   3004     f32 x;     // c
   3005     f32 y;     // 8
   3006     u32 ydiff; // 4
   3007 
   3008     if (sHandView == NULL || sMenuView == NULL) {
   3009         return;
   3010     }
   3011 
   3012     x = sHandView->upperLeft.x;
   3013     y = sHandView->upperLeft.y;
   3014 
   3015     if (!(x > sMenuView->upperLeft.x && x < sMenuView->upperLeft.x + sMenuView->lowerRight.x
   3016           && y > sMenuView->upperLeft.y && y < sMenuView->upperLeft.y + sMenuView->lowerRight.y)) {
   3017         return;
   3018     }
   3019     ydiff = (y - sMenuView->upperLeft.y) / 25.0f;
   3020 
   3021     if (ydiff < sItemsInMenu) {
   3022         sMenuGadgets[ydiff]->drawFlags |= OBJ_HIGHLIGHTED;
   3023     }
   3024 }
   3025 
   3026 /* 2532D4 -> 2533DC */
   3027 void Unknown801A4B04(void) {
   3028     if (D_801A86AC != NULL) {
   3029         D_801A86AC->prevScaledTotal = 20.0f;
   3030     }
   3031     if (D_801A86A4 != NULL) {
   3032         D_801A86A4->prevScaledTotal = (f32)((sDLGenTime * 50.0f) + 20.0f);
   3033     }
   3034     if (D_801A86A8 != NULL) {
   3035         D_801A86A8->prevScaledTotal = (f32)((sDLGenTime * 50.0f) + 20.0f);
   3036     }
   3037     sDLGenTime = get_scaled_timer_total("dlgen");
   3038     sRCPTime = get_scaled_timer_total("rcp");
   3039     sDynamicsTime = get_scaled_timer_total("dynamics");
   3040 }
   3041 
   3042 /* 2533DC -> 253728; orig name: func_801A4C0C */
   3043 void update_cursor(void) {
   3044     if (sHandView == NULL)
   3045         return;
   3046 
   3047     if (gGdCtrl.currFrame - gGdCtrl.dragStartFrame < 300) {
   3048         sHandView->flags |= VIEW_UPDATE;
   3049         // by playing the sfx every frame, it will only play once as it
   3050         // never leaves the "sfx played last frame" buffer
   3051         gd_play_sfx(GD_SFX_HAND_APPEAR);
   3052     } else {
   3053         sHandView->flags &= ~VIEW_UPDATE;
   3054         gd_play_sfx(GD_SFX_HAND_DISAPPEAR);
   3055     }
   3056 
   3057     sHandView->upperLeft.x = (f32) gGdCtrl.csrX;
   3058     sHandView->upperLeft.y = (f32) gGdCtrl.csrY;
   3059 
   3060     // Make hand display list
   3061     begin_gddl(sHandShape->dlNums[gGdFrameBufNum]);
   3062     if (gGdCtrl.dragging) {
   3063         gd_put_sprite((u16 *) gd_texture_hand_closed, sHandView->upperLeft.x, sHandView->upperLeft.y, 0x20, 0x20);
   3064     } else {
   3065         gd_put_sprite((u16 *) gd_texture_hand_open, sHandView->upperLeft.x, sHandView->upperLeft.y, 0x20, 0x20);
   3066     }
   3067     gd_enddlsplist_parent();
   3068 
   3069     if (sHandView->upperLeft.x < sHandView->parent->upperLeft.x) {
   3070         sHandView->upperLeft.x = sHandView->parent->upperLeft.x;
   3071     }
   3072     if (sHandView->upperLeft.x > (sHandView->parent->upperLeft.x + sHandView->parent->lowerRight.x)) {
   3073         sHandView->upperLeft.x = sHandView->parent->upperLeft.x + sHandView->parent->lowerRight.x;
   3074     }
   3075 
   3076     if (sHandView->upperLeft.y < sHandView->parent->upperLeft.y) {
   3077         sHandView->upperLeft.y = sHandView->parent->upperLeft.y;
   3078     }
   3079     if (sHandView->upperLeft.y > (sHandView->parent->upperLeft.y + sHandView->parent->lowerRight.y)) {
   3080         sHandView->upperLeft.y = sHandView->parent->upperLeft.y + sHandView->parent->lowerRight.y;
   3081     }
   3082 }
   3083 
   3084 /* 253728 -> 2538E0 */
   3085 void Unknown801A4F58(void) {
   3086     register s16 *cbufOff; // a0
   3087     register s16 *cbufOn;  // a1
   3088     register u16 *zbuf;    // a2
   3089     register s16 colour;   // a3
   3090     register s16 r;        // t0
   3091     register s16 g;        // t1
   3092     register s16 b;        // t2
   3093     register s32 i;        // t3
   3094 
   3095     cbufOff = sScreenView->colourBufs[gGdFrameBufNum ^ 1];
   3096     cbufOn = sScreenView->colourBufs[gGdFrameBufNum];
   3097     zbuf = sScreenView->zbuf;
   3098 
   3099     for (i = 0; i < (320 * 240); i++) { // L801A4FCC
   3100         colour = cbufOff[i];
   3101         if (colour) {
   3102             r = (s16)(colour >> 11 & 0x1F);
   3103             g = (s16)(colour >> 6 & 0x1F);
   3104             b = (s16)(colour >> 1 & 0x1F);
   3105             if (--r < 0) {
   3106                 r = 0;
   3107             }
   3108             if (--g < 0) {
   3109                 g = 0;
   3110             }
   3111             if (--b < 0) {
   3112                 b = 0;
   3113             }
   3114 
   3115             colour = (s16)(r << 11 | g << 6 | b << 1);
   3116             cbufOff[i] = colour;
   3117             cbufOn[i] = colour;
   3118         } else { // L801A50D8
   3119             zbuf[i] = 0xFFFC;
   3120         }
   3121     }
   3122 }
   3123 
   3124 /* 2538E0 -> 253938 */
   3125 void Proc801A5110(struct ObjView *view) {
   3126     if (view->flags & VIEW_UPDATE) {
   3127         apply_to_obj_types_in_group(OBJ_TYPE_NETS, (applyproc_t) convert_net_verts, view->components);
   3128     }
   3129 }
   3130 
   3131 /* 253938 -> 2539DC; orig name: func_801A5168 */
   3132 void update_view_and_dl(struct ObjView *view) {
   3133     UNUSED u8 filler[4];
   3134     s32 prevFlags; // 18
   3135 
   3136     prevFlags = view->flags;
   3137     update_view(view);
   3138     if (prevFlags & VIEW_UPDATE) {
   3139         sCurrentGdDl = sMHeadMainDls[gGdFrameBufNum];
   3140         if (view->gdDlNum != 0) {
   3141             func_801A4848(view->gdDlNum);
   3142         }
   3143     }
   3144 }
   3145 
   3146 /**
   3147  * Unused - called by __main__
   3148  */
   3149 void func_801A520C(void) {
   3150     UNUSED u8 filler[8];
   3151 
   3152     start_timer("1frame");
   3153     start_timer("cpu");
   3154     stub_renderer_9();
   3155     reset_cur_dl_indices();
   3156     parse_p1_controller();
   3157     setup_timers();
   3158     start_timer("dlgen");
   3159     apply_to_obj_types_in_group(OBJ_TYPE_VIEWS, (applyproc_t) update_view_and_dl, gGdViewsGroup);
   3160     stop_timer("dlgen");
   3161     restart_timer("netupd");
   3162     if (!gGdCtrl.newStartPress) {
   3163         apply_to_obj_types_in_group(OBJ_TYPE_VIEWS, (applyproc_t) Proc801A5110, gGdViewsGroup);
   3164     }
   3165     split_timer("netupd");
   3166     split_timer("cpu");
   3167     func_801A4808();
   3168     restart_timer("cpu");
   3169     func_801A025C();
   3170     update_cursor();
   3171     func_801A4918();
   3172     stop_timer("1frame");
   3173     sTracked1FrameTime = get_scaled_timer_total("1frame");
   3174     split_timer("cpu");
   3175     func_801A01EC();
   3176 }
   3177 
   3178 /**
   3179  * Unused
   3180  */
   3181 void Unknown801A5344(void) {
   3182     if ((sActiveView = sScreenView) == NULL) {
   3183         return;
   3184     }
   3185 
   3186     reset_cur_dl_indices();
   3187     sScreenView->gdDlNum = gd_startdisplist(8);
   3188     start_view_dl(sScreenView);
   3189     gd_set_one_cycle();
   3190     gd_enddlsplist_parent();
   3191     func_801A4848(sScreenView->gdDlNum);
   3192     stub_renderer_9();
   3193     func_801A4808();
   3194     sScreenView->gdDlNum = 0;
   3195 }
   3196 
   3197 /* 253BC8 -> 2540E0 */
   3198 void gd_init(void) {
   3199     s32 i; // 34
   3200     UNUSED u8 filler[4];
   3201     s8 *data; // 2c
   3202 
   3203     imin("gd_init");
   3204     i = (u32)(sMemBlockPoolSize - DOUBLE_SIZE_ON_64_BIT(0x3E800));
   3205     data = gd_allocblock(i);
   3206     gd_add_mem_to_heap(i, data, 0x10);
   3207     sAlpha = (u16) 0xff;
   3208     D_801A867C = 0;
   3209     D_801A8680 = 0;
   3210     sTextureCount = 0;
   3211     gGdFrameBufNum = 0;
   3212     D_801A86BC = 1;
   3213     sItemsInMenu = 0;
   3214     sDebugViewsCount = 0;
   3215     sCurrDebugViewIndex = 0;
   3216     sGdDlCount = 0;
   3217     D_801A8674 = 0;
   3218     sLightId = 0;
   3219     sAmbScaleColour.r = 0.0f;
   3220     sAmbScaleColour.g = 0.0f;
   3221     sAmbScaleColour.b = 0.0f;
   3222 
   3223     for (i = 0; i < ARRAY_COUNT(sLightScaleColours); i++) {
   3224         sLightScaleColours[i].r = 1.0f;
   3225         sLightScaleColours[i].g = 0.0f;
   3226         sLightScaleColours[i].b = 0.0f;
   3227         sLightDirections[i].x = 0;
   3228         sLightDirections[i].y = 120;
   3229         sLightDirections[i].z = 0;
   3230     }
   3231 
   3232     sNumLights = NUMLIGHTS_2;
   3233     gd_set_identity_mat4(&sInitIdnMat4);
   3234     mat4_to_mtx(&sInitIdnMat4, &sIdnMtx);
   3235     remove_all_memtrackers();
   3236     null_obj_lists();
   3237     start_memtracker("total");
   3238     remove_all_timers();
   3239 
   3240     start_memtracker("Static DL");
   3241     sStaticDl = new_gd_dl(0, 1900, 4000, 1, 300, 8);
   3242     stop_memtracker("Static DL");
   3243 
   3244     start_memtracker("Dynamic DLs");
   3245     sDynamicMainDls[0] = new_gd_dl(1, 600, 10, 200, 10, 3);
   3246     sDynamicMainDls[1] = new_gd_dl(1, 600, 10, 200, 10, 3);
   3247     stop_memtracker("Dynamic DLs");
   3248 
   3249     sMHeadMainDls[0] = new_gd_dl(1, 100, 0, 0, 0, 0);
   3250     sMHeadMainDls[1] = new_gd_dl(1, 100, 0, 0, 0, 0);
   3251 
   3252     for (i = 0; i < ARRAY_COUNT(sViewDls); i++) {
   3253         sViewDls[i][0] = create_child_gdl(1, sDynamicMainDls[0]);
   3254         sViewDls[i][1] = create_child_gdl(1, sDynamicMainDls[1]);
   3255     }
   3256 
   3257     sScreenView =
   3258         make_view("screenview2", (VIEW_2_COL_BUF | VIEW_UNK_1000 | VIEW_COLOUR_BUF | VIEW_Z_BUF), 0, 0,
   3259                   0, 320, 240, NULL);
   3260     sScreenView->colour.r = 0.0f;
   3261     sScreenView->colour.g = 0.0f;
   3262     sScreenView->colour.b = 0.0f;
   3263     sScreenView->parent = sScreenView;
   3264     sScreenView->flags &= ~VIEW_UPDATE;
   3265     sActiveView = sScreenView;
   3266 
   3267     // Zero out controller inputs
   3268     data = (s8 *) &gGdCtrl;
   3269     for (i = 0; (u32) i < sizeof(struct GdControl); i++) {
   3270         *data++ = 0;
   3271     }
   3272 
   3273     // 801A5868
   3274     gGdCtrl.unk88 = 1.0f;
   3275     gGdCtrl.unkA0 = -45.0f;
   3276     gGdCtrl.unkAC = 45.0f;
   3277     gGdCtrl.unk00 = 2;
   3278     gGdCtrl.newStartPress = FALSE;
   3279     gGdCtrl.prevFrame = &gGdCtrlPrev;
   3280     gGdCtrl.csrX = 160;
   3281     gGdCtrl.csrY = 120;
   3282     gGdCtrl.dragStartFrame = -1000;
   3283     unusedDl801BB0AC = create_mtl_gddl(4);
   3284     imout();
   3285 }
   3286 
   3287 /**
   3288  * Unused - reverses the characters in `str`.
   3289  */
   3290 void reverse_string(char *str, s32 len) {
   3291     char buf[100];
   3292     s32 i;
   3293 
   3294     for (i = 0; i < len; i++) {
   3295         buf[i] = str[len - i - 1];
   3296     }
   3297 
   3298     for (i = 0; i < len; i++) {
   3299         str[i] = buf[i];
   3300     }
   3301 }
   3302 
   3303 /* 254168 -> 25417C */
   3304 void stub_renderer_12(UNUSED s8 *arg0) {
   3305 }
   3306 
   3307 /* 25417C -> 254190 */
   3308 void stub_renderer_13(UNUSED void *arg0) {
   3309 }
   3310 
   3311 /* 254190 -> 2541A4 */
   3312 void stub_renderer_14(UNUSED s8 *arg0) {
   3313 }
   3314 
   3315 /**
   3316  * Initializes the pick buffer. This functions like the `pick` or `gselect`
   3317  * functions from IRIS GL.
   3318  * @param buf  pointer to an array of 16-bit values
   3319  * @param len  maximum number of values to store
   3320  */
   3321 void init_pick_buf(s16 *buf, s32 len) {
   3322     buf[0] = 0;
   3323     buf[1] = 0;
   3324     sPickBufLen = len;
   3325     sPickBuf = buf;
   3326     sPickBufPosition = 0;
   3327 }
   3328 
   3329 /**
   3330  * Stores a 16-bit value into the pick buffer. This functions like the
   3331  * `pushname` function from IRIS GL.
   3332  */
   3333 void store_in_pickbuf(s16 data) {
   3334     sPickBuf[sPickBufPosition++] = data;
   3335 }
   3336 
   3337 /* 25421C -> 254250; orig name: func_801A5A4C
   3338 ** Divides by 3, since in the final game, only thing stored
   3339 ** in the pick buf is a tupple of three halves: (datasize, objtype, objnumber)
   3340 ** (datasize is always 2) */
   3341 s32 get_cur_pickbuf_offset(UNUSED s16 *arg0) {
   3342     return sPickBufPosition / 3;
   3343 }
   3344 
   3345 /* 254250 -> 254264 */
   3346 void stub_renderer_15(UNUSED u32 arg0) {
   3347 }
   3348 
   3349 /* 254264 -> 254278 */
   3350 void stub_renderer_16(UNUSED u32 arg0) {
   3351 }
   3352 
   3353 /* 254278 -> 254288 */
   3354 void stub_renderer_17(void) {
   3355 }
   3356 
   3357 /* 254288 -> 2542B0 */
   3358 void *Unknown801A5AB8(s32 texnum) {
   3359     return sLoadedTextures[texnum];
   3360 }
   3361 
   3362 /* 2542B0 -> 254328 */
   3363 void Unknown801A5AE0(s32 arg0) {
   3364     D_801BB018 = arg0;
   3365     if (D_801BB01C != D_801BB018) {
   3366         branch_cur_dl_to_num(sTextureDisplayLists[arg0]);
   3367         D_801BB01C = D_801BB018;
   3368     }
   3369 }
   3370 
   3371 /* 254328 -> 2543B8; orig name: func_801A5B58 */
   3372 void set_vtx_tc_buf(f32 tcS, f32 tcT) {
   3373     sVtxCvrtTCBuf[0] = (s16)(tcS * 512.0f);
   3374     sVtxCvrtTCBuf[1] = (s16)(tcT * 512.0f);
   3375 }
   3376 
   3377 /* 2543B8 -> 2543F4 */
   3378 void add_debug_view(struct ObjView *view) {
   3379     sDebugViews[sDebugViewsCount++] = view;
   3380 }
   3381 
   3382 /* 2543F4 -> 254450; orig name: Unknown801A5C24 */
   3383 union ObjVarVal *cvrt_val_to_kb(union ObjVarVal *dst, union ObjVarVal src) {
   3384     union ObjVarVal temp;
   3385 
   3386     temp.f = src.f / 1024.0; //? 1024.0f
   3387     return (*dst = temp, dst);
   3388 }
   3389 
   3390 /* 254450 -> 254560 */
   3391 void Unknown801A5C80(struct ObjGroup *parentGroup) {
   3392     struct ObjLabel *label;      // 3c
   3393     struct ObjGroup *debugGroup; // 38
   3394 
   3395     d_start_group("debugg");
   3396     label = (struct ObjLabel *) d_makeobj(D_LABEL, 0);
   3397     d_set_rel_pos(10.0f, 230.0f, 0.0f);
   3398     d_set_parm_ptr(PARM_PTR_CHAR, gd_strdup("FT %2.2f"));
   3399     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTracked1FrameTime);
   3400     label->unk30 = 3;
   3401     d_end_group("debugg");
   3402 
   3403     debugGroup = (struct ObjGroup *) d_use_obj("debugg");
   3404     make_view("debugview", (VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_1_CYCLE | VIEW_DRAW), 2, 0, 0, 320,
   3405               240, debugGroup);
   3406 
   3407     if (parentGroup != NULL) {
   3408         addto_group(parentGroup, &debugGroup->header);
   3409     }
   3410 }
   3411 
   3412 /* 254560 -> 2547C8 */
   3413 void Unknown801A5D90(struct ObjGroup *arg0) {
   3414     struct ObjLabel *mtLabel;  // 254
   3415     struct ObjGroup *labelgrp; // 250
   3416     struct ObjView *memview;   // 24c
   3417     s32 trackerNum;                 // memtracker id and/or i
   3418     s32 sp244;                 // label y position?
   3419     s32 sp240;                 // done checking all memtrakcers
   3420     s32 sp23C;                 // memtracker label made?
   3421     char mtStatsFmt[0x100];    // 13c
   3422     char groupId[0x100];       // 3c
   3423     struct MemTracker *mt;     // 38
   3424 
   3425     sp240 = FALSE;
   3426     trackerNum = -1;
   3427 
   3428     while (!sp240) {
   3429         sprintf(groupId, "memg%d\n", trackerNum);
   3430         d_start_group(AsDynName(groupId));
   3431         sp244 = 20;
   3432         sp23C = FALSE;
   3433 
   3434         for (;;) {
   3435             trackerNum++;
   3436             mt = get_memtracker_by_index(trackerNum);
   3437 
   3438             if (mt->name != NULL) {
   3439                 sprintf(mtStatsFmt, "%s  %%6.2fk", mt->name);
   3440                 mtLabel = (struct ObjLabel *) d_makeobj(D_LABEL, AsDynName(0));
   3441                 d_set_rel_pos(10.0f, sp244, 0.0f);
   3442                 d_set_parm_ptr(PARM_PTR_CHAR, gd_strdup(mtStatsFmt));
   3443                 d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &mt->total);
   3444                 mtLabel->unk30 = 3;
   3445                 d_add_valproc(cvrt_val_to_kb);
   3446                 sp23C = TRUE;
   3447                 sp244 += 14;
   3448                 if (sp244 > 200) {
   3449                     break;
   3450                 }
   3451             }
   3452 
   3453             if (trackerNum >= GD_NUM_MEM_TRACKERS) {
   3454                 sp240 = TRUE;
   3455                 break;
   3456             }
   3457         }
   3458 
   3459         d_end_group(AsDynName(groupId));
   3460         labelgrp = (struct ObjGroup *) d_use_obj(AsDynName(groupId));
   3461 
   3462         if (sp23C) {
   3463             memview = make_view("memview",
   3464                                 (VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_UNK_2000 | VIEW_UNK_4000
   3465                                  | VIEW_1_CYCLE | VIEW_DRAW),
   3466                                 2, 0, 10, 320, 200, labelgrp);
   3467             memview->colour.r = 0.0f;
   3468             memview->colour.g = 0.0f;
   3469             memview->colour.b = 0.0f;
   3470             addto_group(arg0, &labelgrp->header);
   3471             memview->flags &= ~VIEW_UPDATE;
   3472             add_debug_view(memview);
   3473         }
   3474     }
   3475 }
   3476 
   3477 /* 2547C8 -> 254AC0 */
   3478 void Unknown801A5FF8(struct ObjGroup *arg0) {
   3479     struct ObjView *menuview;      // 3c
   3480     UNUSED struct ObjLabel *label; // 38
   3481     struct ObjGroup *menugrp;      // 34
   3482     UNUSED u8 filler[8];
   3483 
   3484     d_start_group("menug");
   3485     sMenuGadgets[0] = d_makeobj(D_GADGET, "menu0");
   3486     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3487     d_set_world_pos(5.0f, 0.0f, 0.0f);
   3488     d_set_scale(100.0f, 20.0f, 0.0f);
   3489     d_set_type(6);
   3490     d_set_colour_num(2);
   3491     label = (struct ObjLabel *) d_makeobj(D_LABEL, AsDynName(0));
   3492     d_set_rel_pos(5.0f, 18.0f, 0.0f);
   3493     d_set_parm_ptr(PARM_PTR_CHAR, "ITEM 1");
   3494     d_add_valptr("menu0", 0x40000, 0, (uintptr_t) NULL);
   3495 
   3496     sMenuGadgets[1] = d_makeobj(D_GADGET, "menu1");
   3497     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3498     d_set_world_pos(5.0f, 25.0f, 0.0f);
   3499     d_set_scale(100.0f, 20.0f, 0.0f);
   3500     d_set_type(6);
   3501     d_set_colour_num(4);
   3502     label = (struct ObjLabel *) d_makeobj(D_LABEL, AsDynName(0));
   3503     d_set_rel_pos(5.0f, 18.0f, 0.0f);
   3504     d_set_parm_ptr(PARM_PTR_CHAR, "ITEM 2");
   3505     d_add_valptr("menu1", 0x40000, 0, (uintptr_t) NULL);
   3506 
   3507     sMenuGadgets[2] = d_makeobj(D_GADGET, "menu2");
   3508     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3509     d_set_world_pos(5.0f, 50.0f, 0.0f);
   3510     d_set_scale(100.0f, 20.0f, 0.0f);
   3511     d_set_type(6);
   3512     d_set_colour_num(3);
   3513     label = (struct ObjLabel *) d_makeobj(D_LABEL, AsDynName(0));
   3514     d_set_rel_pos(5.0f, 18.0f, 0.0f);
   3515     d_set_parm_ptr(PARM_PTR_CHAR, "ITEM 3");
   3516     d_add_valptr("menu2", 0x40000, 0, (uintptr_t) NULL);
   3517     sItemsInMenu = 3;
   3518     d_end_group("menug");
   3519 
   3520     menugrp = (struct ObjGroup *) d_use_obj("menug");
   3521     menuview = make_view(
   3522         "menuview", (VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_BORDERED | VIEW_UNK_2000 | VIEW_UNK_4000),
   3523         2, 100, 20, 110, 150, menugrp);
   3524     menuview->colour.r = 0.0f;
   3525     menuview->colour.g = 0.0f;
   3526     menuview->colour.b = 0.0f;
   3527     addto_group(arg0, &menugrp->header);
   3528     sMenuView = menuview;
   3529 }
   3530 
   3531 /* 254AC0 -> 254DFC; orig name: PutSprite */
   3532 void gd_put_sprite(u16 *sprite, s32 x, s32 y, s32 wx, s32 wy) {
   3533     s32 c; // 5c
   3534     s32 r; // 58
   3535 
   3536     gSPDisplayList(next_gfx(), osVirtualToPhysical(gd_dl_sprite_start_tex_block));
   3537     for (r = 0; r < wy; r += 32) {
   3538         for (c = 0; c < wx; c += 32) {
   3539              gDPLoadTextureBlock(next_gfx(), (r * 32) + sprite + c, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0,
   3540                 G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD)
   3541              gSPTextureRectangle(next_gfx(), x << 2, (y + r) << 2, (x + 32) << 2, (y + r + 32) << 2,
   3542                 G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
   3543         }
   3544     }
   3545 
   3546     gDPPipeSync(next_gfx());
   3547     gDPSetCycleType(next_gfx(), G_CYC_1CYCLE);
   3548     gDPSetRenderMode(next_gfx(), G_RM_AA_ZB_OPA_INTER, G_RM_NOOP2);
   3549     gSPTexture(next_gfx(), 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF);
   3550 }
   3551 
   3552 /* 254DFC -> 254F94; orig name: proc_dyn_list */
   3553 void gd_setup_cursor(struct ObjGroup *parentgrp) {
   3554     struct ObjView *mouseview; // 34
   3555     struct ObjGroup *mousegrp; // 30
   3556     UNUSED struct ObjNet *net; // 2c
   3557 
   3558     sHandShape = make_shape(0, "mouse");
   3559     sHandShape->dlNums[0] = gd_startdisplist(7);
   3560     gd_put_sprite((u16 *) gd_texture_hand_open, 100, 100, 32, 32);
   3561     gd_enddlsplist_parent();
   3562     sHandShape->dlNums[1] = gd_startdisplist(7);
   3563     gd_put_sprite((u16 *) gd_texture_hand_open, 100, 100, 32, 32);
   3564     gd_enddlsplist_parent();
   3565 
   3566     d_start_group("mouseg");
   3567     net = (struct ObjNet *) d_makeobj(D_NET, AsDynName(0));
   3568     d_set_init_pos(0.0f, 0.0f, 0.0f);
   3569     d_set_type(3);
   3570     d_set_shapeptrptr(&sHandShape);
   3571     d_end_group("mouseg");
   3572 
   3573     mousegrp = (struct ObjGroup *) d_use_obj("mouseg");
   3574     mouseview = make_view("mouseview",
   3575                           (VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_1_CYCLE | VIEW_MOVEMENT | VIEW_DRAW),
   3576                           2, 0, 0, 32, 32, mousegrp);
   3577     mouseview->flags &= ~VIEW_UPDATE;
   3578     sHandView = mouseview;
   3579     if (parentgrp != NULL) {
   3580         addto_group(parentgrp, &mousegrp->header);
   3581     }
   3582 }
   3583 
   3584 /**
   3585  * 254F94 -> 254FE4; orig name: Proc801A67C4
   3586  * This prints all timers if the view was not updated for a frame
   3587  **/
   3588 void view_proc_print_timers(struct ObjView *self) {
   3589     if (self->flags & VIEW_WAS_UPDATED) {
   3590         return;
   3591     }
   3592 
   3593     print_all_timers();
   3594 }
   3595 
   3596 /* 254FE4 -> 255600; not called; orig name: Unknown801A6814 */
   3597 void make_timer_gadgets(void) {
   3598     struct ObjLabel *timerLabel;
   3599     struct ObjGroup *timerg;
   3600     UNUSED u8 filler[4];
   3601     struct ObjView *timersview;
   3602     struct ObjGadget *bar1;
   3603     struct ObjGadget *bar2;
   3604     struct ObjGadget *bar3;
   3605     struct ObjGadget *bar4;
   3606     struct ObjGadget *bar5;
   3607     struct ObjGadget *bar6;
   3608     struct GdTimer *timer;
   3609     s32 i;
   3610     char timerNameBuf[0x20];
   3611 
   3612     d_start_group("timerg");
   3613     d_makeobj(D_GADGET, "bar1");
   3614     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3615     d_set_world_pos(20.0f, 5.0f, 0.0f);
   3616     d_set_scale(50.0f, 5.0f, 0.0f);
   3617     d_set_type(4);
   3618     d_set_parm_f(PARM_F_RANGE_MIN, 0);
   3619     d_set_parm_f(PARM_F_RANGE_MAX, sTimeScaleFactor);
   3620     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTimeScaleFactor);
   3621     bar1 = (struct ObjGadget *) d_use_obj("bar1");
   3622     bar1->colourNum = COLOUR_WHITE;
   3623 
   3624     d_makeobj(D_GADGET, "bar2");
   3625     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3626     d_set_world_pos(70.0f, 5.0f, 0.0f);
   3627     d_set_scale(50.0f, 5.0f, 0.0f);
   3628     d_set_type(4);
   3629     d_set_parm_f(PARM_F_RANGE_MIN, 0);
   3630     d_set_parm_f(PARM_F_RANGE_MAX, sTimeScaleFactor);
   3631     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTimeScaleFactor);
   3632     bar2 = (struct ObjGadget *) d_use_obj("bar2");
   3633     bar2->colourNum = COLOUR_PINK;
   3634 
   3635     d_makeobj(D_GADGET, "bar3");
   3636     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3637     d_set_world_pos(120.0f, 5.0f, 0.0f);
   3638     d_set_scale(50.0f, 5.0f, 0.0f);
   3639     d_set_type(4);
   3640     d_set_parm_f(PARM_F_RANGE_MIN, 0);
   3641     d_set_parm_f(PARM_F_RANGE_MAX, sTimeScaleFactor);
   3642     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTimeScaleFactor);
   3643     bar3 = (struct ObjGadget *) d_use_obj("bar3");
   3644     bar3->colourNum = COLOUR_WHITE;
   3645 
   3646     d_makeobj(D_GADGET, "bar4");
   3647     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3648     d_set_world_pos(170.0f, 5.0f, 0.0f);
   3649     d_set_scale(50.0f, 5.0f, 0.0f);
   3650     d_set_type(4);
   3651     d_set_parm_f(PARM_F_RANGE_MIN, 0);
   3652     d_set_parm_f(PARM_F_RANGE_MAX, sTimeScaleFactor);
   3653     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTimeScaleFactor);
   3654     bar4 = (struct ObjGadget *) d_use_obj("bar4");
   3655     bar4->colourNum = COLOUR_PINK;
   3656 
   3657     d_makeobj(D_GADGET, "bar5");
   3658     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3659     d_set_world_pos(220.0f, 5.0f, 0.0f);
   3660     d_set_scale(50.0f, 5.0f, 0.0f);
   3661     d_set_type(4);
   3662     d_set_parm_f(PARM_F_RANGE_MIN, 0);
   3663     d_set_parm_f(PARM_F_RANGE_MAX, sTimeScaleFactor);
   3664     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTimeScaleFactor);
   3665     bar5 = (struct ObjGadget *) d_use_obj("bar5");
   3666     bar5->colourNum = COLOUR_WHITE;
   3667 
   3668     d_makeobj(D_GADGET, "bar6");
   3669     d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3670     d_set_world_pos(270.0f, 5.0f, 0.0f);
   3671     d_set_scale(50.0f, 5.0f, 0.0f);
   3672     d_set_type(4);
   3673     d_set_parm_f(PARM_F_RANGE_MIN, 0);
   3674     d_set_parm_f(PARM_F_RANGE_MAX, sTimeScaleFactor);
   3675     d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &sTimeScaleFactor);
   3676     bar6 = (struct ObjGadget *) d_use_obj("bar6");
   3677     bar6->colourNum = COLOUR_PINK;
   3678 
   3679     for (i = 0; i < GD_NUM_TIMERS; i++) {
   3680         sprintf(timerNameBuf, "tim%d\n", i);
   3681 
   3682         timer = get_timernum(i);
   3683 
   3684         d_makeobj(D_GADGET, timerNameBuf);
   3685         d_set_obj_draw_flag(OBJ_IS_GRABBABLE);
   3686         d_set_world_pos(20.0f, (f32)((i * 15) + 15), 0.0f);
   3687         d_set_scale(50.0f, 14.0f, 0);
   3688         d_set_type(4);
   3689         d_set_parm_f(PARM_F_RANGE_MIN, 0.0f);
   3690         d_set_parm_f(PARM_F_RANGE_MAX, 1.0f);
   3691         d_add_valptr(NULL, 0, OBJ_VALUE_FLOAT, (uintptr_t) &timer->prevScaledTotal);
   3692         sTimerGadgets[i] = (struct ObjGadget *) d_use_obj(timerNameBuf);
   3693         sTimerGadgets[i]->colourNum = timer->gadgetColourNum;
   3694 
   3695         timerLabel = (struct ObjLabel *) d_makeobj(D_LABEL, AsDynName(0));
   3696         d_set_rel_pos(5.0f, 14.0f, 0);
   3697         d_set_parm_ptr(PARM_PTR_CHAR, (void *) timer->name);
   3698         d_add_valptr(timerNameBuf, 0x40000, 0, (uintptr_t) NULL);
   3699         timerLabel->unk30 = 3;
   3700     }
   3701 
   3702     d_end_group("timerg");
   3703     timerg = (struct ObjGroup *) d_use_obj("timerg");
   3704     timersview = make_view(
   3705         "timersview", (VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_1_CYCLE | VIEW_MOVEMENT | VIEW_DRAW), 2,
   3706         0, 10, 320, 270, timerg);
   3707     timersview->colour.r = 0.0f;
   3708     timersview->colour.g = 0.0f;
   3709     timersview->colour.b = 0.0f;
   3710     timersview->flags &= ~VIEW_UPDATE;
   3711     timersview->proc = view_proc_print_timers;
   3712     add_debug_view(timersview);
   3713 
   3714     return;
   3715 }
   3716 
   3717 /* 255600 -> 255614 */
   3718 void stub_renderer_18(UNUSED u32 a0) {
   3719 }
   3720 
   3721 /* 255614 -> 255628 */
   3722 void stub_renderer_19(UNUSED u32 a0) {
   3723 }
   3724 
   3725 #ifndef NO_SEGMENTED_MEMORY
   3726 /**
   3727  * Copies `size` bytes of data from ROM address `romAddr` to RAM address `vAddr`.
   3728  */
   3729 static void gd_block_dma(u32 romAddr, void *vAddr, s32 size) {
   3730     s32 blockSize;
   3731 
   3732     do {
   3733         if ((blockSize = size) > 0x1000) {
   3734             blockSize = 0x1000;
   3735         }
   3736 
   3737         osPiStartDma(&sGdDMAReqMesg, OS_MESG_PRI_NORMAL, OS_READ, romAddr, vAddr, blockSize, &sGdDMAQueue);
   3738         osRecvMesg(&sGdDMAQueue, &sGdDMACompleteMsg, OS_MESG_BLOCK);
   3739         romAddr += blockSize;
   3740         vAddr = (void *) ((uintptr_t) vAddr + blockSize);
   3741         size -= 0x1000;
   3742     } while (size > 0);
   3743 }
   3744 
   3745 /**
   3746  * Loads the specified DynList from ROM and processes it.
   3747  */
   3748 struct GdObj *load_dynlist(struct DynList *dynlist) {
   3749     u32 segSize;
   3750     u8 *allocSegSpace;
   3751     void *allocPtr;
   3752     uintptr_t dynlistSegStart;
   3753     uintptr_t dynlistSegEnd;
   3754     s32 i;
   3755     s32 tlbEntries;
   3756     struct GdObj *loadedList;
   3757 
   3758     i = -1;
   3759 
   3760     // Make sure the dynlist exists
   3761     while (sDynLists[++i].list != NULL) {
   3762         if (sDynLists[i].list == dynlist) {
   3763             break;
   3764         }
   3765     }
   3766     if (sDynLists[i].list == NULL) {
   3767         fatal_printf("load_dynlist() ptr not found in any banks");
   3768     }
   3769 
   3770     switch (sDynLists[i].flag) {
   3771         case STD_LIST_BANK:
   3772             dynlistSegStart = (uintptr_t) _gd_dynlistsSegmentRomStart;
   3773             dynlistSegEnd = (uintptr_t) _gd_dynlistsSegmentRomEnd;
   3774             break;
   3775         default:
   3776             fatal_printf("load_dynlist() unkown bank");
   3777     }
   3778 
   3779 #define PAGE_SIZE 65536  // size of a 64K TLB page
   3780 
   3781     segSize = dynlistSegEnd - dynlistSegStart;
   3782     allocSegSpace = gd_malloc_temp(segSize + PAGE_SIZE);
   3783 
   3784     if ((allocPtr = (void *) allocSegSpace) == NULL) {
   3785         fatal_printf("Not enough DRAM for DATA segment \n");
   3786     }
   3787 
   3788     allocSegSpace = (u8 *) (((uintptr_t) allocSegSpace + PAGE_SIZE) & 0xFFFF0000);
   3789 
   3790     // Copy the dynlist data from ROM
   3791     gd_block_dma(dynlistSegStart, (void *) allocSegSpace, segSize);
   3792 
   3793     osUnmapTLBAll();
   3794 
   3795     tlbEntries = (segSize / PAGE_SIZE) / 2 + 1;
   3796     if (tlbEntries >= 31) {
   3797         fatal_printf("load_dynlist() too many TLBs");
   3798     }
   3799 
   3800     // Map virtual address 0x04000000 to `allocSegSpace`
   3801     for (i = 0; i < tlbEntries; i++) {
   3802         osMapTLB(i, OS_PM_64K,
   3803             (void *) (uintptr_t) (0x04000000 + (i * 2 * PAGE_SIZE)),  // virtual address to map
   3804             GD_LOWER_24(((uintptr_t) allocSegSpace) + (i * 2 * PAGE_SIZE) + 0),  // even page address
   3805             GD_LOWER_24(((uintptr_t) allocSegSpace) + (i * 2 * PAGE_SIZE) + PAGE_SIZE),  // odd page address
   3806             -1);
   3807     }
   3808 
   3809 #undef PAGE_SIZE
   3810 
   3811     // process the dynlist
   3812     loadedList = proc_dynlist(dynlist);
   3813 
   3814     gd_free(allocPtr);
   3815     osUnmapTLBAll();
   3816 
   3817     return loadedList;
   3818 }
   3819 #else
   3820 struct GdObj *load_dynlist(struct DynList *dynlist) {
   3821     return proc_dynlist(dynlist);
   3822 }
   3823 #endif
   3824 
   3825 /**
   3826  * Unused (not called)
   3827  */
   3828 void stub_renderer_20(UNUSED u32 a0) {
   3829 }
   3830 
   3831 /**
   3832  * Unused (not called)
   3833  */
   3834 void func_801A71CC(struct ObjNet *net) {
   3835     s32 i; // spB4
   3836     s32 j; // spB0
   3837     f32 spAC;
   3838     f32 spA8;
   3839     struct GdBoundingBox bbox;
   3840     UNUSED u8 filler1[4];
   3841     struct ObjZone *sp88;
   3842     register struct ListNode *link;  // s0 (84)
   3843     s32 sp80;                     // linked planes contained in zone?
   3844     s32 sp7C;                     // linked planes in net count?
   3845     register struct ListNode *link1; // s1 (78)
   3846     register struct ListNode *link2; // s2 (74)
   3847     register struct ListNode *link3; // s3 (70)
   3848     struct GdVec3f sp64;
   3849     UNUSED u8 filler2[4];
   3850     struct ObjPlane *plane; // 5c
   3851     UNUSED u8 filler3[4];
   3852     struct ObjZone *linkedZone; // 54
   3853     UNUSED u8 filler4[4];
   3854     struct ObjPlane *planeL2; // 4c
   3855     UNUSED u8 filler5[4];
   3856     struct ObjPlane *planeL3; // 44
   3857 
   3858     if (net->unk21C == NULL) {
   3859         net->unk21C = make_group(0);
   3860     }
   3861 
   3862     gd_print_bounding_box("making zones for net=", &net->boundingBox);
   3863 
   3864     sp64.x = (ABS(net->boundingBox.minX) + ABS(net->boundingBox.maxX)) / 16.0f;
   3865     sp64.z = (ABS(net->boundingBox.minZ) + ABS(net->boundingBox.maxZ)) / 16.0f;
   3866 
   3867     spA8 = net->boundingBox.minZ + sp64.z / 2.0f;
   3868 
   3869     for (i = 0; i < 16; i++) {
   3870         spAC = net->boundingBox.minX + sp64.x / 2.0f;
   3871 
   3872         for (j = 0; j < 16; j++) {
   3873             bbox.minX = spAC - (sp64.x / 2.0f);
   3874             bbox.minY = 0.0f;
   3875             bbox.minZ = spA8 - (sp64.z / 2.0f);
   3876 
   3877             bbox.maxX = spAC + (sp64.x / 2.0f);
   3878             bbox.maxY = 0.0f;
   3879             bbox.maxZ = spA8 + (sp64.z / 2.0f);
   3880 
   3881             sp88 = make_zone(NULL, &bbox, NULL);
   3882             addto_group(net->unk21C, &sp88->header);
   3883             sp88->unk2C = make_group(0);
   3884 
   3885             spAC += sp64.x;
   3886         }
   3887         spA8 += sp64.z;
   3888     }
   3889 
   3890     for (link = net->unk1CC->firstMember; link != NULL; link = link->next) {
   3891         plane = (struct ObjPlane *) link->obj;
   3892         plane->unk18 = FALSE;
   3893     }
   3894 
   3895     i = 0; // acts as Zone N here... kinda
   3896     for (link1 = net->unk21C->firstMember; link1 != NULL; link1 = link1->next) {
   3897         linkedZone = (struct ObjZone *) link1->obj;
   3898         sp88 = linkedZone;
   3899         sp7C = 0;
   3900         sp80 = 0;
   3901 
   3902         for (link2 = net->unk1CC->firstMember; link2 != NULL; link2 = link2->next) {
   3903             planeL2 = (struct ObjPlane *) link2->obj;
   3904             sp7C++;
   3905             if (gd_plane_point_within(&planeL2->boundingBox, &sp88->boundingBox)) {
   3906                 planeL2->unk18 = TRUE;
   3907                 addto_group(sp88->unk2C, &planeL2->header);
   3908                 sp80++;
   3909             }
   3910         }
   3911 
   3912         if (sp80 == 0) {
   3913             stub_objects_1(net->unk21C, &linkedZone->header); // stubbed fatal function?
   3914         } else {
   3915             gd_printf("%d/%d planes in zone %d\n", sp80, sp7C, i++);
   3916         }
   3917     }
   3918 
   3919     for (link3 = net->unk1CC->firstMember; link3 != NULL; link3 = link3->next) {
   3920         planeL3 = (struct ObjPlane *) link3->obj;
   3921 
   3922         if (!planeL3->unk18) {
   3923             gd_print_bounding_box("plane=", &planeL3->boundingBox);
   3924             fatal_printf("plane not in any zones\n");
   3925         }
   3926     }
   3927 }
   3928 
   3929 /* 255EB0 -> 255EC0 */
   3930 void stub_renderer_21(void) {
   3931 }