diff --git a/include/config.h.orig b/include/config.h.orig deleted file mode 100644 index 1cd32588..00000000 --- a/include/config.h.orig +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -/** - * @file config.h - * A catch-all file for configuring various bugfixes and other settings - * (maybe eventually) in SM64 - */ - -// Bug Fixes -// --| US Version Nintendo Bug Fixes -/// Fixes bug where obtaining over 999 coins sets the number of lives to 999 (or -25) -#define BUGFIX_MAX_LIVES (0 || VERSION_US || VERSION_EU || VERSION_SH) -/// Fixes bug where the Boss music won't fade out after defeating King Bob-omb -#define BUGFIX_KING_BOB_OMB_FADE_MUSIC (0 || VERSION_US || VERSION_EU || VERSION_SH) -/// Fixes bug in Bob-Omb Battlefield where entering a warp stops the Koopa race music -#define BUGFIX_KOOPA_RACE_MUSIC (0 || VERSION_US || VERSION_EU || VERSION_SH) -/// Fixes bug where Piranha Plants do not reset their action state when the -/// player exits their activation radius. -#define BUGFIX_PIRANHA_PLANT_STATE_RESET (0 || VERSION_US || VERSION_EU || VERSION_SH) -/// Fixes bug where sleeping Piranha Plants damage players that bump into them -#define BUGFIX_PIRANHA_PLANT_SLEEP_DAMAGE (0 || VERSION_US || VERSION_SH) -/// Fixes bug where it shows a star when you grab a key in bowser battle stages -#define BUGFIX_STAR_BOWSER_KEY (0 || VERSION_US || VERSION_EU || VERSION_SH) - -// Support Rumble Pak -#define ENABLE_RUMBLE (1 || VERSION_SH) - -// Screen Size Defines -#define SCREEN_WIDTH 320 -#define SCREEN_HEIGHT 240 - -// Border Height Define for NTSC Versions -#ifdef TARGET_N64 -#ifndef VERSION_EU -#define BORDER_HEIGHT 0 -#else -#define BORDER_HEIGHT 0 -#endif -#else -// What's the point of having a border? -#define BORDER_HEIGHT 0 -#endif - -#endif // CONFIG_H diff --git a/src/game/game_init.c.orig b/src/game/game_init.c.orig deleted file mode 100644 index b8d19126..00000000 --- a/src/game/game_init.c.orig +++ /dev/null @@ -1,689 +0,0 @@ -#include - -#include "sm64.h" -#include "gfx_dimensions.h" -#include "audio/external.h" -#include "buffers/buffers.h" -#include "buffers/gfx_output_buffer.h" -#include "buffers/framebuffers.h" -#include "buffers/zbuffer.h" -#include "engine/level_script.h" -#include "game_init.h" -#include "main.h" -#include "memory.h" -#include "profiler.h" -#include "save_file.h" -#include "seq_ids.h" -#include "sound_init.h" -#include "print.h" -#include "segment2.h" -#include "segment_symbols.h" -#include "rumble_init.h" -#ifdef HVQM -#include -#endif -#ifdef UNF -#include "usb/usb.h" -#include "usb/debug.h" -#endif -#ifdef SRAM -#include "sram.h" -#endif -#include - -// FIXME: I'm not sure all of these variables belong in this file, but I don't -// know of a good way to split them -struct Controller gControllers[3]; -struct SPTask *gGfxSPTask; -Gfx *gDisplayListHead; -u8 *gGfxPoolEnd; -struct GfxPool *gGfxPool; -OSContStatus gControllerStatuses[4]; -OSContPad gControllerPads[4]; -u8 gControllerBits; -#ifdef EEP -s8 gEepromProbe; -#endif -#ifdef SRAM -s8 gSramProbe; -#endif -OSMesgQueue gGameVblankQueue; -OSMesgQueue D_80339CB8; -OSMesg D_80339CD0; -OSMesg D_80339CD4; -struct VblankHandler gGameVblankHandler; -uintptr_t gPhysicalFrameBuffers[3]; -uintptr_t gPhysicalZBuffer; -void *D_80339CF0; -void *D_80339CF4; -struct MarioAnimation D_80339D10; -struct MarioAnimation gDemo; -UNUSED u8 filler80339D30[0x90]; - -s32 unused8032C690 = 0; -u32 gGlobalTimer = 0; -u8 gIsConsole; - -u16 sCurrFBNum = 0; -u16 frameBufferIndex = 0; -void (*gGoddardVblankCallback)(void) = NULL; -struct Controller *gPlayer1Controller = &gControllers[0]; -struct Controller *gPlayer2Controller = &gControllers[1]; -// probably debug only, see note below -struct Controller *gPlayer3Controller = &gControllers[2]; -struct DemoInput *gCurrDemoInput = NULL; // demo input sequence -u16 gDemoInputListID = 0; -struct DemoInput gRecordedDemoInput = { 0 }; // possibly removed in EU. TODO: Check - -/** - * Initializes the Reality Display Processor (RDP). - * This function initializes settings such as texture filtering mode, - * scissoring, and render mode (although keep in mind that this render - * mode is not used in-game, where it is set in render_graph_node.c). - */ -void my_rdp_init(void) { - gDPPipeSync(gDisplayListHead++); - gDPPipelineMode(gDisplayListHead++, G_PM_1PRIMITIVE); - - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); - - gDPSetTextureLOD(gDisplayListHead++, G_TL_TILE); - gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE); - gDPSetTextureDetail(gDisplayListHead++, G_TD_CLAMP); - gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP); - gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP); - gDPSetTextureConvert(gDisplayListHead++, G_TC_FILT); - - gDPSetCombineKey(gDisplayListHead++, G_CK_NONE); - gDPSetAlphaCompare(gDisplayListHead++, G_AC_NONE); - gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); - gDPSetColorDither(gDisplayListHead++, G_CD_MAGICSQ); - gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); - -#ifdef VERSION_SH - gDPSetAlphaDither(gDisplayListHead++, G_AD_PATTERN); -#endif - gDPPipeSync(gDisplayListHead++); -} - -/** - * Initializes the RSP's built-in geometry and lighting engines. - * Most of these (with the notable exception of gSPNumLights), are - * almost immediately overwritten. - */ -void my_rsp_init(void) { - gSPClearGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CULL_BOTH | G_FOG - | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD); - - gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CULL_BACK | G_LIGHTING); - - gSPNumLights(gDisplayListHead++, NUMLIGHTS_1); - gSPTexture(gDisplayListHead++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); - - // @bug Nintendo did not explicitly define the clipping ratio. - // For Fast3DEX2, this causes the dreaded warped vertices issue - // unless the clipping ratio is changed back to the intended value, - // as Fast3DEX2 uses a different initial value than Fast3D(EX). -#ifdef F3DEX_GBI_2 - gSPClipRatio(gDisplayListHead++, FRUSTRATIO_1); -#endif -} - -/** Clear the Z buffer. */ -void clear_z_buffer(void) { - gDPPipeSync(gDisplayListHead++); - - gDPSetDepthSource(gDisplayListHead++, G_ZS_PIXEL); - gDPSetDepthImage(gDisplayListHead++, gPhysicalZBuffer); - - gDPSetColorImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, gPhysicalZBuffer); - gDPSetFillColor(gDisplayListHead++, - GPACK_ZDZ(G_MAXFBZ, 0) << 16 | GPACK_ZDZ(G_MAXFBZ, 0)); - - gDPFillRectangle(gDisplayListHead++, 0, BORDER_HEIGHT, SCREEN_WIDTH - 1, - SCREEN_HEIGHT - 1 - BORDER_HEIGHT); -} - -/** Sets up the final framebuffer image. */ -void display_frame_buffer(void) { - gDPPipeSync(gDisplayListHead++); - - gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); - gDPSetColorImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, - gPhysicalFrameBuffers[frameBufferIndex]); - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, - SCREEN_HEIGHT - BORDER_HEIGHT); -} - -/** Clears the framebuffer, allowing it to be overwritten. */ -void clear_frame_buffer(s32 color) { - gDPPipeSync(gDisplayListHead++); - - gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); - gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); - - gDPSetFillColor(gDisplayListHead++, color); - gDPFillRectangle(gDisplayListHead++, - GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - BORDER_HEIGHT - 1); - - gDPPipeSync(gDisplayListHead++); - - gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); -} - -/** Clears and initializes the viewport. */ -void clear_viewport(Vp *viewport, s32 color) { - s16 vpUlx = (viewport->vp.vtrans[0] - viewport->vp.vscale[0]) / 4 + 1; - s16 vpUly = (viewport->vp.vtrans[1] - viewport->vp.vscale[1]) / 4 + 1; - s16 vpLrx = (viewport->vp.vtrans[0] + viewport->vp.vscale[0]) / 4 - 2; - s16 vpLry = (viewport->vp.vtrans[1] + viewport->vp.vscale[1]) / 4 - 2; - -#ifdef WIDESCREEN - vpUlx = GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(vpUlx); - vpLrx = GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(SCREEN_WIDTH - vpLrx); -#endif - - gDPPipeSync(gDisplayListHead++); - - gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); - gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); - - gDPSetFillColor(gDisplayListHead++, color); - gDPFillRectangle(gDisplayListHead++, vpUlx, vpUly, vpLrx, vpLry); - - gDPPipeSync(gDisplayListHead++); - - gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); -} - -/** Draws the horizontal screen borders */ -void draw_screen_borders(void) { - gDPPipeSync(gDisplayListHead++); - - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); - gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); - - gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(0, 0, 0, 0) << 16 | GPACK_RGBA5551(0, 0, 0, 0)); - -#if BORDER_HEIGHT != 0 - gDPFillRectangle(gDisplayListHead++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), 0, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, BORDER_HEIGHT - 1); - gDPFillRectangle(gDisplayListHead++, - GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), SCREEN_HEIGHT - BORDER_HEIGHT, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - 1); -#endif -} - -void make_viewport_clip_rect(Vp *viewport) { - s16 vpUlx = (viewport->vp.vtrans[0] - viewport->vp.vscale[0]) / 4 + 1; - s16 vpPly = (viewport->vp.vtrans[1] - viewport->vp.vscale[1]) / 4 + 1; - s16 vpLrx = (viewport->vp.vtrans[0] + viewport->vp.vscale[0]) / 4 - 1; - s16 vpLry = (viewport->vp.vtrans[1] + viewport->vp.vscale[1]) / 4 - 1; - - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, vpUlx, vpPly, vpLrx, vpLry); -} - -/** - * Loads the F3D microcodes. - * Refer to this function if you would like to load - * other microcodes (i.e. S2DEX). - */ -void create_task_structure(void) { - s32 entries = gDisplayListHead - gGfxPool->buffer; - - gGfxSPTask->msgqueue = &D_80339CB8; - gGfxSPTask->msg = (OSMesg) 2; - gGfxSPTask->task.t.type = M_GFXTASK; - gGfxSPTask->task.t.ucode_boot = rspbootTextStart; - gGfxSPTask->task.t.ucode_boot_size = ((u8 *) rspbootTextEnd - (u8 *) rspbootTextStart); - gGfxSPTask->task.t.flags = 0; -#ifdef F3DZEX_GBI_2 - gGfxSPTask->task.t.ucode = gspF3DZEX2_PosLight_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspF3DZEX2_PosLight_fifoDataStart; -#elif F3DEX2PL_GBI - gGfxSPTask->task.t.ucode = gspF3DEX2_PosLight_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspF3DEX2_PosLight_fifoDataStart; -#elif F3DEX_GBI_2 - gGfxSPTask->task.t.ucode = gspF3DEX2_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspF3DEX2_fifoDataStart; -#elif F3DEX_GBI - gGfxSPTask->task.t.ucode = gspF3DEX_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspF3DEX_fifoDataStart; -#elif SUPER3D_GBI - gGfxSPTask->task.t.ucode = gspSuper3D_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspSuper3D_fifoDataStart; -#else - gGfxSPTask->task.t.ucode = gspFast3D_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspFast3D_fifoDataStart; -#endif - gGfxSPTask->task.t.ucode_size = SP_UCODE_SIZE; // (this size is ignored) - gGfxSPTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE; - gGfxSPTask->task.t.dram_stack = (u64 *) gGfxSPTaskStack; - gGfxSPTask->task.t.dram_stack_size = SP_DRAM_STACK_SIZE8; - gGfxSPTask->task.t.output_buff = gGfxSPTaskOutputBuffer; - gGfxSPTask->task.t.output_buff_size = - (u64 *)((u8 *) gGfxSPTaskOutputBuffer + sizeof(gGfxSPTaskOutputBuffer)); - gGfxSPTask->task.t.data_ptr = (u64 *) &gGfxPool->buffer; - gGfxSPTask->task.t.data_size = entries * sizeof(Gfx); - gGfxSPTask->task.t.yield_data_ptr = (u64 *) gGfxSPTaskYieldBuffer; - gGfxSPTask->task.t.yield_data_size = OS_YIELD_DATA_SIZE; -} - -/** Starts rendering the scene. */ -void init_render_image(void) { - move_segment_table_to_dmem(); - my_rdp_init(); - my_rsp_init(); - clear_z_buffer(); - display_frame_buffer(); -} - -/** Ends the master display list. */ -void end_master_display_list(void) { - draw_screen_borders(); - if (gShowProfiler) { - draw_profiler(); - } - - gDPFullSync(gDisplayListHead++); - gSPEndDisplayList(gDisplayListHead++); - - create_task_structure(); -} - -void draw_reset_bars(void) { - s32 sp24; - s32 sp20; - s32 fbNum; - u64 *sp18; - - if (gResetTimer != 0 && D_8032C648 < 15) { - if (sCurrFBNum == 0) { - fbNum = 2; - } else { - fbNum = sCurrFBNum - 1; - } - - sp18 = (u64 *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[fbNum]); - sp18 += D_8032C648++ * (SCREEN_WIDTH / 4); - - for (sp24 = 0; sp24 < ((SCREEN_HEIGHT / 16) + 1); sp24++) { - // Loop must be one line to match on -O2 - for (sp20 = 0; sp20 < (SCREEN_WIDTH / 4); sp20++) *sp18++ = 0; - sp18 += ((SCREEN_WIDTH / 4) * 14); - } - } - - osWritebackDCacheAll(); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); -} - -void rendering_init(void) { - if (IO_READ(DPC_PIPEBUSY_REG) == 0) { - gIsConsole = 0; - } else { - gIsConsole = 1; - } - gGfxPool = &gGfxPools[0]; - set_segment_base_addr(1, gGfxPool->buffer); - gGfxSPTask = &gGfxPool->spTask; - gDisplayListHead = gGfxPool->buffer; - gGfxPoolEnd = (u8 *) (gGfxPool->buffer + GFX_POOL_SIZE); - init_render_image(); - clear_frame_buffer(0); - end_master_display_list(); - send_display_list(&gGfxPool->spTask); - - frameBufferIndex++; - gGlobalTimer++; -} - -void config_gfx_pool(void) { - gGfxPool = &gGfxPools[gGlobalTimer % 2]; - set_segment_base_addr(1, gGfxPool->buffer); - gGfxSPTask = &gGfxPool->spTask; - gDisplayListHead = gGfxPool->buffer; - gGfxPoolEnd = (u8 *) (gGfxPool->buffer + GFX_POOL_SIZE); -} - -/** Handles vsync. */ -void display_and_vsync(void) { - profiler_log_thread5_time(BEFORE_DISPLAY_LISTS); - osRecvMesg(&D_80339CB8, &D_80339BEC, OS_MESG_BLOCK); - if (gGoddardVblankCallback != NULL) { - gGoddardVblankCallback(); - gGoddardVblankCallback = NULL; - } - send_display_list(&gGfxPool->spTask); - profiler_log_thread5_time(AFTER_DISPLAY_LISTS); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); - osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[sCurrFBNum])); - profiler_log_thread5_time(THREAD5_END); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); - if (++sCurrFBNum == 3) { - sCurrFBNum = 0; - } - if (++frameBufferIndex == 3) { - frameBufferIndex = 0; - } - gGlobalTimer++; -} - -// this function records distinct inputs over a 255-frame interval to RAM locations and was likely -// used to record the demo sequences seen in the final game. This function is unused. -UNUSED static void record_demo(void) { - // record the player's button mask and current rawStickX and rawStickY. - u8 buttonMask = - ((gPlayer1Controller->buttonDown & (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON)) >> 8) - | (gPlayer1Controller->buttonDown & (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)); - s8 rawStickX = gPlayer1Controller->rawStickX; - s8 rawStickY = gPlayer1Controller->rawStickY; - - // if the stick is in deadzone, set its value to 0 to - // nullify the effects. We do not record deadzone inputs. - if (rawStickX > -8 && rawStickX < 8) { - rawStickX = 0; - } - - if (rawStickY > -8 && rawStickY < 8) { - rawStickY = 0; - } - - // record the distinct input and timer so long as they - // are unique. If the timer hits 0xFF, reset the timer - // for the next demo input. - if (gRecordedDemoInput.timer == 0xFF || buttonMask != gRecordedDemoInput.buttonMask - || rawStickX != gRecordedDemoInput.rawStickX || rawStickY != gRecordedDemoInput.rawStickY) { - gRecordedDemoInput.timer = 0; - gRecordedDemoInput.buttonMask = buttonMask; - gRecordedDemoInput.rawStickX = rawStickX; - gRecordedDemoInput.rawStickY = rawStickY; - } - gRecordedDemoInput.timer++; -} - -// take the updated controller struct and calculate -// the new x, y, and distance floats. -void adjust_analog_stick(struct Controller *controller) { - UNUSED u8 pad[8]; - - // reset the controller's x and y floats. - controller->stickX = 0; - controller->stickY = 0; - - // modulate the rawStickX and rawStickY to be the new f32 values by adding/subtracting 6. - if (controller->rawStickX <= -8) { - controller->stickX = controller->rawStickX + 6; - } - - if (controller->rawStickX >= 8) { - controller->stickX = controller->rawStickX - 6; - } - - if (controller->rawStickY <= -8) { - controller->stickY = controller->rawStickY + 6; - } - - if (controller->rawStickY >= 8) { - controller->stickY = controller->rawStickY - 6; - } - - // calculate f32 magnitude from the center by vector length. - controller->stickMag = - sqrtf(controller->stickX * controller->stickX + controller->stickY * controller->stickY); - - // magnitude cannot exceed 64.0f: if it does, modify the values appropriately to - // flatten the values down to the allowed maximum value. - if (controller->stickMag > 64) { - controller->stickX *= 64 / controller->stickMag; - controller->stickY *= 64 / controller->stickMag; - controller->stickMag = 64; - } -} - -// if a demo sequence exists, this will run the demo -// input list until it is complete. called every frame. -void run_demo_inputs(void) { - // eliminate the unused bits. - gControllers[0].controllerData->button &= VALID_BUTTONS; - - /* - Check if a demo inputs list - exists and if so, run the - active demo input list. - */ - if (gCurrDemoInput != NULL) { - /* - clear player 2's inputs if they exist. Player 2's controller - cannot be used to influence a demo. At some point, Nintendo - may have planned for there to be a demo where 2 players moved - around instead of just one, so clearing player 2's influence from - the demo had to have been necessary to perform this. Co-op mode, perhaps? - */ - if (gControllers[1].controllerData != NULL) { - gControllers[1].controllerData->stick_x = 0; - gControllers[1].controllerData->stick_y = 0; - gControllers[1].controllerData->button = 0; - } - - // the timer variable being 0 at the current input means the demo is over. - // set the button to the END_DEMO mask to end the demo. - if (gCurrDemoInput->timer == 0) { - gControllers[0].controllerData->stick_x = 0; - gControllers[0].controllerData->stick_y = 0; - gControllers[0].controllerData->button = END_DEMO; - } else { - // backup the start button if it is pressed, since we don't want the - // demo input to override the mask where start may have been pressed. - u16 startPushed = gControllers[0].controllerData->button & START_BUTTON; - - // perform the demo inputs by assigning the current button mask and the stick inputs. - gControllers[0].controllerData->stick_x = gCurrDemoInput->rawStickX; - gControllers[0].controllerData->stick_y = gCurrDemoInput->rawStickY; - - /* - to assign the demo input, the button information is stored in - an 8-bit mask rather than a 16-bit mask. this is because only - A, B, Z, Start, and the C-Buttons are used in a demo, as bits - in that order. In order to assign the mask, we need to take the - upper 4 bits (A, B, Z, and Start) and shift then left by 8 to - match the correct input mask. We then add this to the masked - lower 4 bits to get the correct button mask. - */ - gControllers[0].controllerData->button = - ((gCurrDemoInput->buttonMask & 0xF0) << 8) + ((gCurrDemoInput->buttonMask & 0xF)); - - // if start was pushed, put it into the demo sequence being input to - // end the demo. - gControllers[0].controllerData->button |= startPushed; - - // run the current demo input's timer down. if it hits 0, advance the - // demo input list. - if (--gCurrDemoInput->timer == 0) { - gCurrDemoInput++; - } - } - } -} - -// update the controller struct with available inputs if present. -void read_controller_inputs(void) { - s32 i; - - // if any controllers are plugged in, update the - // controller information. - if (gControllerBits) { - osRecvMesg(&gSIEventMesgQueue, &D_80339BEC, OS_MESG_BLOCK); - osContGetReadData(&gControllerPads[0]); -#if ENABLE_RUMBLE - release_rumble_pak_control(); -#endif - } - run_demo_inputs(); - - for (i = 0; i < 2; i++) { - struct Controller *controller = &gControllers[i]; - - // if we're receiving inputs, update the controller struct - // with the new button info. - if (controller->controllerData != NULL) { - controller->rawStickX = controller->controllerData->stick_x; - controller->rawStickY = controller->controllerData->stick_y; - controller->buttonPressed = controller->controllerData->button - & (controller->controllerData->button ^ controller->buttonDown); - // 0.5x A presses are a good meme - controller->buttonDown = controller->controllerData->button; - adjust_analog_stick(controller); - } else // otherwise, if the controllerData is NULL, 0 out all of the inputs. - { - controller->rawStickX = 0; - controller->rawStickY = 0; - controller->buttonPressed = 0; - controller->buttonDown = 0; - controller->stickX = 0; - controller->stickY = 0; - controller->stickMag = 0; - } - } - - // For some reason, player 1's inputs are copied to player 3's port. This - // potentially may have been a way the developers "recorded" the inputs - // for demos, despite record_demo existing. - gPlayer3Controller->rawStickX = gPlayer1Controller->rawStickX; - gPlayer3Controller->rawStickY = gPlayer1Controller->rawStickY; - gPlayer3Controller->stickX = gPlayer1Controller->stickX; - gPlayer3Controller->stickY = gPlayer1Controller->stickY; - gPlayer3Controller->stickMag = gPlayer1Controller->stickMag; - gPlayer3Controller->buttonPressed = gPlayer1Controller->buttonPressed; - gPlayer3Controller->buttonDown = gPlayer1Controller->buttonDown; -} - -// initialize the controller structs to point at the OSCont information. -void init_controllers(void) { - s16 port, cont; - - // set controller 1 to point to the set of status/pads for input 1 and - // init the controllers. - gControllers[0].statusData = &gControllerStatuses[0]; - gControllers[0].controllerData = &gControllerPads[0]; - osContInit(&gSIEventMesgQueue, &gControllerBits, &gControllerStatuses[0]); - -#ifdef EEP - // strangely enough, the EEPROM probe for save data is done in this function. - // save pak detection? - gEepromProbe = osEepromProbe(&gSIEventMesgQueue); -#endif -#ifdef SRAM - gSramProbe = nuPiInitSram(); -#endif - - // loop over the 4 ports and link the controller structs to the appropriate - // status and pad. Interestingly, although there are pointers to 3 controllers, - // only 2 are connected here. The third seems to have been reserved for debug - // purposes and was never connected in the retail ROM, thus gPlayer3Controller - // cannot be used, despite being referenced in various code. - for (cont = 0, port = 0; port < 4 && cont < 2; port++) { - // is controller plugged in? - if (gControllerBits & (1 << port)) { - // the game allows you to have just 1 controller plugged - // into any port in order to play the game. this was probably - // so if any of the ports didn't work, you can have controllers - // plugged into any of them and it will work. -#if ENABLE_RUMBLE - gControllers[cont].port = port; -#endif - gControllers[cont].statusData = &gControllerStatuses[port]; - gControllers[cont++].controllerData = &gControllerPads[port]; - } - } -} - -void setup_game_memory(void) { - UNUSED u8 pad[8]; - - set_segment_base_addr(0, (void *) 0x80000000); - osCreateMesgQueue(&D_80339CB8, &D_80339CD4, 1); - osCreateMesgQueue(&gGameVblankQueue, &D_80339CD0, 1); - gPhysicalZBuffer = VIRTUAL_TO_PHYSICAL(gZBuffer); - gPhysicalFrameBuffers[0] = VIRTUAL_TO_PHYSICAL(gFrameBuffer0); - gPhysicalFrameBuffers[1] = VIRTUAL_TO_PHYSICAL(gFrameBuffer1); - gPhysicalFrameBuffers[2] = VIRTUAL_TO_PHYSICAL(gFrameBuffer2); - D_80339CF0 = main_pool_alloc(0x4000, MEMORY_POOL_LEFT); - set_segment_base_addr(17, (void *) D_80339CF0); - func_80278A78(&D_80339D10, gMarioAnims, D_80339CF0); - D_80339CF4 = main_pool_alloc(2048, MEMORY_POOL_LEFT); - set_segment_base_addr(24, (void *) D_80339CF4); - func_80278A78(&gDemo, gDemoInputs, D_80339CF4); - load_segment(0x10, _entrySegmentRomStart, _entrySegmentRomEnd, MEMORY_POOL_LEFT); - load_segment_decompress(2, _segment2_yay0SegmentRomStart, _segment2_yay0SegmentRomEnd); -} - -// main game loop thread. runs forever as long as the game -// continues. -void thread5_game_loop(UNUSED void *arg) { - struct LevelCommand *addr; - - setup_game_memory(); -#if ENABLE_RUMBLE - init_rumble_pak_scheduler_queue(); -#endif - init_controllers(); -#if ENABLE_RUMBLE - create_thread_6(); -#endif -#ifdef HVQM - createHvqmThread(); -#endif - save_file_load_all(); - - set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1); - - // point addr to the entry point into the level script data. - addr = segmented_to_virtual(level_script_entry); - - play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0); - set_sound_mode(save_file_get_sound_mode()); - rendering_init(); - - while (TRUE) { - // if the reset timer is active, run the process to reset the game. - if (gResetTimer) { - draw_reset_bars(); - continue; - } - profiler_log_thread5_time(THREAD5_START); - - // if any controllers are plugged in, start read the data for when - // read_controller_inputs is called later. - if (gControllerBits) { -#if ENABLE_RUMBLE - block_until_rumble_pak_free(); -#endif - osContStartReadData(&gSIEventMesgQueue); - } - - audio_game_loop_tick(); - config_gfx_pool(); - read_controller_inputs(); - addr = level_script_execute(addr); - - display_and_vsync(); - - // when debug info is enabled, print the "BUF %d" information. - if (gShowDebugText) { - // subtract the end of the gfx pool with the display list to obtain the - // amount of free space remaining. - print_text_fmt_int(180, 20, "BUF %d", gGfxPoolEnd - (u8 *) gDisplayListHead); - } -#if 0 - if (gPlayer1Controller->buttonPressed & L_TRIG) { - osStartThread(&hvqmThread); - osRecvMesg(&gDmaMesgQueue, NULL, OS_MESG_BLOCK); - } -#endif - } -} diff --git a/src/game/level_update.c.orig b/src/game/level_update.c.orig deleted file mode 100644 index d380d6a2..00000000 --- a/src/game/level_update.c.orig +++ /dev/null @@ -1,1324 +0,0 @@ -#include - -#include "sm64.h" -#include "seq_ids.h" -#include "dialog_ids.h" -#include "audio/external.h" -#include "level_update.h" -#include "game_init.h" -#include "level_update.h" -#include "main.h" -#include "engine/math_util.h" -#include "engine/graph_node.h" -#include "area.h" -#include "save_file.h" -#include "sound_init.h" -#include "mario.h" -#include "camera.h" -#include "object_list_processor.h" -#include "ingame_menu.h" -#include "obj_behaviors.h" -#include "save_file.h" -#include "debug_course.h" -#ifdef VERSION_EU -#include "memory.h" -#include "eu_translation.h" -#include "segment_symbols.h" -#endif -#include "level_table.h" -#include "course_table.h" -#include "rumble_init.h" - -#define PLAY_MODE_NORMAL 0 -#define PLAY_MODE_PAUSED 2 -#define PLAY_MODE_CHANGE_AREA 3 -#define PLAY_MODE_CHANGE_LEVEL 4 -#define PLAY_MODE_FRAME_ADVANCE 5 - -#define WARP_TYPE_NOT_WARPING 0 -#define WARP_TYPE_CHANGE_LEVEL 1 -#define WARP_TYPE_CHANGE_AREA 2 -#define WARP_TYPE_SAME_AREA 3 - -#define WARP_NODE_F0 0xF0 -#define WARP_NODE_DEATH 0xF1 -#define WARP_NODE_F2 0xF2 -#define WARP_NODE_WARP_FLOOR 0xF3 -#define WARP_NODE_CREDITS_START 0xF8 -#define WARP_NODE_CREDITS_NEXT 0xF9 -#define WARP_NODE_CREDITS_END 0xFA - -#define WARP_NODE_CREDITS_MIN 0xF8 - -// TODO: Make these ifdefs better -const char *credits01[] = { "1GAME DIRECTOR", "SHIGERU MIYAMOTO" }; -const char *credits02[] = { "2ASSISTANT DIRECTORS", "YOSHIAKI KOIZUMI", "TAKASHI TEZUKA" }; -const char *credits03[] = { "2SYSTEM PROGRAMMERS", "YASUNARI NISHIDA", "YOSHINORI TANIMOTO" }; -const char *credits04[] = { "3PROGRAMMERS", "HAJIME YAJIMA", "DAIKI IWAMOTO", "TOSHIO IWAWAKI" }; -#if defined(VERSION_JP) || defined(VERSION_SH) -const char *credits05[] = { "1CAMERA PROGRAMMER", "TAKUMI KAWAGOE" }; -const char *credits06[] = { "1MARIO FACE PROGRAMMER", "GILES GODDARD" }; -const char *credits07[] = { "2COURSE DIRECTORS", "YOICHI YAMADA", "YASUHISA YAMAMURA" }; -const char *credits08[] = { "2COURSE DESIGNERS", "KENTA USUI", "NAOKI MORI" }; -const char *credits09[] = { "3COURSE DESIGNERS", "YOSHIKI HARUHANA", "MAKOTO MIYANAGA", - "KATSUHIKO KANNO" }; -const char *credits10[] = { "1SOUND COMPOSER", "KOJI KONDO" }; - -#ifdef VERSION_SH -const char *credits11[] = { "4SOUND EFFECTS", "SOUND PROGRAMMER", "YOJI INAGAKI", "HIDEAKI SHIMIZU" }; -const char *credits12[] = { "23D ANIMATORS", "YOSHIAKI KOIZUMI", "SATORU TAKIZAWA" }; -const char *credits13[] = { "1CG DESIGNER", "MASANAO ARIMOTO" }; -const char *credits14[] = { "3TECHNICAL SUPPORT", "TAKAO SAWANO", "HIROHITO YOSHIMOTO", "HIROTO YADA" }; -const char *credits15[] = { "1TECHNICAL SUPPORT", "SGI. 64PROJECT STAFF" }; -const char *credits16[] = { "2PROGRESS MANAGEMENT", "KIMIYOSHI FUKUI", "KEIZO KATO" }; -const char *credits17[] = { "4MARIO VOICE", "PEACH VOICE", "CHARLES MARTINET", "LESLIE SWAN" }; -const char *credits18[] = { "3SPECIAL THANKS TO", "JYOHO KAIHATUBU", "ALL NINTENDO", - "MARIO CLUB STAFF" }; -const char *credits19[] = { "1PRODUCER", "SHIGERU MIYAMOTO" }; -const char *credits20[] = { "1EXECUTIVE PRODUCER", "HIROSHI YAMAUCHI" }; -#else // VERSION_JP -const char *credits11[] = { "1SOUND EFFECTS", "YOJI INAGAKI" }; -const char *credits12[] = { "1SOUND PROGRAMMER", "HIDEAKI SHIMIZU" }; -const char *credits13[] = { "23D ANIMATORS", "YOSHIAKI KOIZUMI", "SATORU TAKIZAWA" }; -const char *credits14[] = { "1CG DESIGNER", "MASANAO ARIMOTO" }; -const char *credits15[] = { "3TECHNICAL SUPPORT", "TAKAO SAWANO", "HIROHITO YOSHIMOTO", "HIROTO YADA" }; -const char *credits16[] = { "1TECHNICAL SUPPORT", "SGI. 64PROJECT STAFF" }; -const char *credits17[] = { "2PROGRESS MANAGEMENT", "KIMIYOSHI FUKUI", "KEIZO KATO" }; -const char *credits18[] = { "3SPECIAL THANKS TO", "JYOHO KAIHATUBU", "ALL NINTENDO", - "MARIO CLUB STAFF" }; -const char *credits19[] = { "1PRODUCER", "SHIGERU MIYAMOTO" }; -const char *credits20[] = { "1EXECUTIVE PRODUCER", "HIROSHI YAMAUCHI" }; -#endif -#else // VERSION_US || VERSION_EU -const char *credits05[] = { - "4CAMERA PROGRAMMER", "MARIO FACE PROGRAMMER", "TAKUMI KAWAGOE", "GILES GODDARD" -}; // US combines camera programmer and Mario face programmer -const char *credits06[] = { "2COURSE DIRECTORS", "YOICHI YAMADA", "YASUHISA YAMAMURA" }; -const char *credits07[] = { "2COURSE DESIGNERS", "KENTA USUI", "NAOKI MORI" }; -const char *credits08[] = { "3COURSE DESIGNERS", "YOSHIKI HARUHANA", "MAKOTO MIYANAGA", - "KATSUHIKO KANNO" }; -#ifdef VERSION_US -const char *credits09[] = { "1SOUND COMPOSER", "KOJI KONDO" }; -const char *credits10[] = { "4SOUND EFFECTS", "SOUND PROGRAMMER", "YOJI INAGAKI", - "HIDEAKI SHIMIZU" }; // as well as sound effects and sound programmer -const char *credits11[] = { "23-D ANIMATORS", "YOSHIAKI KOIZUMI", "SATORU TAKIZAWA" }; -const char *credits12[] = { "1ADDITIONAL GRAPHICS", "MASANAO ARIMOTO" }; -const char *credits13[] = { "3TECHNICAL SUPPORT", "TAKAO SAWANO", "HIROHITO YOSHIMOTO", "HIROTO YADA" }; -const char *credits14[] = { "1TECHNICAL SUPPORT", "SGI N64 PROJECT STAFF" }; -const char *credits15[] = { "2PROGRESS MANAGEMENT", "KIMIYOSHI FUKUI", "KEIZO KATO" }; -const char *credits16[] = { "5SCREEN TEXT WRITER", "TRANSLATION", "LESLIE SWAN", "MINA AKINO", - "HIRO YAMADA" }; // ...in order to make room for these 2 new lines -#else // VERSION_EU -const char *credits09[] = { "7SOUND COMPOSER", "SOUND EFFECTS", "SOUND PROGRAMMER", "KOJI KONDO", - "YOJI INAGAKI", "HIDEAKI SHIMIZU" }; -const char *credits10[] = { "63-D ANIMATORS", "ADDITIONAL GRAPHICS", "YOSHIAKI KOIZUMI", "SATORU TAKIZAWA", - "MASANAO ARIMOTO" }; -const char *credits11[] = { "3TECHNICAL SUPPORT", "TAKAO SAWANO", "HIROHITO YOSHIMOTO", "HIROTO YADA" }; -const char *credits12[] = { "1TECHNICAL SUPPORT", "SGI N64 PROJECT STAFF" }; -const char *credits13[] = { "2PROGRESS MANAGEMENT", "KIMIYOSHI FUKUI", "KEIZO KATO" }; -const char *credits14[] = { "5SCREEN TEXT WRITER", "ENGLISH TRANSLATION", "LESLIE SWAN", "MINA AKINO", - "HIRO YAMADA" }; -const char *credits15[] = { "4SCREEN TEXT WRITER", "FRENCH TRANSLATION", "JULIEN BARDAKOFF", - "KENJI HARAGUCHI" }; -const char *credits16[] = { "4SCREEN TEXT WRITER", "GERMAN TRANSLATION", "THOMAS GOERG", - "THOMAS SPINDLER" }; -#endif -const char *credits17[] = { "4MARIO VOICE", "PEACH VOICE", "CHARLES MARTINET", "LESLIE SWAN" }; -const char *credits18[] = { "3SPECIAL THANKS TO", "EAD STAFF", "ALL NINTENDO PERSONNEL", -#ifdef VERSION_US - "MARIO CLUB STAFF" }; -#else // VERSION_EU - "SUPER MARIO CLUB STAFF" }; -#endif -const char *credits19[] = { "1PRODUCER", "SHIGERU MIYAMOTO" }; -const char *credits20[] = { "1EXECUTIVE PRODUCER", "HIROSHI YAMAUCHI" }; -#endif - - -struct CreditsEntry sCreditsSequence[] = { - { LEVEL_CASTLE_GROUNDS, 1, 1, -128, { 0, 8000, 0 }, NULL }, - { LEVEL_BOB, 1, 1, 117, { 713, 3918, -3889 }, credits01 }, - { LEVEL_WF, 1, 50, 46, { 347, 5376, 326 }, credits02 }, - { LEVEL_JRB, 1, 18, 22, { 3800, -4840, 2727 }, credits03 }, - { LEVEL_CCM, 2, 34, 25, { -5464, 6656, -6575 }, credits04 }, - { LEVEL_BBH, 1, 1, 60, { 257, 1922, 2580 }, credits05 }, - { LEVEL_HMC, 1, -15, 123, { -6469, 1616, -6054 }, credits06 }, - { LEVEL_THI, 3, 17, -32, { 508, 1024, 1942 }, credits07 }, - { LEVEL_LLL, 2, 33, 124, { -73, 82, -1467 }, credits08 }, - { LEVEL_SSL, 1, 65, 98, { -5906, 1024, -2576 }, credits09 }, - { LEVEL_DDD, 1, 50, 47, { -4884, -4607, -272 }, credits10 }, - { LEVEL_SL, 1, 17, -34, { 1925, 3328, 563 }, credits11 }, - { LEVEL_WDW, 1, 33, 105, { -537, 1850, 1818 }, credits12 }, - { LEVEL_TTM, 1, 2, -33, { 2613, 313, 1074 }, credits13 }, - { LEVEL_THI, 1, 51, 54, { -2609, 512, 856 }, credits14 }, - { LEVEL_TTC, 1, 17, -72, { -1304, -71, -967 }, credits15 }, - { LEVEL_RR, 1, 33, 64, { 1565, 1024, -148 }, credits16 }, - { LEVEL_SA, 1, 1, 24, { -1050, -1330, -1559 }, credits17 }, - { LEVEL_COTMC, 1, 49, -16, { -254, 415, -6045 }, credits18 }, - { LEVEL_DDD, 2, -111, -64, { 3948, 1185, -104 }, credits19 }, - { LEVEL_CCM, 1, 33, 31, { 3169, -4607, 5240 }, credits20 }, - { LEVEL_CASTLE_GROUNDS, 1, 1, -128, { 0, 906, -1200 }, NULL }, - { LEVEL_NONE, 0, 1, 0, { 0, 0, 0 }, NULL }, -}; - -struct MarioState gMarioStates[1]; -struct HudDisplay gHudDisplay; -s16 sCurrPlayMode; -u16 D_80339ECA; -s16 sTransitionTimer; -void (*sTransitionUpdate)(s16 *); -struct WarpDest sWarpDest; -s16 D_80339EE0; -s16 sDelayedWarpOp; -s16 sDelayedWarpTimer; -s16 sSourceWarpNodeId; -s32 sDelayedWarpArg; -#if defined(VERSION_EU) || defined(VERSION_SH) -s16 unusedEULevelUpdateBss1; -#endif -s8 sTimerRunning; -s8 gNeverEnteredCastle; - -struct MarioState *gMarioState = &gMarioStates[0]; -u8 unused1[4] = { 0 }; -s8 sWarpCheckpointActive = FALSE; -u8 unused3[4]; -u8 unused4[2]; - -u16 level_control_timer(s32 timerOp) { - switch (timerOp) { - case TIMER_CONTROL_SHOW: - gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIMER; - sTimerRunning = FALSE; - gHudDisplay.timer = 0; - break; - - case TIMER_CONTROL_START: - sTimerRunning = TRUE; - break; - - case TIMER_CONTROL_STOP: - sTimerRunning = FALSE; - break; - - case TIMER_CONTROL_HIDE: - gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIMER; - sTimerRunning = FALSE; - gHudDisplay.timer = 0; - break; - } - - return gHudDisplay.timer; -} - -u32 pressed_pause(void) { - u32 val4 = get_dialog_id() >= 0; - u32 intangible = (gMarioState->action & ACT_FLAG_INTANGIBLE) != 0; - - if (!intangible && !val4 && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE - && (gPlayer1Controller->buttonPressed & START_BUTTON)) { - return TRUE; - } - - return FALSE; -} - -void set_play_mode(s16 playMode) { - sCurrPlayMode = playMode; - D_80339ECA = 0; -} - -void warp_special(s32 arg) { - sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL; - D_80339ECA = 0; - D_80339EE0 = arg; -} - -void fade_into_special_warp(u32 arg, u32 color) { - if (color != 0) { - color = 0xFF; - } - - fadeout_music(190); - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x10, color, color, color); - level_set_transition(30, NULL); - - warp_special(arg); -} - -void stub_level_update_1(void) { -} - -void load_level_init_text(u32 arg) { - s32 gotAchievement; - u32 dialogID = gCurrentArea->dialog[arg]; - - switch (dialogID) { - case DIALOG_129: - gotAchievement = save_file_get_flags() & SAVE_FLAG_HAVE_VANISH_CAP; - break; - - case DIALOG_130: - gotAchievement = save_file_get_flags() & SAVE_FLAG_HAVE_METAL_CAP; - break; - - case DIALOG_131: - gotAchievement = save_file_get_flags() & SAVE_FLAG_HAVE_WING_CAP; - break; - - case 255: - gotAchievement = TRUE; - break; - - default: - gotAchievement = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1); - break; - } - - if (!gotAchievement) { - level_set_transition(-1, NULL); - create_dialog_box(dialogID); - } -} - -void init_door_warp(struct SpawnInfo *spawnInfo, u32 arg1) { - if (arg1 & 0x00000002) { - spawnInfo->startAngle[1] += 0x8000; - } - - spawnInfo->startPos[0] += 300.0f * sins(spawnInfo->startAngle[1]); - spawnInfo->startPos[2] += 300.0f * coss(spawnInfo->startAngle[1]); -} - -void set_mario_initial_cap_powerup(struct MarioState *m) { - u32 capCourseIndex = gCurrCourseNum - COURSE_CAP_COURSES; - - switch (capCourseIndex) { - case COURSE_COTMC - COURSE_CAP_COURSES: - m->flags |= MARIO_METAL_CAP | MARIO_CAP_ON_HEAD; - m->capTimer = 600; - break; - - case COURSE_TOTWC - COURSE_CAP_COURSES: - m->flags |= MARIO_WING_CAP | MARIO_CAP_ON_HEAD; - m->capTimer = 1200; - break; - - case COURSE_VCUTM - COURSE_CAP_COURSES: - m->flags |= MARIO_VANISH_CAP | MARIO_CAP_ON_HEAD; - m->capTimer = 600; - break; - } -} - -void set_mario_initial_action(struct MarioState *m, u32 spawnType, u32 actionArg) { - switch (spawnType) { - case MARIO_SPAWN_DOOR_WARP: - set_mario_action(m, ACT_WARP_DOOR_SPAWN, actionArg); - break; - case MARIO_SPAWN_UNKNOWN_02: - set_mario_action(m, ACT_IDLE, 0); - break; - case MARIO_SPAWN_UNKNOWN_03: - set_mario_action(m, ACT_EMERGE_FROM_PIPE, 0); - break; - case MARIO_SPAWN_TELEPORT: - set_mario_action(m, ACT_TELEPORT_FADE_IN, 0); - break; - case MARIO_SPAWN_INSTANT_ACTIVE: - set_mario_action(m, ACT_IDLE, 0); - break; - case MARIO_SPAWN_AIRBORNE: - set_mario_action(m, ACT_SPAWN_NO_SPIN_AIRBORNE, 0); - break; - case MARIO_SPAWN_HARD_AIR_KNOCKBACK: - set_mario_action(m, ACT_HARD_BACKWARD_AIR_KB, 0); - break; - case MARIO_SPAWN_SPIN_AIRBORNE_CIRCLE: - set_mario_action(m, ACT_SPAWN_SPIN_AIRBORNE, 0); - break; - case MARIO_SPAWN_DEATH: - set_mario_action(m, ACT_FALLING_DEATH_EXIT, 0); - break; - case MARIO_SPAWN_SPIN_AIRBORNE: - set_mario_action(m, ACT_SPAWN_SPIN_AIRBORNE, 0); - break; - case MARIO_SPAWN_FLYING: - set_mario_action(m, ACT_FLYING, 2); - break; - case MARIO_SPAWN_SWIMMING: - set_mario_action(m, ACT_WATER_IDLE, 1); - break; - case MARIO_SPAWN_PAINTING_STAR_COLLECT: - set_mario_action(m, ACT_EXIT_AIRBORNE, 0); - break; - case MARIO_SPAWN_PAINTING_DEATH: - set_mario_action(m, ACT_DEATH_EXIT, 0); - break; - case MARIO_SPAWN_AIRBORNE_STAR_COLLECT: - set_mario_action(m, ACT_FALLING_EXIT_AIRBORNE, 0); - break; - case MARIO_SPAWN_AIRBORNE_DEATH: - set_mario_action(m, ACT_UNUSED_DEATH_EXIT, 0); - break; - case MARIO_SPAWN_LAUNCH_STAR_COLLECT: - set_mario_action(m, ACT_SPECIAL_EXIT_AIRBORNE, 0); - break; - case MARIO_SPAWN_LAUNCH_DEATH: - set_mario_action(m, ACT_SPECIAL_DEATH_EXIT, 0); - break; - } - - set_mario_initial_cap_powerup(m); -} - -void init_mario_after_warp(void) { - struct ObjectWarpNode *spawnNode = area_get_warp_node(sWarpDest.nodeId); - u32 marioSpawnType = get_mario_spawn_type(spawnNode->object); - - if (gMarioState->action != ACT_UNINITIALIZED) { - gPlayerSpawnInfos[0].startPos[0] = (s16) spawnNode->object->oPosX; - gPlayerSpawnInfos[0].startPos[1] = (s16) spawnNode->object->oPosY; - gPlayerSpawnInfos[0].startPos[2] = (s16) spawnNode->object->oPosZ; - - gPlayerSpawnInfos[0].startAngle[0] = 0; - gPlayerSpawnInfos[0].startAngle[1] = spawnNode->object->oMoveAngleYaw; - gPlayerSpawnInfos[0].startAngle[2] = 0; - - if (marioSpawnType == MARIO_SPAWN_DOOR_WARP) { - init_door_warp(&gPlayerSpawnInfos[0], sWarpDest.arg); - } - - if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL || sWarpDest.type == WARP_TYPE_CHANGE_AREA) { - gPlayerSpawnInfos[0].areaIndex = sWarpDest.areaIdx; - load_mario_area(); - } - - init_mario(); - set_mario_initial_action(gMarioState, marioSpawnType, sWarpDest.arg); - - gMarioState->interactObj = spawnNode->object; - gMarioState->usedObj = spawnNode->object; - } - - reset_camera(gCurrentArea->camera); - sWarpDest.type = WARP_TYPE_NOT_WARPING; - sDelayedWarpOp = WARP_OP_NONE; - - switch (marioSpawnType) { - case MARIO_SPAWN_UNKNOWN_03: - play_transition(WARP_TRANSITION_FADE_FROM_STAR, 0x10, 0x00, 0x00, 0x00); - break; - case MARIO_SPAWN_DOOR_WARP: - play_transition(WARP_TRANSITION_FADE_FROM_CIRCLE, 0x10, 0x00, 0x00, 0x00); - break; - case MARIO_SPAWN_TELEPORT: - play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x14, 0xFF, 0xFF, 0xFF); - break; - case MARIO_SPAWN_SPIN_AIRBORNE: - play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x1A, 0xFF, 0xFF, 0xFF); - break; - case MARIO_SPAWN_SPIN_AIRBORNE_CIRCLE: - play_transition(WARP_TRANSITION_FADE_FROM_CIRCLE, 0x10, 0x00, 0x00, 0x00); - break; - case MARIO_SPAWN_UNKNOWN_27: - play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x10, 0x00, 0x00, 0x00); - break; - default: - play_transition(WARP_TRANSITION_FADE_FROM_STAR, 0x10, 0x00, 0x00, 0x00); - break; - } - - if (gCurrDemoInput == NULL) { - set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0); - - if (gMarioState->flags & MARIO_METAL_CAP) { - play_cap_music(SEQUENCE_ARGS(4, SEQ_EVENT_METAL_CAP)); - } - - if (gMarioState->flags & (MARIO_VANISH_CAP | MARIO_WING_CAP)) { - play_cap_music(SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP)); - } - -#ifndef VERSION_JP - if (gCurrLevelNum == LEVEL_BOB - && get_current_background_music() != SEQUENCE_ARGS(4, SEQ_LEVEL_SLIDE) - && sTimerRunning) { - play_music(SEQ_PLAYER_LEVEL, SEQUENCE_ARGS(4, SEQ_LEVEL_SLIDE), 0); - } -#endif - - if (sWarpDest.levelNum == LEVEL_CASTLE && sWarpDest.areaIdx == 1 -#ifndef VERSION_JP - && (sWarpDest.nodeId == 31 || sWarpDest.nodeId == 32) -#else - && sWarpDest.nodeId == 31 -#endif - ) - play_sound(SOUND_MENU_MARIO_CASTLE_WARP, gGlobalSoundSource); -#ifndef VERSION_JP - if (sWarpDest.levelNum == LEVEL_CASTLE_GROUNDS && sWarpDest.areaIdx == 1 - && (sWarpDest.nodeId == 7 || sWarpDest.nodeId == 10 || sWarpDest.nodeId == 20 - || sWarpDest.nodeId == 30)) { - play_sound(SOUND_MENU_MARIO_CASTLE_WARP, gGlobalSoundSource); - } -#endif - } -} - -// used for warps inside one level -void warp_area(void) { - if (sWarpDest.type != WARP_TYPE_NOT_WARPING) { - if (sWarpDest.type == WARP_TYPE_CHANGE_AREA) { - level_control_timer(TIMER_CONTROL_HIDE); - unload_mario_area(); - load_area(sWarpDest.areaIdx); - } - - init_mario_after_warp(); - } -} - -// used for warps between levels -void warp_level(void) { - gCurrLevelNum = sWarpDest.levelNum; - - level_control_timer(TIMER_CONTROL_HIDE); - - load_area(sWarpDest.areaIdx); - init_mario_after_warp(); -} - -void warp_credits(void) { - s32 marioAction; - - switch (sWarpDest.nodeId) { - case WARP_NODE_CREDITS_START: - marioAction = ACT_END_PEACH_CUTSCENE; - break; - - case WARP_NODE_CREDITS_NEXT: - marioAction = ACT_CREDITS_CUTSCENE; - break; - - case WARP_NODE_CREDITS_END: - marioAction = ACT_END_WAVING_CUTSCENE; - break; - } - - gCurrLevelNum = sWarpDest.levelNum; - - load_area(sWarpDest.areaIdx); - - vec3s_set(gPlayerSpawnInfos[0].startPos, gCurrCreditsEntry->marioPos[0], - gCurrCreditsEntry->marioPos[1], gCurrCreditsEntry->marioPos[2]); - - vec3s_set(gPlayerSpawnInfos[0].startAngle, 0, 0x100 * gCurrCreditsEntry->marioAngle, 0); - - gPlayerSpawnInfos[0].areaIndex = sWarpDest.areaIdx; - - load_mario_area(); - init_mario(); - - set_mario_action(gMarioState, marioAction, 0); - - reset_camera(gCurrentArea->camera); - - sWarpDest.type = WARP_TYPE_NOT_WARPING; - sDelayedWarpOp = WARP_OP_NONE; - - play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x14, 0x00, 0x00, 0x00); - - if (gCurrCreditsEntry == NULL || gCurrCreditsEntry == sCreditsSequence) { - set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0); - } -} - -void check_instant_warp(void) { - s16 cameraAngle; - struct Surface *floor; - - if (gCurrLevelNum == LEVEL_CASTLE - && save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1) >= 70) { - return; - } - - if ((floor = gMarioState->floor) != NULL) { - s32 index = floor->type - SURFACE_INSTANT_WARP_1B; - if (index >= INSTANT_WARP_INDEX_START && index < INSTANT_WARP_INDEX_STOP - && gCurrentArea->instantWarps != NULL) { - struct InstantWarp *warp = &gCurrentArea->instantWarps[index]; - - if (warp->id != 0) { - gMarioState->pos[0] += warp->displacement[0]; - gMarioState->pos[1] += warp->displacement[1]; - gMarioState->pos[2] += warp->displacement[2]; - - gMarioState->marioObj->oPosX = gMarioState->pos[0]; - gMarioState->marioObj->oPosY = gMarioState->pos[1]; - gMarioState->marioObj->oPosZ = gMarioState->pos[2]; - - cameraAngle = gMarioState->area->camera->yaw; - - change_area(warp->area); - gMarioState->area = gCurrentArea; - - warp_camera(warp->displacement[0], warp->displacement[1], warp->displacement[2]); - - gMarioState->area->camera->yaw = cameraAngle; - } - } - } -} - -s16 music_changed_through_warp(s16 arg) { - struct ObjectWarpNode *warpNode = area_get_warp_node(arg); - s16 levelNum = warpNode->node.destLevel & 0x7F; - -#if BUGFIX_KOOPA_RACE_MUSIC - - s16 destArea = warpNode->node.destArea; - s16 val4 = TRUE; - s16 sp2C; - - if (levelNum == LEVEL_BOB && levelNum == gCurrLevelNum && destArea == gCurrAreaIndex) { - sp2C = get_current_background_music(); - if (sp2C == SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP | SEQ_VARIATION) - || sp2C == SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP)) { - val4 = 0; - } - } else { - u16 val8 = gAreas[destArea].musicParam; - u16 val6 = gAreas[destArea].musicParam2; - - val4 = levelNum == gCurrLevelNum && val8 == gCurrentArea->musicParam - && val6 == gCurrentArea->musicParam2; - - if (get_current_background_music() != val6) { - val4 = FALSE; - } - } - return val4; - -#else - - u16 val8 = gAreas[warpNode->node.destArea].musicParam; - u16 val6 = gAreas[warpNode->node.destArea].musicParam2; - - s16 val4 = levelNum == gCurrLevelNum && val8 == gCurrentArea->musicParam - && val6 == gCurrentArea->musicParam2; - - if (get_current_background_music() != val6) { - val4 = FALSE; - } - return val4; - -#endif -} - -/** - * Set the current warp type and destination level/area/node. - */ -void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 arg3) { - if (destWarpNode >= WARP_NODE_CREDITS_MIN) { - sWarpDest.type = WARP_TYPE_CHANGE_LEVEL; - } else if (destLevel != gCurrLevelNum) { - sWarpDest.type = WARP_TYPE_CHANGE_LEVEL; - } else if (destArea != gCurrentArea->index) { - sWarpDest.type = WARP_TYPE_CHANGE_AREA; - } else { - sWarpDest.type = WARP_TYPE_SAME_AREA; - } - - sWarpDest.levelNum = destLevel; - sWarpDest.areaIdx = destArea; - sWarpDest.nodeId = destWarpNode; - sWarpDest.arg = arg3; -} - -// From Surface 0xD3 to 0xFC -#define PAINTING_WARP_INDEX_START 0x00 // Value greater than or equal to Surface 0xD3 -#define PAINTING_WARP_INDEX_FA 0x2A // THI Huge Painting index left -#define PAINTING_WARP_INDEX_END 0x2D // Value less than Surface 0xFD - -/** - * Check if Mario is above and close to a painting warp floor, and return the - * corresponding warp node. - */ -struct WarpNode *get_painting_warp_node(void) { - struct WarpNode *warpNode = NULL; - s32 paintingIndex = gMarioState->floor->type - SURFACE_PAINTING_WARP_D3; - - if (paintingIndex >= PAINTING_WARP_INDEX_START && paintingIndex < PAINTING_WARP_INDEX_END) { - if (paintingIndex < PAINTING_WARP_INDEX_FA - || gMarioState->pos[1] - gMarioState->floorHeight < 80.0f) { - warpNode = &gCurrentArea->paintingWarpNodes[paintingIndex]; - } - } - - return warpNode; -} - -/** - * Check is Mario has entered a painting, and if so, initiate a warp. - */ -void initiate_painting_warp(void) { - if (gCurrentArea->paintingWarpNodes != NULL && gMarioState->floor != NULL) { - struct WarpNode warpNode; - struct WarpNode *pWarpNode = get_painting_warp_node(); - - if (pWarpNode != NULL) { - if (gMarioState->action & ACT_FLAG_INTANGIBLE) { - play_painting_eject_sound(); - } else if (pWarpNode->id != 0) { - warpNode = *pWarpNode; - - if (!(warpNode.destLevel & 0x80)) { - sWarpCheckpointActive = check_warp_checkpoint(&warpNode); - } - - initiate_warp(warpNode.destLevel & 0x7F, warpNode.destArea, warpNode.destNode, 0); - check_if_should_set_warp_checkpoint(&warpNode); - - play_transition_after_delay(WARP_TRANSITION_FADE_INTO_COLOR, 30, 255, 255, 255, 45); - level_set_transition(74, basic_update); - - set_mario_action(gMarioState, ACT_DISAPPEARED, 0); - - gMarioState->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; - - play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource); - fadeout_music(398); -#if ENABLE_RUMBLE - queue_rumble_data(80, 70); - func_sh_8024C89C(1); -#endif - } - } - } -} - -/** - * If there is not already a delayed warp, schedule one. The source node is - * based on the warp operation and sometimes Mario's used object. - * Return the time left until the delayed warp is initiated. - */ -s16 level_trigger_warp(struct MarioState *m, s32 warpOp) { - s32 val04 = TRUE; - - if (sDelayedWarpOp == WARP_OP_NONE) { - m->invincTimer = -1; - sDelayedWarpArg = 0; - sDelayedWarpOp = warpOp; - - switch (warpOp) { - case WARP_OP_DEMO_NEXT: - case WARP_OP_DEMO_END: sDelayedWarpTimer = 20; // Must be one line to match on -O2 - sSourceWarpNodeId = WARP_NODE_F0; - gSavedCourseNum = COURSE_NONE; - val04 = FALSE; - play_transition(WARP_TRANSITION_FADE_INTO_STAR, 0x14, 0x00, 0x00, 0x00); - break; - - case WARP_OP_CREDITS_END: - sDelayedWarpTimer = 60; - sSourceWarpNodeId = WARP_NODE_F0; - val04 = FALSE; - gSavedCourseNum = COURSE_NONE; - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x3C, 0x00, 0x00, 0x00); - break; - - case WARP_OP_STAR_EXIT: - sDelayedWarpTimer = 32; - sSourceWarpNodeId = WARP_NODE_F0; - gSavedCourseNum = COURSE_NONE; - play_transition(WARP_TRANSITION_FADE_INTO_MARIO, 0x20, 0x00, 0x00, 0x00); - break; - - case WARP_OP_DEATH: - if (m->numLives == 0) { - sDelayedWarpOp = WARP_OP_GAME_OVER; - } - sDelayedWarpTimer = 48; - sSourceWarpNodeId = WARP_NODE_DEATH; - play_transition(WARP_TRANSITION_FADE_INTO_BOWSER, 0x30, 0x00, 0x00, 0x00); - play_sound(SOUND_MENU_BOWSER_LAUGH, gGlobalSoundSource); - break; - - case WARP_OP_WARP_FLOOR: - sSourceWarpNodeId = WARP_NODE_WARP_FLOOR; - if (area_get_warp_node(sSourceWarpNodeId) == NULL) { - if (m->numLives == 0) { - sDelayedWarpOp = WARP_OP_GAME_OVER; - } else { - sSourceWarpNodeId = WARP_NODE_DEATH; - } - } - sDelayedWarpTimer = 20; - play_transition(WARP_TRANSITION_FADE_INTO_CIRCLE, 0x14, 0x00, 0x00, 0x00); - break; - - case WARP_OP_UNKNOWN_01: // enter totwc - sDelayedWarpTimer = 30; - sSourceWarpNodeId = WARP_NODE_F2; - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x1E, 0xFF, 0xFF, 0xFF); -#ifndef VERSION_JP - play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource); -#endif - break; - - case WARP_OP_UNKNOWN_02: // bbh enter - sDelayedWarpTimer = 30; - sSourceWarpNodeId = (m->usedObj->oBehParams & 0x00FF0000) >> 16; - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x1E, 0xFF, 0xFF, 0xFF); - break; - - case WARP_OP_TELEPORT: - sDelayedWarpTimer = 20; - sSourceWarpNodeId = (m->usedObj->oBehParams & 0x00FF0000) >> 16; - val04 = !music_changed_through_warp(sSourceWarpNodeId); - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x14, 0xFF, 0xFF, 0xFF); - break; - - case WARP_OP_WARP_DOOR: - sDelayedWarpTimer = 20; - sDelayedWarpArg = m->actionArg; - sSourceWarpNodeId = (m->usedObj->oBehParams & 0x00FF0000) >> 16; - val04 = !music_changed_through_warp(sSourceWarpNodeId); - play_transition(WARP_TRANSITION_FADE_INTO_CIRCLE, 0x14, 0x00, 0x00, 0x00); - break; - - case WARP_OP_WARP_OBJECT: - sDelayedWarpTimer = 20; - sSourceWarpNodeId = (m->usedObj->oBehParams & 0x00FF0000) >> 16; - val04 = !music_changed_through_warp(sSourceWarpNodeId); - play_transition(WARP_TRANSITION_FADE_INTO_STAR, 0x14, 0x00, 0x00, 0x00); - break; - - case WARP_OP_CREDITS_START: - sDelayedWarpTimer = 30; - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x1E, 0x00, 0x00, 0x00); - break; - - case WARP_OP_CREDITS_NEXT: - if (gCurrCreditsEntry == &sCreditsSequence[0]) { - sDelayedWarpTimer = 60; - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x3C, 0x00, 0x00, 0x00); - } else { - sDelayedWarpTimer = 20; - play_transition(WARP_TRANSITION_FADE_INTO_COLOR, 0x14, 0x00, 0x00, 0x00); - } - val04 = FALSE; - break; - } - - if (val04 && gCurrDemoInput == NULL) { - fadeout_music((3 * sDelayedWarpTimer / 2) * 8 - 2); - } - } - - return sDelayedWarpTimer; -} - -/** - * If a delayed warp is ready, initiate it. - */ -void initiate_delayed_warp(void) { - struct ObjectWarpNode *warpNode; - s32 destWarpNode; - - if (sDelayedWarpOp != WARP_OP_NONE && --sDelayedWarpTimer == 0) { - reset_dialog_render_state(); - - if (gDebugLevelSelect && (sDelayedWarpOp & WARP_OP_TRIGGERS_LEVEL_SELECT)) { - warp_special(-9); - } else if (gCurrDemoInput != NULL) { - if (sDelayedWarpOp == WARP_OP_DEMO_END) { - warp_special(-8); - } else { - warp_special(-2); - } - } else { - switch (sDelayedWarpOp) { - case WARP_OP_GAME_OVER: - save_file_reload(); - warp_special(-3); - break; - - case WARP_OP_CREDITS_END: - warp_special(-1); - sound_banks_enable(SEQ_PLAYER_SFX, - SOUND_BANKS_ALL & ~SOUND_BANKS_DISABLED_AFTER_CREDITS); - break; - - case WARP_OP_DEMO_NEXT: - warp_special(-2); - break; - - case WARP_OP_CREDITS_START: - gCurrCreditsEntry = &sCreditsSequence[0]; - initiate_warp(gCurrCreditsEntry->levelNum, gCurrCreditsEntry->areaIndex, - WARP_NODE_CREDITS_START, 0); - break; - - case WARP_OP_CREDITS_NEXT: - sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_ALL); - - gCurrCreditsEntry += 1; - gCurrActNum = gCurrCreditsEntry->unk02 & 0x07; - if ((gCurrCreditsEntry + 1)->levelNum == LEVEL_NONE) { - destWarpNode = WARP_NODE_CREDITS_END; - } else { - destWarpNode = WARP_NODE_CREDITS_NEXT; - } - - initiate_warp(gCurrCreditsEntry->levelNum, gCurrCreditsEntry->areaIndex, - destWarpNode, 0); - break; - - default: - warpNode = area_get_warp_node(sSourceWarpNodeId); - - initiate_warp(warpNode->node.destLevel & 0x7F, warpNode->node.destArea, - warpNode->node.destNode, sDelayedWarpArg); - - check_if_should_set_warp_checkpoint(&warpNode->node); - if (sWarpDest.type != WARP_TYPE_CHANGE_LEVEL) { - level_set_transition(2, NULL); - } - break; - } - } - } -} - -void update_hud_values(void) { - if (gCurrCreditsEntry == NULL) { - s16 numHealthWedges = gMarioState->health > 0 ? gMarioState->health >> 8 : 0; - - if (gCurrCourseNum >= COURSE_MIN) { - gHudDisplay.flags |= HUD_DISPLAY_FLAG_COIN_COUNT; - } else { - gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_COIN_COUNT; - } - - if (gHudDisplay.coins < gMarioState->numCoins) { - if (gGlobalTimer & 0x00000001) { - u32 coinSound; - if (gMarioState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) { - coinSound = SOUND_GENERAL_COIN_WATER; - } else { - coinSound = SOUND_GENERAL_COIN; - } - - gHudDisplay.coins += 1; - play_sound(coinSound, gMarioState->marioObj->header.gfx.cameraToObject); - } - } - - if (gMarioState->numLives > 100) { - gMarioState->numLives = 100; - } - -#if BUGFIX_MAX_LIVES - if (gMarioState->numCoins > 999) { - gMarioState->numCoins = 999; - } - - if (gHudDisplay.coins > 999) { - gHudDisplay.coins = 999; - } -#else - if (gMarioState->numCoins > 999) { - gMarioState->numLives = (s8) 999; //! Wrong variable - } -#endif - - gHudDisplay.stars = gMarioState->numStars; - gHudDisplay.lives = gMarioState->numLives; - gHudDisplay.keys = gMarioState->numKeys; - - if (numHealthWedges > gHudDisplay.wedges) { - play_sound(SOUND_MENU_POWER_METER, gGlobalSoundSource); - } - gHudDisplay.wedges = numHealthWedges; - - if (gMarioState->hurtCounter > 0) { - gHudDisplay.flags |= HUD_DISPLAY_FLAG_EMPHASIZE_POWER; - } else { - gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_EMPHASIZE_POWER; - } - } -} - -/** - * Update objects, HUD, and camera. This update function excludes things like - * endless staircase, warps, pausing, etc. This is used when entering a painting, - * presumably to allow painting and camera updating while avoiding triggering the - * warp twice. - */ -void basic_update(UNUSED s16 *arg) { - area_update_objects(); - update_hud_values(); - - if (gCurrentArea != NULL) { - update_camera(gCurrentArea->camera); - } -} - -s32 play_mode_normal(void) { - if (gCurrDemoInput != NULL) { - print_intro_text(); - if (gPlayer1Controller->buttonPressed & END_DEMO) { - level_trigger_warp(gMarioState, - gCurrLevelNum == LEVEL_PSS ? WARP_OP_DEMO_END : WARP_OP_DEMO_NEXT); - } else if (!gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE - && (gPlayer1Controller->buttonPressed & START_BUTTON)) { - level_trigger_warp(gMarioState, WARP_OP_DEMO_NEXT); - } - } - - warp_area(); - check_instant_warp(); - - if (sTimerRunning && gHudDisplay.timer < 17999) { - gHudDisplay.timer += 1; - } - - area_update_objects(); - update_hud_values(); - - if (gCurrentArea != NULL) { - update_camera(gCurrentArea->camera); - } - - initiate_painting_warp(); - initiate_delayed_warp(); - - // If either initiate_painting_warp or initiate_delayed_warp initiated a - // warp, change play mode accordingly. - if (sCurrPlayMode == PLAY_MODE_NORMAL) { - if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) { - set_play_mode(PLAY_MODE_CHANGE_LEVEL); - } else if (sTransitionTimer != 0) { - set_play_mode(PLAY_MODE_CHANGE_AREA); - } else if (pressed_pause()) { - lower_background_noise(1); -#if ENABLE_RUMBLE - cancel_rumble(); -#endif - gCameraMovementFlags |= CAM_MOVE_PAUSE_SCREEN; - set_play_mode(PLAY_MODE_PAUSED); - } - } - - return 0; -} - -s32 play_mode_paused(void) { - if (gPauseScreenMode == 0) { - set_menu_mode(RENDER_PAUSE_SCREEN); - } else if (gPauseScreenMode == 1) { - raise_background_noise(1); - gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; - set_play_mode(PLAY_MODE_NORMAL); - } else { - // Exit level - - if (gDebugLevelSelect) { - fade_into_special_warp(-9, 1); - } else { - initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); - fade_into_special_warp(0, 0); - gSavedCourseNum = COURSE_NONE; - } - - gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; - } - - return 0; -} - -/** - * Debug mode that lets you frame advance by pressing D-pad down. Unfortunately - * it uses the pause camera, making it basically unusable in most levels. - */ -s32 play_mode_frame_advance(void) { - if (gPlayer1Controller->buttonPressed & D_JPAD) { - gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; - play_mode_normal(); - } else if (gPlayer1Controller->buttonPressed & START_BUTTON) { - gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; - raise_background_noise(1); - set_play_mode(PLAY_MODE_NORMAL); - } else { - gCameraMovementFlags |= CAM_MOVE_PAUSE_SCREEN; - } - - return 0; -} - -/** - * Set the transition, which is a period of time after the warp is initiated - * but before it actually occurs. If updateFunction is not NULL, it will be - * called each frame during the transition. - */ -void level_set_transition(s16 length, void (*updateFunction)(s16 *)) { - sTransitionTimer = length; - sTransitionUpdate = updateFunction; -} - -/** - * Play the transition and then return to normal play mode. - */ -s32 play_mode_change_area(void) { - //! This maybe was supposed to be sTransitionTimer == -1? sTransitionUpdate - // is never set to -1. - if (sTransitionUpdate == (void (*)(s16 *)) - 1) { - update_camera(gCurrentArea->camera); - } else if (sTransitionUpdate != NULL) { - sTransitionUpdate(&sTransitionTimer); - } - - if (sTransitionTimer > 0) { - sTransitionTimer -= 1; - } - - if (sTransitionTimer == 0) { - sTransitionUpdate = NULL; - set_play_mode(PLAY_MODE_NORMAL); - } - - return 0; -} - -/** - * Play the transition and then return to normal play mode. - */ -s32 play_mode_change_level(void) { - if (sTransitionUpdate != NULL) { - sTransitionUpdate(&sTransitionTimer); - } - - if (--sTransitionTimer == -1) { - gHudDisplay.flags = HUD_DISPLAY_NONE; - sTransitionTimer = 0; - sTransitionUpdate = NULL; - - if (sWarpDest.type != WARP_TYPE_NOT_WARPING) { - return sWarpDest.levelNum; - } else { - return D_80339EE0; - } - } - - return 0; -} - -/** - * Unused play mode. Doesn't call transition update and doesn't reset transition at the end. - */ -static s32 play_mode_unused(void) { - if (--sTransitionTimer == -1) { - gHudDisplay.flags = HUD_DISPLAY_NONE; - - if (sWarpDest.type != WARP_TYPE_NOT_WARPING) { - return sWarpDest.levelNum; - } else { - return D_80339EE0; - } - } - - return 0; -} - -s32 update_level(void) { - s32 changeLevel; - - switch (sCurrPlayMode) { - case PLAY_MODE_NORMAL: - changeLevel = play_mode_normal(); - break; - case PLAY_MODE_PAUSED: - changeLevel = play_mode_paused(); - break; - case PLAY_MODE_CHANGE_AREA: - changeLevel = play_mode_change_area(); - break; - case PLAY_MODE_CHANGE_LEVEL: - changeLevel = play_mode_change_level(); - break; - case PLAY_MODE_FRAME_ADVANCE: - changeLevel = play_mode_frame_advance(); - break; - } - - if (changeLevel) { - reset_volume(); - enable_background_sound(); - } - - return changeLevel; -} - -s32 init_level(void) { - s32 val4 = 0; - - set_play_mode(PLAY_MODE_NORMAL); - - sDelayedWarpOp = WARP_OP_NONE; - sTransitionTimer = 0; - D_80339EE0 = 0; - - if (gCurrCreditsEntry == NULL) { - gHudDisplay.flags = HUD_DISPLAY_DEFAULT; - } else { - gHudDisplay.flags = HUD_DISPLAY_NONE; - } - - sTimerRunning = FALSE; - - if (sWarpDest.type != WARP_TYPE_NOT_WARPING) { - if (sWarpDest.nodeId >= WARP_NODE_CREDITS_MIN) { - warp_credits(); - } else { - warp_level(); - } - } else { - if (gPlayerSpawnInfos[0].areaIndex >= 0) { - load_mario_area(); - init_mario(); - } - - if (gCurrentArea != NULL) { - reset_camera(gCurrentArea->camera); - - if (gCurrDemoInput != NULL) { - set_mario_action(gMarioState, ACT_IDLE, 0); - } else if (gDebugLevelSelect == 0) { - if (gMarioState->action != ACT_UNINITIALIZED) { - set_mario_action(gMarioState, ACT_IDLE, 0); - } - } - } - - if (val4 != 0) { - play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x5A, 0xFF, 0xFF, 0xFF); - } else { - play_transition(WARP_TRANSITION_FADE_FROM_STAR, 0x10, 0xFF, 0xFF, 0xFF); - } - - if (gCurrDemoInput == NULL) { - set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0); - } - } -#if ENABLE_RUMBLE - if (gCurrDemoInput == NULL) { - cancel_rumble(); - } -#endif - - if (gMarioState->action == ACT_INTRO_CUTSCENE) { - sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_DISABLED_DURING_INTRO_CUTSCENE); - } - - return 1; -} - -/** - * Initialize the current level if initOrUpdate is 0, or update the level if it is 1. - */ -s32 lvl_init_or_update(s16 initOrUpdate, UNUSED s32 unused) { - s32 result = 0; - - switch (initOrUpdate) { - case 0: - result = init_level(); - break; - case 1: - result = update_level(); - break; - } - - return result; -} - -s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum) { -#ifdef VERSION_EU - s16 var = eu_get_language(); - switch (var) { - case LANGUAGE_ENGLISH: - load_segment_decompress(0x19, _translation_en_yay0SegmentRomStart, - _translation_en_yay0SegmentRomEnd); - break; - case LANGUAGE_FRENCH: - load_segment_decompress(0x19, _translation_fr_yay0SegmentRomStart, - _translation_fr_yay0SegmentRomEnd); - break; - case LANGUAGE_GERMAN: - load_segment_decompress(0x19, _translation_de_yay0SegmentRomStart, - _translation_de_yay0SegmentRomEnd); - break; - } -#endif - sWarpDest.type = WARP_TYPE_NOT_WARPING; - sDelayedWarpOp = WARP_OP_NONE; - gNeverEnteredCastle = !save_file_exists(gCurrSaveFileNum - 1); - - gCurrLevelNum = levelNum; - gCurrCourseNum = COURSE_NONE; - gSavedCourseNum = COURSE_NONE; - gCurrCreditsEntry = NULL; - gSpecialTripleJump = FALSE; - - init_mario_from_save_file(); - disable_warp_checkpoint(); - save_file_move_cap_to_default_location(); - select_mario_cam_mode(); - set_yoshi_as_not_dead(); - - return levelNum; -} - -s32 lvl_set_current_level(UNUSED s16 arg0, s32 levelNum) { - s32 warpCheckpointActive = sWarpCheckpointActive; - - sWarpCheckpointActive = FALSE; - gCurrLevelNum = levelNum; - gCurrCourseNum = gLevelToCourseNumTable[levelNum - 1]; - - if (gCurrDemoInput != NULL || gCurrCreditsEntry != NULL || gCurrCourseNum == COURSE_NONE) { - return 0; - } - - if (gCurrLevelNum != LEVEL_BOWSER_1 && gCurrLevelNum != LEVEL_BOWSER_2 - && gCurrLevelNum != LEVEL_BOWSER_3) { - gMarioState->numCoins = 0; - gHudDisplay.coins = 0; - gCurrCourseStarFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1); - } - - if (gSavedCourseNum != gCurrCourseNum) { - gSavedCourseNum = gCurrCourseNum; - nop_change_course(); - disable_warp_checkpoint(); - } - - if (gCurrCourseNum > COURSE_STAGES_MAX || warpCheckpointActive) { - return 0; - } - - if (gDebugLevelSelect && !gShowProfiler) { - return 0; - } - - return 1; -} - -/** - * Play the "thank you so much for to playing my game" sound. - */ -s32 lvl_play_the_end_screen_sound(UNUSED s16 arg0, UNUSED s32 arg1) { - play_sound(SOUND_MENU_THANK_YOU_PLAYING_MY_GAME, gGlobalSoundSource); - return 1; -} diff --git a/src/game/rendering_graph_node.c.orig b/src/game/rendering_graph_node.c.orig deleted file mode 100644 index a3007a59..00000000 --- a/src/game/rendering_graph_node.c.orig +++ /dev/null @@ -1,1092 +0,0 @@ -#include - -#include "area.h" -#include "engine/math_util.h" -#include "game_init.h" -#include "gfx_dimensions.h" -#include "main.h" -#include "memory.h" -#include "print.h" -#include "rendering_graph_node.h" -#include "shadow.h" -#include "sm64.h" - -/** - * This file contains the code that processes the scene graph for rendering. - * The scene graph is responsible for drawing everything except the HUD / text boxes. - * First the root of the scene graph is processed when geo_process_root - * is called from level_script.c. The rest of the tree is traversed recursively - * using the function geo_process_node_and_siblings, which switches over all - * geo node types and calls a specialized function accordingly. - * The types are defined in engine/graph_node.h - * - * The scene graph typically looks like: - * - Root (viewport) - * - Master list - * - Ortho projection - * - Background (skybox) - * - Master list - * - Perspective - * - Camera - * - - * - Object parent - * - - * - Master list - * - Script node (Cannon overlay) - * - */ - -s16 gMatStackIndex; -Mat4 gMatStack[32]; -Mtx *gMatStackFixed[32]; - -/** - * Animation nodes have state in global variables, so this struct captures - * the animation state so a 'context switch' can be made when rendering the - * held object. - */ -struct GeoAnimState { - /*0x00*/ u8 type; - /*0x01*/ u8 enabled; - /*0x02*/ s16 frame; - /*0x04*/ f32 translationMultiplier; - /*0x08*/ u16 *attribute; - /*0x0C*/ s16 *data; -}; - -// For some reason, this is a GeoAnimState struct, but the current state consists -// of separate global variables. It won't match EU otherwise. -struct GeoAnimState gGeoTempState; - -u8 gCurAnimType; -u8 gCurAnimEnabled; -s16 gCurrAnimFrame; -f32 gCurAnimTranslationMultiplier; -u16 *gCurrAnimAttribute; -s16 *gCurAnimData; - -struct AllocOnlyPool *gDisplayListHeap; - -struct RenderModeContainer { - u32 modes[8]; -}; - -/* Rendermode settings for cycle 1 for all 8 layers. */ -struct RenderModeContainer renderModeTable_1Cycle[2] = { { { - G_RM_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_TEX_EDGE, - G_RM_AA_XLU_SURF, - G_RM_AA_XLU_SURF, - G_RM_AA_XLU_SURF, - } }, - { { - /* z-buffered */ - G_RM_ZB_OPA_SURF, - G_RM_AA_ZB_OPA_SURF, - G_RM_AA_ZB_OPA_DECAL, - G_RM_AA_ZB_OPA_INTER, - G_RM_AA_ZB_TEX_EDGE, - G_RM_AA_ZB_XLU_SURF, - G_RM_AA_ZB_XLU_DECAL, - G_RM_AA_ZB_XLU_INTER, - } } }; - -/* Rendermode settings for cycle 2 for all 8 layers. */ -struct RenderModeContainer renderModeTable_2Cycle[2] = { { { - G_RM_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_TEX_EDGE2, - G_RM_AA_XLU_SURF2, - G_RM_AA_XLU_SURF2, - G_RM_AA_XLU_SURF2, - } }, - { { - /* z-buffered */ - G_RM_ZB_OPA_SURF2, - G_RM_AA_ZB_OPA_SURF2, - G_RM_AA_ZB_OPA_DECAL2, - G_RM_AA_ZB_OPA_INTER2, - G_RM_AA_ZB_TEX_EDGE2, - G_RM_AA_ZB_XLU_SURF2, - G_RM_AA_ZB_XLU_DECAL2, - G_RM_AA_ZB_XLU_INTER2, - } } }; - -struct GraphNodeRoot *gCurGraphNodeRoot = NULL; -struct GraphNodeMasterList *gCurGraphNodeMasterList = NULL; -struct GraphNodePerspective *gCurGraphNodeCamFrustum = NULL; -struct GraphNodeCamera *gCurGraphNodeCamera = NULL; -struct GraphNodeObject *gCurGraphNodeObject = NULL; -struct GraphNodeHeldObject *gCurGraphNodeHeldObject = NULL; -u16 gAreaUpdateCounter = 0; - -#ifdef F3DEX_GBI_2 -LookAt lookAt; -#endif - -/** - * Process a master list node. - */ -static void geo_process_master_list_sub(struct GraphNodeMasterList *node) { - struct DisplayListNode *currList; - s32 i; - s32 enableZBuffer = (node->node.flags & GRAPH_RENDER_Z_BUFFER) != 0; - struct RenderModeContainer *modeList = &renderModeTable_1Cycle[enableZBuffer]; - struct RenderModeContainer *mode2List = &renderModeTable_2Cycle[enableZBuffer]; - - // @bug This is where the LookAt values should be calculated but aren't. - // As a result, environment mapping is broken on Fast3DEX2 without the - // changes below. -#ifdef F3DEX_GBI_2 - Mtx lMtx; - guLookAtReflect(&lMtx, &lookAt, 0, 0, 0, /* eye */ 0, 0, 1, /* at */ 1, 0, 0 /* up */); -#endif - - if (enableZBuffer != 0) { - gDPPipeSync(gDisplayListHead++); - gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER); - } - - for (i = 0; i < GFX_NUM_MASTER_LISTS; i++) { - if ((currList = node->listHeads[i]) != NULL) { - gDPSetRenderMode(gDisplayListHead++, modeList->modes[i], mode2List->modes[i]); - while (currList != NULL) { - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transform), - G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - gSPDisplayList(gDisplayListHead++, currList->displayList); - currList = currList->next; - } - } - } - if (enableZBuffer != 0) { - gDPPipeSync(gDisplayListHead++); - gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER); - } -} - -/** - * Appends the display list to one of the master lists based on the layer - * parameter. Look at the RenderModeContainer struct to see the corresponding - * render modes of layers. - */ -static void geo_append_display_list(void *displayList, s16 layer) { - -#ifdef F3DEX_GBI_2 - gSPLookAt(gDisplayListHead++, &lookAt); -#endif - if (gCurGraphNodeMasterList != 0) { - struct DisplayListNode *listNode = - alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode)); - - listNode->transform = gMatStackFixed[gMatStackIndex]; - listNode->displayList = displayList; - listNode->next = 0; - if (gCurGraphNodeMasterList->listHeads[layer] == 0) { - gCurGraphNodeMasterList->listHeads[layer] = listNode; - } else { - gCurGraphNodeMasterList->listTails[layer]->next = listNode; - } - gCurGraphNodeMasterList->listTails[layer] = listNode; - } -} - -/** - * Process the master list node. - */ -static void geo_process_master_list(struct GraphNodeMasterList *node) { - s32 i; - UNUSED s32 sp1C; - - if (gCurGraphNodeMasterList == NULL && node->node.children != NULL) { - gCurGraphNodeMasterList = node; - for (i = 0; i < GFX_NUM_MASTER_LISTS; i++) { - node->listHeads[i] = NULL; - } - geo_process_node_and_siblings(node->node.children); - geo_process_master_list_sub(node); - gCurGraphNodeMasterList = NULL; - } -} - -/** - * Process an orthographic projection node. - */ -static void geo_process_ortho_projection(struct GraphNodeOrthoProjection *node) { - if (node->node.children != NULL) { - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - f32 left = (gCurGraphNodeRoot->x - gCurGraphNodeRoot->width) / 2.0f * node->scale; - f32 right = (gCurGraphNodeRoot->x + gCurGraphNodeRoot->width) / 2.0f * node->scale; - f32 top = (gCurGraphNodeRoot->y - gCurGraphNodeRoot->height) / 2.0f * node->scale; - f32 bottom = (gCurGraphNodeRoot->y + gCurGraphNodeRoot->height) / 2.0f * node->scale; - - guOrtho(mtx, left, right, bottom, top, -2.0f, 2.0f, 1.0f); - gSPPerspNormalize(gDisplayListHead++, 0xFFFF); - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); - - geo_process_node_and_siblings(node->node.children); - } -} - -/** - * Process a perspective projection node. - */ -static void geo_process_perspective(struct GraphNodePerspective *node) { - if (node->fnNode.func != NULL) { - node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]); - } - if (node->fnNode.node.children != NULL) { - u16 perspNorm; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - -#ifdef VERSION_EU - f32 aspect = ((f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height) * 1.1f; -#else - f32 aspect = (f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height; -#endif - - guPerspective(mtx, &perspNorm, node->fov, aspect, node->near / WORLD_SCALE, node->far / WORLD_SCALE, 1.0f); - gSPPerspNormalize(gDisplayListHead++, perspNorm); - - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); - - gCurGraphNodeCamFrustum = node; - geo_process_node_and_siblings(node->fnNode.node.children); - gCurGraphNodeCamFrustum = NULL; - } -} - -/** - * Process a level of detail node. From the current transformation matrix, - * the perpendicular distance to the camera is extracted and the children - * of this node are only processed if that distance is within the render - * range of this node. - */ -static void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) { - f32 distanceFromCam; - if (gIsConsole) { - distanceFromCam = -gMatStack[gMatStackIndex][3][2]; - } else { - distanceFromCam = 50; - } - - if ((f32)node->minDistance <= distanceFromCam && distanceFromCam < (f32)node->maxDistance) { - if (node->node.children != 0) { - geo_process_node_and_siblings(node->node.children); - } - } -} - -/** - * Process a switch case node. The node's selection function is called - * if it is 0, and among the node's children, only the selected child is - * processed next. - */ -static void geo_process_switch(struct GraphNodeSwitchCase *node) { - struct GraphNode *selectedChild = node->fnNode.node.children; - s32 i; - - if (node->fnNode.func != NULL) { - node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]); - } - for (i = 0; selectedChild != NULL && node->selectedCase > i; i++) { - selectedChild = selectedChild->next; - } - if (selectedChild != NULL) { - geo_process_node_and_siblings(selectedChild); - } -} - -static void make_roll_matrix(Mtx *mtx, s16 angle) { - Mat4 temp; - - mtxf_identity(temp); - temp[0][0] = coss(angle); - temp[0][1] = sins(angle); - temp[1][0] = -temp[0][1]; - temp[1][1] = temp[0][0]; - guMtxF2L(temp, mtx); -} - -/** - * Process a camera node. - */ -static void geo_process_camera(struct GraphNodeCamera *node) { - Mat4 cameraTransform; - Mtx *rollMtx = alloc_display_list(sizeof(*rollMtx)); - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - if (node->fnNode.func != NULL) { - node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]); - } - make_roll_matrix(rollMtx, node->rollScreen); - - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(rollMtx), G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH); - - mtxf_lookat(cameraTransform, node->pos, node->focus, node->roll); - mtxf_mul(gMatStack[gMatStackIndex + 1], cameraTransform, gMatStack[gMatStackIndex]); - gMatStackIndex++; - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->fnNode.node.children != 0) { - gCurGraphNodeCamera = node; - node->matrixPtr = &gMatStack[gMatStackIndex]; - geo_process_node_and_siblings(node->fnNode.node.children); - gCurGraphNodeCamera = NULL; - } - gMatStackIndex--; -} - -/** - * Process a translation / rotation node. A transformation matrix based - * on the node's translation and rotation is created and pushed on both - * the float and fixed point matrix stacks. - * For the rest it acts as a normal display list node. - */ -static void geo_process_translation_rotation(struct GraphNodeTranslationRotation *node) { - Mat4 mtxf; - Vec3f translation; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - vec3s_to_vec3f(translation, node->translation); - mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation); - mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); - gMatStackIndex++; - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gMatStackIndex--; -} - -/** - * Process a translation node. A transformation matrix based on the node's - * translation is created and pushed on both the float and fixed point matrix stacks. - * For the rest it acts as a normal display list node. - */ -static void geo_process_translation(struct GraphNodeTranslation *node) { - Mat4 mtxf; - Vec3f translation; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - vec3s_to_vec3f(translation, node->translation); - mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero); - mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); - gMatStackIndex++; - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gMatStackIndex--; -} - -/** - * Process a rotation node. A transformation matrix based on the node's - * rotation is created and pushed on both the float and fixed point matrix stacks. - * For the rest it acts as a normal display list node. - */ -static void geo_process_rotation(struct GraphNodeRotation *node) { - Mat4 mtxf; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation); - mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); - gMatStackIndex++; - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gMatStackIndex--; -} - -/** - * Process a scaling node. A transformation matrix based on the node's - * scale is created and pushed on both the float and fixed point matrix stacks. - * For the rest it acts as a normal display list node. - */ -static void geo_process_scale(struct GraphNodeScale *node) { - UNUSED Mat4 transform; - Vec3f scaleVec; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - vec3f_set(scaleVec, node->scale, node->scale, node->scale); - mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec); - gMatStackIndex++; - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gMatStackIndex--; -} - -/** - * Process a billboard node. A transformation matrix is created that makes its - * children face the camera, and it is pushed on the floating point and fixed - * point matrix stacks. - * For the rest it acts as a normal display list node. - */ -static void geo_process_billboard(struct GraphNodeBillboard *node) { - Vec3f translation; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - gMatStackIndex++; - vec3s_to_vec3f(translation, node->translation); - mtxf_billboard(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex - 1], translation, - gCurGraphNodeCamera->roll); - if (gCurGraphNodeHeldObject != NULL) { - mtxf_scale_vec3f(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex], - gCurGraphNodeHeldObject->objNode->header.gfx.scale); - } else if (gCurGraphNodeObject != NULL) { - mtxf_scale_vec3f(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex], - gCurGraphNodeObject->scale); - } - - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gMatStackIndex--; -} - -/** - * Process a display list node. It draws a display list without first pushing - * a transformation on the stack, so all transformations are inherited from the - * parent node. It processes its children if it has them. - */ -static void geo_process_display_list(struct GraphNodeDisplayList *node) { - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } -} - -/** - * Process a generated list. Instead of storing a pointer to a display list, - * the list is generated on the fly by a function. - */ -static void geo_process_generated_list(struct GraphNodeGenerated *node) { - if (node->fnNode.func != NULL) { - Gfx *list = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, - (struct AllocOnlyPool *) gMatStack[gMatStackIndex]); - - if (list != NULL) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(list), node->fnNode.node.flags >> 8); - } - } - if (node->fnNode.node.children != NULL) { - geo_process_node_and_siblings(node->fnNode.node.children); - } -} - -/** - * Process a background node. Tries to retrieve a background display list from - * the function of the node. If that function is null or returns null, a black - * rectangle is drawn instead. - */ -static void geo_process_background(struct GraphNodeBackground *node) { - Gfx *list = NULL; - - if (node->fnNode.func != NULL) { - list = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, - (struct AllocOnlyPool *) gMatStack[gMatStackIndex]); - } - if (list != NULL) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(list), node->fnNode.node.flags >> 8); - } else if (gCurGraphNodeMasterList != NULL) { -#ifndef F3DEX_GBI_2E - Gfx *gfxStart = alloc_display_list(sizeof(Gfx) * 7); -#else - Gfx *gfxStart = alloc_display_list(sizeof(Gfx) * 8); -#endif - Gfx *gfx = gfxStart; - - gDPPipeSync(gfx++); - gDPSetCycleType(gfx++, G_CYC_FILL); - gDPSetFillColor(gfx++, node->background); - gDPFillRectangle(gfx++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - BORDER_HEIGHT - 1); - gDPPipeSync(gfx++); - gDPSetCycleType(gfx++, G_CYC_1CYCLE); - gSPEndDisplayList(gfx++); - - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(gfxStart), 0); - } - if (node->fnNode.node.children != NULL) { - geo_process_node_and_siblings(node->fnNode.node.children); - } -} - -/** - * Render an animated part. The current animation state is not part of the node - * but set in global variables. If an animated part is skipped, everything afterwards desyncs. - */ -static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { - Mat4 matrix; - Vec3s rotation; - Vec3f translation; - Mtx *matrixPtr = alloc_display_list(sizeof(*matrixPtr)); - - vec3s_copy(rotation, gVec3sZero); - vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]); - if (gCurAnimType == ANIM_TYPE_TRANSLATION) { - translation[0] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - translation[1] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - translation[2] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurAnimType = ANIM_TYPE_ROTATION; - } else { - if (gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) { - translation[0] += - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurrAnimAttribute += 2; - translation[2] += - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurAnimType = ANIM_TYPE_ROTATION; - } else { - if (gCurAnimType == ANIM_TYPE_VERTICAL_TRANSLATION) { - gCurrAnimAttribute += 2; - translation[1] += - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurrAnimAttribute += 2; - gCurAnimType = ANIM_TYPE_ROTATION; - } else if (gCurAnimType == ANIM_TYPE_NO_TRANSLATION) { - gCurrAnimAttribute += 6; - gCurAnimType = ANIM_TYPE_ROTATION; - } - } - } - - if (gCurAnimType == ANIM_TYPE_ROTATION) { - rotation[0] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]; - rotation[1] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]; - rotation[2] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]; - } - mtxf_rotate_xyz_and_translate(matrix, translation, rotation); - mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]); - gMatStackIndex++; - mtxf_to_mtx(matrixPtr, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = matrixPtr; - if (node->displayList != NULL) { - geo_append_display_list(node->displayList, node->node.flags >> 8); - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gMatStackIndex--; -} - -/** - * Initialize the animation-related global variables for the currently drawn - * object's animation. - */ -void geo_set_animation_globals(struct AnimInfo *node, s32 hasAnimation) { - struct Animation *anim = node->curAnim; - - if (hasAnimation) { - node->animFrame = geo_update_animation_frame(node, &node->animFrameAccelAssist); - } - node->animTimer = gAreaUpdateCounter; - if (anim->flags & ANIM_FLAG_HOR_TRANS) { - gCurAnimType = ANIM_TYPE_VERTICAL_TRANSLATION; - } else if (anim->flags & ANIM_FLAG_VERT_TRANS) { - gCurAnimType = ANIM_TYPE_LATERAL_TRANSLATION; - } else if (anim->flags & ANIM_FLAG_6) { - gCurAnimType = ANIM_TYPE_NO_TRANSLATION; - } else { - gCurAnimType = ANIM_TYPE_TRANSLATION; - } - - gCurrAnimFrame = node->animFrame; - gCurAnimEnabled = (anim->flags & ANIM_FLAG_5) == 0; - gCurrAnimAttribute = segmented_to_virtual((void *) anim->index); - gCurAnimData = segmented_to_virtual((void *) anim->values); - - if (anim->animYTransDivisor == 0) { - gCurAnimTranslationMultiplier = 1.0f; - } else { - gCurAnimTranslationMultiplier = (f32) node->animYTrans / (f32) anim->animYTransDivisor; - } -} - -/** - * Process a shadow node. Renders a shadow under an object offset by the - * translation of the first animated component and rotated according to - * the floor below it. - */ -static void geo_process_shadow(struct GraphNodeShadow *node) { - Gfx *shadowList; - Mat4 mtxf; - Vec3f shadowPos; - Vec3f animOffset; - f32 objScale; - f32 shadowScale; - f32 sinAng; - f32 cosAng; - struct GraphNode *geo; - Mtx *mtx; - - if (gCurGraphNodeCamera != NULL && gCurGraphNodeObject != NULL) { - if (gCurGraphNodeHeldObject != NULL) { - get_pos_from_transform_mtx(shadowPos, gMatStack[gMatStackIndex], - *gCurGraphNodeCamera->matrixPtr); - shadowScale = node->shadowScale; - } else { - vec3f_copy(shadowPos, gCurGraphNodeObject->pos); - shadowScale = node->shadowScale * gCurGraphNodeObject->scale[0]; - } - - objScale = 1.0f; - if (gCurAnimEnabled) { - if (gCurAnimType == ANIM_TYPE_TRANSLATION - || gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) { - geo = node->node.children; - if (geo != NULL && geo->type == GRAPH_NODE_TYPE_SCALE) { - objScale = ((struct GraphNodeScale *) geo)->scale; - } - animOffset[0] = - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier * objScale; - animOffset[1] = 0.0f; - gCurrAnimAttribute += 2; - animOffset[2] = - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier * objScale; - gCurrAnimAttribute -= 6; - - // simple matrix rotation so the shadow offset rotates along with the object - sinAng = sins(gCurGraphNodeObject->angle[1]); - cosAng = coss(gCurGraphNodeObject->angle[1]); - - shadowPos[0] += animOffset[0] * cosAng + animOffset[2] * sinAng; - shadowPos[2] += -animOffset[0] * sinAng + animOffset[2] * cosAng; - } - } - - shadowList = create_shadow_below_xyz(shadowPos[0], shadowPos[1], shadowPos[2], shadowScale, - node->shadowSolidity, node->shadowType); - if (shadowList != NULL) { - mtx = alloc_display_list(sizeof(*mtx)); - gMatStackIndex++; - mtxf_translate(mtxf, shadowPos); - mtxf_mul(gMatStack[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtr); - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (gShadowAboveWaterOrLava == TRUE) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 4); - } else if (gMarioOnIceOrCarpet == 1 || gShadowAboveCustomWater == 1) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 5); - } else { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 6); - } - gMatStackIndex--; - } - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } -} - -/** - * Check whether an object is in view to determine whether it should be drawn. - * This is known as frustum culling. - * It checks whether the object is far away, very close / behind the camera, - * or horizontally out of view. It does not check whether it is vertically - * out of view. It assumes a sphere of 300 units around the object's position - * unless the object has a culling radius node that specifies otherwise. - * - * The matrix parameter should be the top of the matrix stack, which is the - * object's transformation matrix times the camera 'look-at' matrix. The math - * is counter-intuitive, but it checks column 3 (translation vector) of this - * matrix to determine where the origin (0,0,0) in object space will be once - * transformed to camera space (x+ = right, y+ = up, z = 'coming out the screen'). - * In 3D graphics, you typically model the world as being moved in front of a - * static camera instead of a moving camera through a static world, which in - * this case simplifies calculations. Note that the perspective matrix is not - * on the matrix stack, so there are still calculations with the fov to compute - * the slope of the lines of the frustum. - * - * z- - * - * \ | / - * \ | / - * \ | / - * \ | / - * \ | / - * \|/ - * C x+ - * - * Since (0,0,0) is unaffected by rotation, columns 0, 1 and 2 are ignored. - */ -static s32 obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { - s16 cullingRadius; - s16 halfFov; // half of the fov in in-game angle units instead of degrees - struct GraphNode *geo; - f32 hScreenEdge; - - if (node->node.flags & GRAPH_RENDER_INVISIBLE) { - return FALSE; - } - - geo = node->sharedChild; - - // ! @bug The aspect ratio is not accounted for. When the fov value is 45, - // the horizontal effective fov is actually 60 degrees, so you can see objects - // visibly pop in or out at the edge of the screen. - halfFov = (gCurGraphNodeCamFrustum->fov / 2.0f + 1.0f) * 32768.0f / 180.0f + 0.5f; - - hScreenEdge = -matrix[3][2] * sins(halfFov) / coss(halfFov); - // -matrix[3][2] is the depth, which gets multiplied by tan(halfFov) to get - // the amount of units between the center of the screen and the horizontal edge - // given the distance from the object to the camera. - -#ifdef WIDESCREEN - // This multiplication should really be performed on 4:3 as well, - // but the issue will be more apparent on widescreen. - hScreenEdge *= GFX_DIMENSIONS_ASPECT_RATIO; -#endif - - if (geo != NULL && geo->type == GRAPH_NODE_TYPE_CULLING_RADIUS) { - cullingRadius = - (f32)((struct GraphNodeCullingRadius *) geo)->cullingRadius; //! Why is there a f32 cast? - } else { - cullingRadius = 300; - } - - // Don't render if the object is close to or behind the camera - if (matrix[3][2] > -100.0f + cullingRadius) { - return FALSE; - } - - //! This makes the HOLP not update when the camera is far away, and it - // makes PU travel safe when the camera is locked on the main map. - // If Mario were rendered with a depth over 65536 it would cause overflow - // when converting the transformation matrix to a fixed point matrix. - if (matrix[3][2] < -20000.0f - cullingRadius) { - return FALSE; - } - - // Check whether the object is horizontally in view - if (matrix[3][0] > hScreenEdge + cullingRadius) { - return FALSE; - } - if (matrix[3][0] < -hScreenEdge - cullingRadius) { - return FALSE; - } - return TRUE; -} - -/** - * Process an object node. - */ -static void geo_process_object(struct Object *node) { - Mat4 mtxf; - s32 hasAnimation = (node->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0; - - if (node->header.gfx.areaIndex == gCurGraphNodeRoot->areaIndex) { - if (node->header.gfx.throwMatrix != NULL) { - mtxf_mul(gMatStack[gMatStackIndex + 1], *node->header.gfx.throwMatrix, - gMatStack[gMatStackIndex]); - } else if (node->header.gfx.node.flags & GRAPH_RENDER_BILLBOARD) { - mtxf_billboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], - node->header.gfx.pos, gCurGraphNodeCamera->roll); - } else { - mtxf_rotate_zxy_and_translate(mtxf, node->header.gfx.pos, node->header.gfx.angle); - mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); - } - - mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1], - node->header.gfx.scale); - node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex]; - node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0]; - node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1]; - node->header.gfx.cameraToObject[2] = gMatStack[gMatStackIndex][3][2]; - - // FIXME: correct types - if (node->header.gfx.animInfo.curAnim != NULL) { - geo_set_animation_globals(&node->header.gfx.animInfo, hasAnimation); - } - if (obj_is_in_view(&node->header.gfx, gMatStack[gMatStackIndex])) { - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - if (node->header.gfx.sharedChild != NULL) { - gCurGraphNodeObject = (struct GraphNodeObject *) node; - node->header.gfx.sharedChild->parent = &node->header.gfx.node; - geo_process_node_and_siblings(node->header.gfx.sharedChild); - node->header.gfx.sharedChild->parent = NULL; - gCurGraphNodeObject = NULL; - } - if (node->header.gfx.node.children != NULL) { - geo_process_node_and_siblings(node->header.gfx.node.children); - } - } - - gMatStackIndex--; - gCurAnimType = ANIM_TYPE_NONE; - node->header.gfx.throwMatrix = NULL; - } -} - -/** - * Process an object parent node. Temporarily assigns itself as the parent of - * the subtree rooted at 'sharedChild' and processes the subtree, after which the - * actual children are be processed. (in practice they are null though) - */ -static void geo_process_object_parent(struct GraphNodeObjectParent *node) { - if (node->sharedChild != NULL) { - node->sharedChild->parent = (struct GraphNode *) node; - geo_process_node_and_siblings(node->sharedChild); - node->sharedChild->parent = NULL; - } - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } -} - -/** - * Process a held object node. - */ -void geo_process_held_object(struct GraphNodeHeldObject *node) { - Mat4 mat; - Vec3f translation; - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - -#ifdef F3DEX_GBI_2 - gSPLookAt(gDisplayListHead++, &lookAt); -#endif - - if (node->fnNode.func != NULL) { - node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]); - } - if (node->objNode != NULL && node->objNode->header.gfx.sharedChild != NULL) { - s32 hasAnimation = (node->objNode->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0; - - translation[0] = node->translation[0] / 4.0f; - translation[1] = node->translation[1] / 4.0f; - translation[2] = node->translation[2] / 4.0f; - - mtxf_translate(mat, translation); - mtxf_copy(gMatStack[gMatStackIndex + 1], *gCurGraphNodeObject->throwMatrix); - gMatStack[gMatStackIndex + 1][3][0] = gMatStack[gMatStackIndex][3][0]; - gMatStack[gMatStackIndex + 1][3][1] = gMatStack[gMatStackIndex][3][1]; - gMatStack[gMatStackIndex + 1][3][2] = gMatStack[gMatStackIndex][3][2]; - mtxf_mul(gMatStack[gMatStackIndex + 1], mat, gMatStack[gMatStackIndex + 1]); - mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1], - node->objNode->header.gfx.scale); - if (node->fnNode.func != NULL) { - node->fnNode.func(GEO_CONTEXT_HELD_OBJ, &node->fnNode.node, - (struct AllocOnlyPool *) gMatStack[gMatStackIndex + 1]); - } - gMatStackIndex++; - mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = mtx; - gGeoTempState.type = gCurAnimType; - gGeoTempState.enabled = gCurAnimEnabled; - gGeoTempState.frame = gCurrAnimFrame; - gGeoTempState.translationMultiplier = gCurAnimTranslationMultiplier; - gGeoTempState.attribute = gCurrAnimAttribute; - gGeoTempState.data = gCurAnimData; - gCurAnimType = 0; - gCurGraphNodeHeldObject = (void *) node; - if (node->objNode->header.gfx.animInfo.curAnim != NULL) { - geo_set_animation_globals(&node->objNode->header.gfx.animInfo, hasAnimation); - } - - geo_process_node_and_siblings(node->objNode->header.gfx.sharedChild); - gCurGraphNodeHeldObject = NULL; - gCurAnimType = gGeoTempState.type; - gCurAnimEnabled = gGeoTempState.enabled; - gCurrAnimFrame = gGeoTempState.frame; - gCurAnimTranslationMultiplier = gGeoTempState.translationMultiplier; - gCurrAnimAttribute = gGeoTempState.attribute; - gCurAnimData = gGeoTempState.data; - gMatStackIndex--; - } - - if (node->fnNode.node.children != NULL) { - geo_process_node_and_siblings(node->fnNode.node.children); - } -} - -/** - * Processes the children of the given GraphNode if it has any - */ -void geo_try_process_children(struct GraphNode *node) { - if (node->children != NULL) { - geo_process_node_and_siblings(node->children); - } -} - -/** - * Process a generic geo node and its siblings. - * The first argument is the start node, and all its siblings will - * be iterated over. - */ -void geo_process_node_and_siblings(struct GraphNode *firstNode) { - s16 iterateChildren = TRUE; - struct GraphNode *curGraphNode = firstNode; - struct GraphNode *parent = curGraphNode->parent; - - // In the case of a switch node, exactly one of the children of the node is - // processed instead of all children like usual - if (parent != NULL) { - iterateChildren = (parent->type != GRAPH_NODE_TYPE_SWITCH_CASE); - } - - do { - if (curGraphNode->flags & GRAPH_RENDER_ACTIVE) { - if (curGraphNode->flags & GRAPH_RENDER_CHILDREN_FIRST) { - geo_try_process_children(curGraphNode); - } else { - switch (curGraphNode->type) { - case GRAPH_NODE_TYPE_ORTHO_PROJECTION: - geo_process_ortho_projection((struct GraphNodeOrthoProjection *) curGraphNode); - break; - case GRAPH_NODE_TYPE_PERSPECTIVE: - geo_process_perspective((struct GraphNodePerspective *) curGraphNode); - break; - case GRAPH_NODE_TYPE_MASTER_LIST: - geo_process_master_list((struct GraphNodeMasterList *) curGraphNode); - break; - case GRAPH_NODE_TYPE_LEVEL_OF_DETAIL: - geo_process_level_of_detail((struct GraphNodeLevelOfDetail *) curGraphNode); - break; - case GRAPH_NODE_TYPE_SWITCH_CASE: - geo_process_switch((struct GraphNodeSwitchCase *) curGraphNode); - break; - case GRAPH_NODE_TYPE_CAMERA: - geo_process_camera((struct GraphNodeCamera *) curGraphNode); - break; - case GRAPH_NODE_TYPE_TRANSLATION_ROTATION: - geo_process_translation_rotation( - (struct GraphNodeTranslationRotation *) curGraphNode); - break; - case GRAPH_NODE_TYPE_TRANSLATION: - geo_process_translation((struct GraphNodeTranslation *) curGraphNode); - break; - case GRAPH_NODE_TYPE_ROTATION: - geo_process_rotation((struct GraphNodeRotation *) curGraphNode); - break; - case GRAPH_NODE_TYPE_OBJECT: - geo_process_object((struct Object *) curGraphNode); - break; - case GRAPH_NODE_TYPE_ANIMATED_PART: - geo_process_animated_part((struct GraphNodeAnimatedPart *) curGraphNode); - break; - case GRAPH_NODE_TYPE_BILLBOARD: - geo_process_billboard((struct GraphNodeBillboard *) curGraphNode); - break; - case GRAPH_NODE_TYPE_DISPLAY_LIST: - geo_process_display_list((struct GraphNodeDisplayList *) curGraphNode); - break; - case GRAPH_NODE_TYPE_SCALE: - geo_process_scale((struct GraphNodeScale *) curGraphNode); - break; - case GRAPH_NODE_TYPE_SHADOW: - geo_process_shadow((struct GraphNodeShadow *) curGraphNode); - break; - case GRAPH_NODE_TYPE_OBJECT_PARENT: - geo_process_object_parent((struct GraphNodeObjectParent *) curGraphNode); - break; - case GRAPH_NODE_TYPE_GENERATED_LIST: - geo_process_generated_list((struct GraphNodeGenerated *) curGraphNode); - break; - case GRAPH_NODE_TYPE_BACKGROUND: - geo_process_background((struct GraphNodeBackground *) curGraphNode); - break; - case GRAPH_NODE_TYPE_HELD_OBJ: - geo_process_held_object((struct GraphNodeHeldObject *) curGraphNode); - break; - default: - geo_try_process_children((struct GraphNode *) curGraphNode); - break; - } - } - } else { - if (curGraphNode->type == GRAPH_NODE_TYPE_OBJECT) { - ((struct GraphNodeObject *) curGraphNode)->throwMatrix = NULL; - } - } - } while (iterateChildren && (curGraphNode = curGraphNode->next) != firstNode); -} - -/** - * Process a root node. This is the entry point for processing the scene graph. - * The root node itself sets up the viewport, then all its children are processed - * to set up the projection and draw display lists. - */ -void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) { - UNUSED s32 unused; - - if (node->node.flags & GRAPH_RENDER_ACTIVE) { - Mtx *initialMatrix; - Vp *viewport = alloc_display_list(sizeof(*viewport)); - - gDisplayListHeap = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), - MEMORY_POOL_LEFT); - initialMatrix = alloc_display_list(sizeof(*initialMatrix)); - gMatStackIndex = 0; - gCurAnimType = 0; - vec3s_set(viewport->vp.vtrans, node->x * 4, node->y * 4, 511); - vec3s_set(viewport->vp.vscale, node->width * 4, node->height * 4, 511); - if (b != NULL) { - clear_frame_buffer(clearColor); - make_viewport_clip_rect(b); - *viewport = *b; - } - - else if (c != NULL) { - clear_frame_buffer(clearColor); - make_viewport_clip_rect(c); - } - - mtxf_identity(gMatStack[gMatStackIndex]); - mtxf_to_mtx(initialMatrix, gMatStack[gMatStackIndex]); - gMatStackFixed[gMatStackIndex] = initialMatrix; - gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewport)); - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gMatStackFixed[gMatStackIndex]), - G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - gCurGraphNodeRoot = node; - if (node->node.children != NULL) { - geo_process_node_and_siblings(node->node.children); - } - gCurGraphNodeRoot = NULL; - if (gShowDebugText) { - print_text_fmt_int(180, 36, "MEM %d", - gDisplayListHeap->totalSpace - gDisplayListHeap->usedSpace); - } - main_pool_free(gDisplayListHeap); - } -}