sm64

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

game_init.c (25909B)


      1 #include <ultra64.h>
      2 
      3 #include "sm64.h"
      4 #include "gfx_dimensions.h"
      5 #include "audio/external.h"
      6 #include "buffers/buffers.h"
      7 #include "buffers/gfx_output_buffer.h"
      8 #include "buffers/framebuffers.h"
      9 #include "buffers/zbuffer.h"
     10 #include "engine/level_script.h"
     11 #include "game_init.h"
     12 #include "main.h"
     13 #include "memory.h"
     14 #include "profiler.h"
     15 #include "save_file.h"
     16 #include "seq_ids.h"
     17 #include "sound_init.h"
     18 #include "print.h"
     19 #include "segment2.h"
     20 #include "segment_symbols.h"
     21 #include "rumble_init.h"
     22 
     23 // First 3 controller slots
     24 struct Controller gControllers[3];
     25 
     26 // Gfx handlers
     27 struct SPTask *gGfxSPTask;
     28 Gfx *gDisplayListHead;
     29 u8 *gGfxPoolEnd;
     30 struct GfxPool *gGfxPool;
     31 
     32 // OS Controllers
     33 OSContStatus gControllerStatuses[4];
     34 OSContPad gControllerPads[4];
     35 u8 gControllerBits;
     36 s8 gEepromProbe; // Save Data Probe
     37 
     38 // OS Messages
     39 OSMesgQueue gGameVblankQueue;
     40 OSMesgQueue gGfxVblankQueue;
     41 OSMesg gGameMesgBuf[1];
     42 OSMesg gGfxMesgBuf[1];
     43 
     44 // Vblank Handler
     45 struct VblankHandler gGameVblankHandler;
     46 
     47 // Buffers
     48 uintptr_t gPhysicalFramebuffers[3];
     49 uintptr_t gPhysicalZBuffer;
     50 
     51 // Mario Anims and Demo allocation
     52 void *gMarioAnimsMemAlloc;
     53 void *gDemoInputsMemAlloc;
     54 struct DmaHandlerList gMarioAnimsBuf;
     55 struct DmaHandlerList gDemoInputsBuf;
     56 
     57 // fillers
     58 UNUSED static u8 sfillerGameInit[0x90];
     59 static s32 sUnusedGameInitValue = 0;
     60 
     61 // General timer that runs as the game starts
     62 u32 gGlobalTimer = 0;
     63 
     64 // Framebuffer rendering values (max 3)
     65 u16 sRenderedFramebuffer = 0;
     66 u16 sRenderingFramebuffer = 0;
     67 
     68 // Goddard Vblank Function Caller
     69 void (*gGoddardVblankCallback)(void) = NULL;
     70 
     71 // Defined controller slots
     72 struct Controller *gPlayer1Controller = &gControllers[0];
     73 struct Controller *gPlayer2Controller = &gControllers[1];
     74 struct Controller *gPlayer3Controller = &gControllers[2]; // Probably debug only, see note below
     75 
     76 // Title Screen Demo Handler
     77 struct DemoInput *gCurrDemoInput = NULL;
     78 u16 gDemoInputListID = 0;
     79 struct DemoInput gRecordedDemoInput = { 0 };
     80 
     81 // Display
     82 // ----------------------------------------------------------------------------------------------------
     83 
     84 /**
     85  * Sets the initial RDP (Reality Display Processor) rendering settings.
     86  */
     87 void init_rdp(void) {
     88     gDPPipeSync(gDisplayListHead++);
     89     gDPPipelineMode(gDisplayListHead++, G_PM_1PRIMITIVE);
     90 
     91     gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
     92     gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
     93 
     94     gDPSetTextureLOD(gDisplayListHead++, G_TL_TILE);
     95     gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
     96     gDPSetTextureDetail(gDisplayListHead++, G_TD_CLAMP);
     97     gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
     98     gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP);
     99     gDPSetTextureConvert(gDisplayListHead++, G_TC_FILT);
    100 
    101     gDPSetCombineKey(gDisplayListHead++, G_CK_NONE);
    102     gDPSetAlphaCompare(gDisplayListHead++, G_AC_NONE);
    103     gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
    104     gDPSetColorDither(gDisplayListHead++, G_CD_MAGICSQ);
    105     gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
    106 
    107 #if defined(VERSION_SH) || defined(VERSION_CN)
    108     gDPSetAlphaDither(gDisplayListHead++, G_AD_PATTERN);
    109 #endif
    110     gDPPipeSync(gDisplayListHead++);
    111 }
    112 
    113 /**
    114  * Sets the initial RSP (Reality Signal Processor) settings.
    115  */
    116 void init_rsp(void) {
    117     gSPClearGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CULL_BOTH | G_FOG
    118                         | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD);
    119 
    120     gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CULL_BACK | G_LIGHTING);
    121 
    122     gSPNumLights(gDisplayListHead++, NUMLIGHTS_1);
    123     gSPTexture(gDisplayListHead++, 0, 0, 0, G_TX_RENDERTILE, G_OFF);
    124 
    125     // @bug Failing to set the clip ratio will result in warped triangles in F3DEX2
    126     // without this change: https://jrra.zone/n64/doc/n64man/gsp/gSPClipRatio.htm
    127 #ifdef F3DEX_GBI_2
    128     gSPClipRatio(gDisplayListHead++, FRUSTRATIO_1);
    129 #endif
    130 }
    131 
    132 /**
    133  * Initialize the z buffer for the current frame.
    134  */
    135 void init_z_buffer(void) {
    136     gDPPipeSync(gDisplayListHead++);
    137 
    138     gDPSetDepthSource(gDisplayListHead++, G_ZS_PIXEL);
    139     gDPSetDepthImage(gDisplayListHead++, gPhysicalZBuffer);
    140 
    141     gDPSetColorImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, gPhysicalZBuffer);
    142     gDPSetFillColor(gDisplayListHead++,
    143                     GPACK_ZDZ(G_MAXFBZ, 0) << 16 | GPACK_ZDZ(G_MAXFBZ, 0));
    144 
    145     gDPFillRectangle(gDisplayListHead++, 0, BORDER_HEIGHT, SCREEN_WIDTH - 1,
    146                      SCREEN_HEIGHT - 1 - BORDER_HEIGHT);
    147 }
    148 
    149 /**
    150  * Tells the RDP which of the three framebuffers it shall draw to.
    151  */
    152 void select_framebuffer(void) {
    153     gDPPipeSync(gDisplayListHead++);
    154 
    155     gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
    156     gDPSetColorImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH,
    157                      gPhysicalFramebuffers[sRenderingFramebuffer]);
    158     gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH,
    159                   SCREEN_HEIGHT - BORDER_HEIGHT);
    160 }
    161 
    162 /**
    163  * Clear the framebuffer and fill it with a 32-bit color.
    164  * Information about the color argument: https://jrra.zone/n64/doc/n64man/gdp/gDPSetFillColor.htm
    165  */
    166 void clear_framebuffer(s32 color) {
    167     gDPPipeSync(gDisplayListHead++);
    168 
    169     gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
    170     gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
    171 
    172     gDPSetFillColor(gDisplayListHead++, color);
    173     gDPFillRectangle(gDisplayListHead++,
    174                      GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT,
    175                      GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - BORDER_HEIGHT - 1);
    176 
    177     gDPPipeSync(gDisplayListHead++);
    178 
    179     gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
    180 }
    181 
    182 /**
    183  * Resets the viewport, readying it for the final image.
    184  */
    185 void clear_viewport(Vp *viewport, s32 color) {
    186     s16 vpUlx = (viewport->vp.vtrans[0] - viewport->vp.vscale[0]) / 4 + 1;
    187     s16 vpUly = (viewport->vp.vtrans[1] - viewport->vp.vscale[1]) / 4 + 1;
    188     s16 vpLrx = (viewport->vp.vtrans[0] + viewport->vp.vscale[0]) / 4 - 2;
    189     s16 vpLry = (viewport->vp.vtrans[1] + viewport->vp.vscale[1]) / 4 - 2;
    190 
    191 #ifdef WIDESCREEN
    192     vpUlx = GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(vpUlx);
    193     vpLrx = GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(SCREEN_WIDTH - vpLrx);
    194 #endif
    195 
    196     gDPPipeSync(gDisplayListHead++);
    197 
    198     gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
    199     gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
    200 
    201     gDPSetFillColor(gDisplayListHead++, color);
    202     gDPFillRectangle(gDisplayListHead++, vpUlx, vpUly, vpLrx, vpLry);
    203 
    204     gDPPipeSync(gDisplayListHead++);
    205 
    206     gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
    207 }
    208 
    209 /**
    210  * Draw the horizontal screen borders.
    211  */
    212 void draw_screen_borders(void) {
    213     gDPPipeSync(gDisplayListHead++);
    214 
    215     gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    216     gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
    217     gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
    218 
    219     gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(0, 0, 0, 0) << 16 | GPACK_RGBA5551(0, 0, 0, 0));
    220 
    221 #if BORDER_HEIGHT != 0
    222     gDPFillRectangle(gDisplayListHead++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), 0,
    223                      GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, BORDER_HEIGHT - 1);
    224     gDPFillRectangle(gDisplayListHead++,
    225                      GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), SCREEN_HEIGHT - BORDER_HEIGHT,
    226                      GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - 1);
    227 #endif
    228 }
    229 
    230 /**
    231  * Defines the viewport scissoring rectangle.
    232  * Scissoring: https://jrra.zone/n64/doc/pro-man/pro12/12-03.htm#01
    233  */
    234 void make_viewport_clip_rect(Vp *viewport) {
    235     s16 vpUlx = (viewport->vp.vtrans[0] - viewport->vp.vscale[0]) / 4 + 1;
    236     s16 vpPly = (viewport->vp.vtrans[1] - viewport->vp.vscale[1]) / 4 + 1;
    237     s16 vpLrx = (viewport->vp.vtrans[0] + viewport->vp.vscale[0]) / 4 - 1;
    238     s16 vpLry = (viewport->vp.vtrans[1] + viewport->vp.vscale[1]) / 4 - 1;
    239 
    240     gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, vpUlx, vpPly, vpLrx, vpLry);
    241 }
    242 
    243 /**
    244  * Initializes the Fast3D OSTask structure.
    245  * If you plan on using gSPLoadUcode, make sure to add OS_TASK_LOADABLE to the flags member.
    246  */
    247 void create_gfx_task_structure(void) {
    248     s32 entries = gDisplayListHead - gGfxPool->buffer;
    249 
    250     gGfxSPTask->msgqueue = &gGfxVblankQueue;
    251     gGfxSPTask->msg = (OSMesg) 2;
    252     gGfxSPTask->task.t.type = M_GFXTASK;
    253     gGfxSPTask->task.t.ucode_boot = rspF3DBootStart;
    254     gGfxSPTask->task.t.ucode_boot_size = ((u8 *) rspF3DBootEnd - (u8 *) rspF3DBootStart);
    255     gGfxSPTask->task.t.flags = 0;
    256     gGfxSPTask->task.t.ucode = rspF3DStart;
    257     gGfxSPTask->task.t.ucode_data = rspF3DDataStart;
    258     gGfxSPTask->task.t.ucode_size = SP_UCODE_SIZE; // (this size is ignored)
    259     gGfxSPTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE;
    260     gGfxSPTask->task.t.dram_stack = (u64 *) gGfxSPTaskStack;
    261     gGfxSPTask->task.t.dram_stack_size = SP_DRAM_STACK_SIZE8;
    262     gGfxSPTask->task.t.output_buff = gGfxSPTaskOutputBuffer;
    263     gGfxSPTask->task.t.output_buff_size =
    264         (u64 *)((u8 *) gGfxSPTaskOutputBuffer + sizeof(gGfxSPTaskOutputBuffer));
    265     gGfxSPTask->task.t.data_ptr = (u64 *) &gGfxPool->buffer;
    266     gGfxSPTask->task.t.data_size = entries * sizeof(Gfx);
    267     gGfxSPTask->task.t.yield_data_ptr = (u64 *) gGfxSPTaskYieldBuffer;
    268     gGfxSPTask->task.t.yield_data_size = OS_YIELD_DATA_SIZE;
    269 }
    270 
    271 /**
    272  * Set default RCP (Reality Co-Processor) settings.
    273  */
    274 void init_rcp(void) {
    275     move_segment_table_to_dmem();
    276     init_rdp();
    277     init_rsp();
    278     init_z_buffer();
    279     select_framebuffer();
    280 }
    281 
    282 /**
    283  * End the master display list and initialize the graphics task structure for the next frame to be rendered.
    284  */
    285 void end_master_display_list(void) {
    286     draw_screen_borders();
    287     if (gShowProfiler) {
    288         draw_profiler();
    289     }
    290 
    291     gDPFullSync(gDisplayListHead++);
    292     gSPEndDisplayList(gDisplayListHead++);
    293 
    294     create_gfx_task_structure();
    295 }
    296 
    297 /**
    298  * Draw the bars that appear when the N64 is soft reset.
    299  */
    300 void draw_reset_bars(void) {
    301     s32 width, height;
    302     s32 fbNum;
    303     u64 *fbPtr;
    304 
    305     if (gResetTimer != 0 && gNmiResetBarsTimer < 15) {
    306         if (sRenderedFramebuffer == 0) {
    307             fbNum = 2;
    308         } else {
    309             fbNum = sRenderedFramebuffer - 1;
    310         }
    311 
    312         fbPtr = (u64 *) PHYSICAL_TO_VIRTUAL(gPhysicalFramebuffers[fbNum]);
    313         fbPtr += gNmiResetBarsTimer++ * (SCREEN_WIDTH / 4);
    314 
    315         for (width = 0; width < ((SCREEN_HEIGHT / 16) + 1); width++) {
    316             // Loop must be one line to match on -O2
    317             for (height = 0; height < (SCREEN_WIDTH / 4); height++) *fbPtr++ = 0;
    318             fbPtr += ((SCREEN_WIDTH / 4) * 14);
    319         }
    320     }
    321 
    322     osWritebackDCacheAll();
    323     osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
    324     osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
    325 }
    326 
    327 /**
    328  * Initial settings for the first rendered frame.
    329  */
    330 void render_init(void) {
    331     gGfxPool = &gGfxPools[0];
    332     set_segment_base_addr(1, gGfxPool->buffer);
    333     gGfxSPTask = &gGfxPool->spTask;
    334     gDisplayListHead = gGfxPool->buffer;
    335     gGfxPoolEnd = (u8 *)(gGfxPool->buffer + GFX_POOL_SIZE);
    336     init_rcp();
    337     clear_framebuffer(0);
    338     end_master_display_list();
    339     exec_display_list(&gGfxPool->spTask);
    340 
    341     sRenderingFramebuffer++;
    342     gGlobalTimer++;
    343 }
    344 
    345 /**
    346  * Selects the location of the F3D output buffer (gDisplayListHead).
    347  */
    348 void select_gfx_pool(void) {
    349     gGfxPool = &gGfxPools[gGlobalTimer % ARRAY_COUNT(gGfxPools)];
    350     set_segment_base_addr(1, gGfxPool->buffer);
    351     gGfxSPTask = &gGfxPool->spTask;
    352     gDisplayListHead = gGfxPool->buffer;
    353     gGfxPoolEnd = (u8 *) (gGfxPool->buffer + GFX_POOL_SIZE);
    354 }
    355 
    356 /**
    357  * This function:
    358  * - Sends the current master display list out to be rendered.
    359  * - Tells the VI which color framebuffer to be displayed.
    360  * - Yields to the VI framerate twice, locking the game at 30 FPS.
    361  * - Selects which framebuffer will be rendered and displayed to next time.
    362  */
    363 void display_and_vsync(void) {
    364     profiler_log_thread5_time(BEFORE_DISPLAY_LISTS);
    365     osRecvMesg(&gGfxVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
    366     if (gGoddardVblankCallback != NULL) {
    367         gGoddardVblankCallback();
    368         gGoddardVblankCallback = NULL;
    369     }
    370     exec_display_list(&gGfxPool->spTask);
    371     profiler_log_thread5_time(AFTER_DISPLAY_LISTS);
    372     osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
    373     osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFramebuffers[sRenderedFramebuffer]));
    374     profiler_log_thread5_time(THREAD5_END);
    375     osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
    376     if (++sRenderedFramebuffer == 3) {
    377         sRenderedFramebuffer = 0;
    378     }
    379     if (++sRenderingFramebuffer == 3) {
    380         sRenderingFramebuffer = 0;
    381     }
    382     gGlobalTimer++;
    383 }
    384 
    385 // Controls
    386 // ----------------------------------------------------------------------------------------------------
    387 
    388 /**
    389  * This function records distinct inputs over a 255-frame interval to RAM locations and was likely
    390  * used to record the demo sequences seen in the final game. This function is unused.
    391  */
    392 UNUSED static void record_demo(void) {
    393     // Record the player's button mask and current rawStickX and rawStickY.
    394     u8 buttonMask =
    395         ((gPlayer1Controller->buttonDown & (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON)) >> 8)
    396         | (gPlayer1Controller->buttonDown & (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS));
    397     s8 rawStickX = gPlayer1Controller->rawStickX;
    398     s8 rawStickY = gPlayer1Controller->rawStickY;
    399 
    400     // If the stick is in deadzone, set its value to 0 to
    401     // nullify the effects. We do not record deadzone inputs.
    402     if (rawStickX > -8 && rawStickX < 8) {
    403         rawStickX = 0;
    404     }
    405 
    406     if (rawStickY > -8 && rawStickY < 8) {
    407         rawStickY = 0;
    408     }
    409 
    410     // Record the distinct input and timer so long as they are unique.
    411     // If the timer hits 0xFF, reset the timer for the next demo input.
    412     if (gRecordedDemoInput.timer == 0xFF || buttonMask != gRecordedDemoInput.buttonMask
    413         || rawStickX != gRecordedDemoInput.rawStickX || rawStickY != gRecordedDemoInput.rawStickY) {
    414         gRecordedDemoInput.timer = 0;
    415         gRecordedDemoInput.buttonMask = buttonMask;
    416         gRecordedDemoInput.rawStickX = rawStickX;
    417         gRecordedDemoInput.rawStickY = rawStickY;
    418     }
    419     gRecordedDemoInput.timer++;
    420 }
    421 
    422 /**
    423  * Take the updated controller struct and calculate the new x, y, and distance floats.
    424  */
    425 void adjust_analog_stick(struct Controller *controller) {
    426     UNUSED u8 filler[8];
    427 
    428     // Reset the controller's x and y floats.
    429     controller->stickX = 0;
    430     controller->stickY = 0;
    431 
    432     // Modulate the rawStickX and rawStickY to be the new f32 values by adding/subtracting 6.
    433     if (controller->rawStickX <= -8) {
    434         controller->stickX = controller->rawStickX + 6;
    435     }
    436 
    437     if (controller->rawStickX >= 8) {
    438         controller->stickX = controller->rawStickX - 6;
    439     }
    440 
    441     if (controller->rawStickY <= -8) {
    442         controller->stickY = controller->rawStickY + 6;
    443     }
    444 
    445     if (controller->rawStickY >= 8) {
    446         controller->stickY = controller->rawStickY - 6;
    447     }
    448 
    449     // Calculate f32 magnitude from the center by vector length.
    450     controller->stickMag =
    451         sqrtf(controller->stickX * controller->stickX + controller->stickY * controller->stickY);
    452 
    453     // Magnitude cannot exceed 64.0f: if it does, modify the values
    454     // appropriately to flatten the values down to the allowed maximum value.
    455     if (controller->stickMag > 64) {
    456         controller->stickX *= 64 / controller->stickMag;
    457         controller->stickY *= 64 / controller->stickMag;
    458         controller->stickMag = 64;
    459     }
    460 }
    461 
    462 /**
    463  * If a demo sequence exists, this will run the demo input list until it is complete.
    464  */
    465 void run_demo_inputs(void) {
    466     // Eliminate the unused bits.
    467     gControllers[0].controllerData->button &= VALID_BUTTONS;
    468 
    469     // Check if a demo inputs list exists and if so,
    470     // run the active demo input list.
    471     if (gCurrDemoInput != NULL) {
    472         // Clear player 2's inputs if they exist. Player 2's controller
    473         // cannot be used to influence a demo. At some point, Nintendo
    474         // may have planned for there to be a demo where 2 players moved
    475         // around instead of just one, so clearing player 2's influence from
    476         // the demo had to have been necessary to perform this. Co-op mode, perhaps?
    477         if (gControllers[1].controllerData != NULL) {
    478             gControllers[1].controllerData->stick_x = 0;
    479             gControllers[1].controllerData->stick_y = 0;
    480             gControllers[1].controllerData->button = 0;
    481         }
    482 
    483         // The timer variable being 0 at the current input means the demo is over.
    484         // Set the button to the END_DEMO mask to end the demo.
    485         if (gCurrDemoInput->timer == 0) {
    486             gControllers[0].controllerData->stick_x = 0;
    487             gControllers[0].controllerData->stick_y = 0;
    488             gControllers[0].controllerData->button = END_DEMO;
    489         } else {
    490             // Backup the start button if it is pressed, since we don't want the
    491             // demo input to override the mask where start may have been pressed.
    492             u16 startPushed = gControllers[0].controllerData->button & START_BUTTON;
    493 
    494             // Perform the demo inputs by assigning the current button mask and the stick inputs.
    495             gControllers[0].controllerData->stick_x = gCurrDemoInput->rawStickX;
    496             gControllers[0].controllerData->stick_y = gCurrDemoInput->rawStickY;
    497 
    498             // To assign the demo input, the button information is stored in
    499             // an 8-bit mask rather than a 16-bit mask. this is because only
    500             // A, B, Z, Start, and the C-Buttons are used in a demo, as bits
    501             // in that order. In order to assign the mask, we need to take the
    502             // upper 4 bits (A, B, Z, and Start) and shift then left by 8 to
    503             // match the correct input mask. We then add this to the masked
    504             // lower 4 bits to get the correct button mask.
    505             gControllers[0].controllerData->button =
    506                 ((gCurrDemoInput->buttonMask & 0xF0) << 8) + ((gCurrDemoInput->buttonMask & 0xF));
    507 
    508             // If start was pushed, put it into the demo sequence being input to end the demo.
    509             gControllers[0].controllerData->button |= startPushed;
    510 
    511             // Run the current demo input's timer down. if it hits 0, advance the demo input list.
    512             if (--gCurrDemoInput->timer == 0) {
    513                 gCurrDemoInput++;
    514             }
    515         }
    516     }
    517 }
    518 
    519 /**
    520  * Update the controller struct with available inputs if present.
    521  */
    522 void read_controller_inputs(void) {
    523     s32 i;
    524 
    525     // If any controllers are plugged in, update the controller information.
    526     if (gControllerBits) {
    527         osRecvMesg(&gSIEventMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
    528         osContGetReadData(&gControllerPads[0]);
    529 #if ENABLE_RUMBLE
    530         release_rumble_pak_control();
    531 #endif
    532     }
    533     run_demo_inputs();
    534 
    535     for (i = 0; i < 2; i++) {
    536         struct Controller *controller = &gControllers[i];
    537 
    538         // if we're receiving inputs, update the controller struct with the new button info.
    539         if (controller->controllerData != NULL) {
    540             controller->rawStickX = controller->controllerData->stick_x;
    541             controller->rawStickY = controller->controllerData->stick_y;
    542             controller->buttonPressed = controller->controllerData->button
    543                                         & (controller->controllerData->button ^ controller->buttonDown);
    544             // 0.5x A presses are a good meme
    545             controller->buttonDown = controller->controllerData->button;
    546             adjust_analog_stick(controller);
    547         } else { // otherwise, if the controllerData is NULL, 0 out all of the inputs.
    548             controller->rawStickX = 0;
    549             controller->rawStickY = 0;
    550             controller->buttonPressed = 0;
    551             controller->buttonDown = 0;
    552             controller->stickX = 0;
    553             controller->stickY = 0;
    554             controller->stickMag = 0;
    555         }
    556     }
    557 
    558     // For some reason, player 1's inputs are copied to player 3's port.
    559     // This potentially may have been a way the developers "recorded"
    560     // the inputs for demos, despite record_demo existing.
    561     gPlayer3Controller->rawStickX = gPlayer1Controller->rawStickX;
    562     gPlayer3Controller->rawStickY = gPlayer1Controller->rawStickY;
    563     gPlayer3Controller->stickX = gPlayer1Controller->stickX;
    564     gPlayer3Controller->stickY = gPlayer1Controller->stickY;
    565     gPlayer3Controller->stickMag = gPlayer1Controller->stickMag;
    566     gPlayer3Controller->buttonPressed = gPlayer1Controller->buttonPressed;
    567     gPlayer3Controller->buttonDown = gPlayer1Controller->buttonDown;
    568 }
    569 
    570 /**
    571  * Initialize the controller structs to point at the OSCont information.
    572  */
    573 void init_controllers(void) {
    574     s16 port, cont;
    575 
    576     // Set controller 1 to point to the set of status/pads for input 1 and
    577     // init the controllers.
    578     gControllers[0].statusData = &gControllerStatuses[0];
    579     gControllers[0].controllerData = &gControllerPads[0];
    580     osContInit(&gSIEventMesgQueue, &gControllerBits, &gControllerStatuses[0]);
    581 
    582     // Strangely enough, the EEPROM probe for save data is done in this function.
    583     // Save Pak detection?
    584     gEepromProbe = osEepromProbe(&gSIEventMesgQueue);
    585 
    586     // Loop over the 4 ports and link the controller structs to the appropriate
    587     // status and pad. Interestingly, although there are pointers to 3 controllers,
    588     // only 2 are connected here. The third seems to have been reserved for debug
    589     // purposes and was never connected in the retail ROM, thus gPlayer3Controller
    590     // cannot be used, despite being referenced in various code.
    591     for (cont = 0, port = 0; port < 4 && cont < 2; port++) {
    592         // Is controller plugged in?
    593         if (gControllerBits & (1 << port)) {
    594             // The game allows you to have just 1 controller plugged
    595             // into any port in order to play the game. this was probably
    596             // so if any of the ports didn't work, you can have controllers
    597             // plugged into any of them and it will work.
    598 #if ENABLE_RUMBLE
    599             gControllers[cont].port = port;
    600 #endif
    601             gControllers[cont].statusData = &gControllerStatuses[port];
    602             gControllers[cont++].controllerData = &gControllerPads[port];
    603         }
    604     }
    605 }
    606 
    607 // Game thread core
    608 // ----------------------------------------------------------------------------------------------------
    609 
    610 /**
    611  * Setup main segments and framebuffers.
    612  */
    613 void setup_game_memory(void) {
    614     UNUSED u8 filler[8];
    615 
    616     // Setup general Segment 0
    617     set_segment_base_addr(0, (void *) 0x80000000);
    618     // Create Mesg Queues
    619     osCreateMesgQueue(&gGfxVblankQueue, gGfxMesgBuf, ARRAY_COUNT(gGfxMesgBuf));
    620     osCreateMesgQueue(&gGameVblankQueue, gGameMesgBuf, ARRAY_COUNT(gGameMesgBuf));
    621     // Setup z buffer and framebuffer
    622     gPhysicalZBuffer = VIRTUAL_TO_PHYSICAL(gZBuffer);
    623     gPhysicalFramebuffers[0] = VIRTUAL_TO_PHYSICAL(gFramebuffer0);
    624     gPhysicalFramebuffers[1] = VIRTUAL_TO_PHYSICAL(gFramebuffer1);
    625     gPhysicalFramebuffers[2] = VIRTUAL_TO_PHYSICAL(gFramebuffer2);
    626     // Setup Mario Animations
    627     gMarioAnimsMemAlloc = main_pool_alloc(0x4000, MEMORY_POOL_LEFT);
    628     set_segment_base_addr(17, (void *) gMarioAnimsMemAlloc);
    629     setup_dma_table_list(&gMarioAnimsBuf, gMarioAnims, gMarioAnimsMemAlloc);
    630     // Setup Demo Inputs List
    631     gDemoInputsMemAlloc = main_pool_alloc(0x800, MEMORY_POOL_LEFT);
    632     set_segment_base_addr(24, (void *) gDemoInputsMemAlloc);
    633     setup_dma_table_list(&gDemoInputsBuf, gDemoInputs, gDemoInputsMemAlloc);
    634     // Setup Level Script Entry
    635     load_segment(0x10, _entrySegmentRomStart, _entrySegmentRomEnd, MEMORY_POOL_LEFT);
    636     // Setup Segment 2 (Fonts, Text, etc)
    637     load_segment_decompress(2, _segment2_mio0SegmentRomStart, _segment2_mio0SegmentRomEnd);
    638 }
    639 
    640 /**
    641  * Main game loop thread. Runs forever as long as the game continues.
    642  */
    643 void thread5_game_loop(UNUSED void *arg) {
    644     struct LevelCommand *addr;
    645 
    646     CN_DEBUG_PRINTF(("start gfx thread\n"));
    647 
    648     setup_game_memory();
    649 #if ENABLE_RUMBLE
    650     init_rumble_pak_scheduler_queue();
    651 #endif
    652 
    653     CN_DEBUG_PRINTF(("init ctrl\n"));
    654     init_controllers();
    655     CN_DEBUG_PRINTF(("done ctrl\n"));
    656 
    657 #if ENABLE_RUMBLE
    658     create_thread_6();
    659 #endif
    660 
    661     save_file_load_all();
    662 
    663     set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1);
    664 
    665     // Point address to the entry point into the level script data.
    666     addr = segmented_to_virtual(level_script_entry);
    667 
    668     play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0);
    669     set_sound_mode(save_file_get_sound_mode());
    670     render_init();
    671 
    672     while (TRUE) {
    673         // If the reset timer is active, run the process to reset the game.
    674         if (gResetTimer != 0) {
    675             draw_reset_bars();
    676             continue;
    677         }
    678         profiler_log_thread5_time(THREAD5_START);
    679 
    680         // If any controllers are plugged in, start read the data for when
    681         // read_controller_inputs is called later.
    682         if (gControllerBits) {
    683 #if ENABLE_RUMBLE
    684             block_until_rumble_pak_free();
    685 #endif
    686             osContStartReadData(&gSIEventMesgQueue);
    687         }
    688 
    689         audio_game_loop_tick();
    690         select_gfx_pool();
    691         read_controller_inputs();
    692         addr = level_script_execute(addr);
    693 
    694         display_and_vsync();
    695 
    696         // when debug info is enabled, print the "BUF %d" information.
    697         if (gShowDebugText) {
    698             // subtract the end of the gfx pool with the display list to obtain the
    699             // amount of free space remaining.
    700             print_text_fmt_int(180, 20, "BUF %d", gGfxPoolEnd - (u8 *) gDisplayListHead);
    701         }
    702     }
    703 }