From 44db9bab773cc3b14c8f944a9411673b6fe08b01 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sat, 7 Jun 2025 21:38:12 -0600 Subject: Add Interpolation (#204) * initial work * more work * progress * Fixed slow fps * Add Lywx changes * Interp Works * Test default tick/logic update * Added missing include (#202) * Added missing include * More missing includes --------- Co-authored-by: MegaMech * test * Revert "test" This reverts commit 1a810d74cc8531ce486bcb1c399cc6798fa1b51d. * Interp Item box * Actually interpolate item box * fix clouds * interp player? * Test 2 * Fix mistake * tag and fix item boxes * tag fake item box and whatever func_800696CC is * these aren't needed * tag karts * Slightly better falling rocks(still needs work) * Tag Smoke and Dust * Removed unneeded code from falling_rock * tag whatever func_80051ABC is * add missing rotate x coord * GrandPrixBallon/kart shadow * Green shells tag, and added comments I neglected to add before. * doesn't compile on win * Fixes * Disabled camera interpolation * Balloons fixes * progress * set_transform_matrix compiles * Compile setTransformMatrix * More transforms interp * Add more interps * matrix * Matrix multi interp * Fix interpolation camera bug * Missing includes needed for Linux. * Excluded access to HM64 Labs on Switch. * interpolation tags for various objects * Bowser castle statue flame interpolated. * tag hedgehogs * cloud interpolation * Interpolated smoke particles from shells * cloud interpolation refactor * Interpolated snowflakes * Interpolated penguins, also added comment tags to places I missed. * tag Snowman interpolation * Interpolated player reflection(sherbet land) * Forgot to uncomment stuff while testing * better tag * tag leaves * Set the default FPS to 30 * tag hud * Fixed "Match Refresh Rate" option * adjust draw distance * remove innecessary rock tag * rag rocks * better tag * Tagged player rank placement in HUD * Tagged Bat, Boos, and TrashBin(Banshee Boardwalk objects) * Refactor render_screens and fix editor raycast * better object interpolation * shift is not needed here * fix tag * fix tags * mole comments * comment * Changed how shell flames are interpolated. * interpolated ended scene fireworks. * Tagged star particles in the ending scene * Shell flames handled better. * this isn't needed * Fix multiplayer cameras * Fixed loading battle maps. * Tagged battle balloons * Some fixes for battle mode * No longer needed changes toAFinishline with the changes mega made. * Tag finishline * fix to make it compile with cmake 3.31 * changed mtxf_multiplication() to fix vert explosion in Desert & DK parkway.(provided by Coco.) * fix memory leaks, avoid invalidate texture (#207) * Fixed macos * More stupid fixes * update with main and update torch and lus and enable action on this branch * Update FrameInterpolation.h * Update FrameInterpolation.cpp * fix some memory leak * Update torch * Update torch * update torch and lus * reduce texture import * don't use fork of torch and lus * Update torch * Update torch --------- Co-authored-by: Lywx * Refactor World::Courses to unique_ptr (#211) * wip course unique ptr * Track unique_ptr : This probably compiles * Finish impl Courses as unique_ptr * Fix error * Fixes * More fixes * Cleanup * Remove old vars --------- Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com> * particle boat and train * fix player particle interpolation * add modify interpolation target fps in menu * fix windows * Update libultraship * Fix logo interp * Interp SetTextMatrix * Fix freecam camera * Clarify comment * Clarify func * fix linux compilation * Update Thwomp.cpp * Update Thwomp.h * Update render.inc.c * Update render.inc.c * Update gbiMacro.c * interp falling rock shadow * Revert change that has no explanation * Update code_80057C60.c * Update code_80057C60.c * Update GrandPrixBalloons.cpp * Update Lakitu.cpp * Update framebuffer_effects.c * Update render_courses.c --------- Co-authored-by: Sonic Dreamcaster Co-authored-by: KiritoDv Co-authored-by: sitton76 <58642183+sitton76@users.noreply.github.com> Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com> Co-authored-by: coco875 <59367621+coco875@users.noreply.github.com> Co-authored-by: coco875 --- .github/workflows/main.yml | 2 +- libultraship | 2 +- src/actors/cow/render.inc.c | 6 + src/actors/fake_item_box/render.inc.c | 16 + src/actors/falling_rock/render.inc.c | 24 +- src/actors/item_box/render.inc.c | 36 +- src/actors/mario_sign/render.inc.c | 13 +- src/actors/piranha_plant/render.inc.c | 2 +- src/actors/trees/render.inc.c | 2 +- src/actors/yoshi_egg/render.inc.c | 8 + src/animation.c | 7 +- src/audio/external.c | 22 +- src/camera.c | 151 ++++- src/camera.h | 2 + src/code_800029B0.c | 8 +- src/code_80005FD0.c | 93 ++- src/code_80057C60.c | 185 +++--- src/code_8006E9C0.c | 8 +- src/code_8006E9C0.h | 2 +- src/code_80086E70.c | 4 +- src/code_800AF9B0.c | 8 +- src/effects.c | 16 +- src/ending/code_80281780.c | 2 +- src/ending/podium_ceremony_actors.c | 6 + src/engine/Matrix.cpp | 50 +- src/engine/Smoke.cpp | 17 +- src/engine/World.cpp | 19 +- src/engine/World.h | 18 +- src/engine/actors/Finishline.cpp | 8 + src/engine/actors/Finishline.h | 1 + src/engine/editor/Editor.cpp | 19 +- src/engine/editor/Editor.h | 1 + src/engine/editor/EditorMath.cpp | 8 +- src/engine/objects/Bat.cpp | 48 +- src/engine/objects/BombKart.cpp | 8 +- src/engine/objects/Boos.cpp | 8 + src/engine/objects/GrandPrixBalloons.cpp | 36 +- src/engine/objects/Hedgehog.cpp | 22 +- src/engine/objects/HotAirBalloon.cpp | 2 +- src/engine/objects/Lakitu.cpp | 10 +- src/engine/objects/Mole.cpp | 107 +-- src/engine/objects/Snowman.cpp | 59 +- src/engine/objects/Thwomp.cpp | 54 +- src/engine/objects/Thwomp.h | 1 + src/engine/objects/TrashBin.cpp | 10 +- src/engine/particles/StarEmitter.cpp | 5 + src/enhancements/collision_viewer.c | 2 + src/enhancements/freecam/freecam.cpp | 41 +- src/enhancements/freecam/freecam.h | 2 +- src/enhancements/freecam/freecam_engine.c | 4 +- src/gbiMacro.c | 1 + src/main.c | 32 +- src/math_util_2.c | 99 ++- src/math_util_2.h | 10 +- src/menu_items.c | 33 +- src/menus.c | 1 + src/os/guLookAtF.c | 2 + src/os/guOrthoF.c | 8 +- src/os/guPerspectiveF.c | 2 + src/os/guRotateF.c | 2 + src/os/guScaleF.c | 2 + src/os/guTranslateF.c | 2 + src/player_controller.c | 20 +- src/port/Engine.cpp | 143 +++- src/port/Engine.h | 4 +- src/port/Game.cpp | 279 ++++---- src/port/Game.h | 86 +-- src/port/interpolation/FrameInterpolation.cpp | 806 +++++++++++++++++++++++ src/port/interpolation/FrameInterpolation.h | 85 +++ src/port/interpolation/matrix.c | 451 +++++++++++++ src/port/interpolation/matrix.h | 94 +++ src/port/resource/importers/AudioBankFactory.cpp | 1 + src/port/resource/type/AudioBank.cpp | 17 + src/port/resource/type/AudioBank.h | 1 + src/port/resource/type/AudioSample.cpp | 14 + src/port/resource/type/AudioSample.h | 1 + src/port/ui/ContentBrowser.cpp | 25 +- src/port/ui/PortMenu.cpp | 149 +++-- src/racing/actors.c | 55 +- src/racing/framebuffer_effects.c | 1 + src/racing/math_util.c | 130 ++-- src/racing/math_util.h | 11 +- src/racing/race_logic.c | 10 +- src/racing/render_courses.c | 12 +- src/racing/skybox_and_splitscreen.c | 90 ++- src/render_objects.c | 217 ++++-- src/render_player.c | 91 ++- src/render_player.h | 7 +- src/spawn_players.c | 26 +- src/staff_ghosts.c | 6 +- src/update_objects.c | 51 +- torch | 2 +- 92 files changed, 3239 insertions(+), 1025 deletions(-) create mode 100644 src/port/interpolation/FrameInterpolation.cpp create mode 100644 src/port/interpolation/FrameInterpolation.h create mode 100644 src/port/interpolation/matrix.c create mode 100644 src/port/interpolation/matrix.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 496346cb8..6bf2a4a5b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: GenerateBuilds on: push: - branches: ["main"] + branches: ["*"] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/libultraship b/libultraship index 6a3f6cd32..47b4d7f6a 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 6a3f6cd327b99f617b623e5b9a3afeae460aac2b +Subproject commit 47b4d7f6ae47e4ac900d080f485d1a6145985144 diff --git a/src/actors/cow/render.inc.c b/src/actors/cow/render.inc.c index e55154c03..af15363c4 100644 --- a/src/actors/cow/render.inc.c +++ b/src/actors/cow/render.inc.c @@ -19,6 +19,9 @@ void render_actor_cow(Camera* camera, Mat4 arg1, struct Actor* arg2) { return; } + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("render_actor_cow", TAG_OBJECT(arg2)); + arg1[3][0] = arg2->pos[0]; arg1[3][1] = arg2->pos[1]; arg1[3][2] = arg2->pos[2]; @@ -42,4 +45,7 @@ void render_actor_cow(Camera* camera, Mat4 arg1, struct Actor* arg2) { break; } } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } diff --git a/src/actors/fake_item_box/render.inc.c b/src/actors/fake_item_box/render.inc.c index 7d0dab71e..34cbfd105 100644 --- a/src/actors/fake_item_box/render.inc.c +++ b/src/actors/fake_item_box/render.inc.c @@ -2,6 +2,7 @@ #include #include #include +#include "port/interpolation/FrameInterpolation.h" /** * @brief Renders the fake item box actor. @@ -24,6 +25,9 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox) f32 temp_f2_2; f32 someMultiplier; + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Fake Item Box", TAG_ITEM_ADDR(fakeItemBox)); + if (is_within_render_distance(camera->pos, fakeItemBox->pos, camera->rot[1], 2500.0f, gCameraZoom[camera - camera1], 1000000.0f) < 0 && CVarGetInteger("gNoCulling", 0) == 0) { @@ -61,6 +65,13 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox) gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIA, G_CC_MODULATEIA); + + /* + * In the original game, the question mark texture would become corrupted. Thus, this code + * makes it disappear to hide the issue. Since the texture no longer becomes corrupted, this + * fix can be removed. + */ +#ifdef TARGET_N64 if ((fakeItemBox->rot[1] < 0xAA1) && (fakeItemBox->rot[1] > 0)) { gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); } else if ((fakeItemBox->rot[1] >= 0x6AA5) && (fakeItemBox->rot[1] < 0x754E)) { @@ -70,9 +81,12 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox) } else if ((fakeItemBox->rot[1] >= 0xC711) && (fakeItemBox->rot[1] < 0xD1BA)) { gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); } else { +#endif gDPSetBlendMask(gDisplayListHead++, 0xFF); gDPSetRenderMode(gDisplayListHead++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2); +#ifdef TARGET_N64 } +#endif gSPDisplayList(gDisplayListHead++, D_0D003090); } else { gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); @@ -163,4 +177,6 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox) gSPDisplayList(gDisplayListHead++, D_0D0030F8); gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK); } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } diff --git a/src/actors/falling_rock/render.inc.c b/src/actors/falling_rock/render.inc.c index 20c6a49b3..a2d132b01 100644 --- a/src/actors/falling_rock/render.inc.c +++ b/src/actors/falling_rock/render.inc.c @@ -1,6 +1,7 @@ #include #include #include +#include "port/interpolation/FrameInterpolation.h" /** * @brief Renders the falling rock actor. @@ -12,7 +13,7 @@ void render_actor_falling_rock(Camera* camera, struct FallingRock* rock) { Vec3s sp98; Vec3f sp8C; - Mat4 sp4C; + Mat4 mtx; f32 height; UNUSED s32 pad[4]; @@ -41,16 +42,29 @@ void render_actor_falling_rock(Camera* camera, struct FallingRock* rock) { sp98[1] = 0; sp98[2] = 0; sp8C[1] = height + 2.0f; - mtxf_pos_rotation_xyz(sp4C, sp8C, sp98); - if (render_set_position(sp4C, 0) == 0) { + + FrameInterpolation_RecordOpenChild("rock_shadow", (uintptr_t) rock); + mtxf_pos_rotation_xyz(mtx, sp8C, sp98); + if (render_set_position(mtx, 0) == 0) { + FrameInterpolation_RecordCloseChild(); return; } gSPDisplayList(gDisplayListHead++, d_course_choco_mountain_dl_6F88); + FrameInterpolation_RecordCloseChild(); } } - mtxf_pos_rotation_xyz(sp4C, rock->pos, rock->rot); - if (render_set_position(sp4C, 0) == 0) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("rock", (uintptr_t) rock); + + mtxf_pos_rotation_xyz(mtx, rock->pos, rock->rot); + if (render_set_position(mtx, 0) == 0) { + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); return; } gSPDisplayList(gDisplayListHead++, d_course_choco_mountain_dl_falling_rock); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } diff --git a/src/actors/item_box/render.inc.c b/src/actors/item_box/render.inc.c index d4a96a0e3..fabf16861 100644 --- a/src/actors/item_box/render.inc.c +++ b/src/actors/item_box/render.inc.c @@ -1,6 +1,7 @@ #include #include #include +#include "port/interpolation/FrameInterpolation.h" /** * @brief Renders the item box actor. @@ -26,6 +27,9 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { f32 temp_f2_2; f32 someMultiplier; + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("ItemBox", TAG_ITEM_ADDR(item_box)); + temp_f0 = is_within_render_distance(camera->pos, item_box->pos, camera->rot[1], 0.0f, gCameraZoom[camera - camera1], 4000000.0f); if (CVarGetInteger("gNoCulling", 0) == 1) { @@ -39,6 +43,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { someVec2[0] = item_box->pos[0]; someVec2[1] = item_box->resetDistance + 2.0f; someVec2[2] = item_box->pos[2]; + mtxf_pos_rotation_xyz(someMatrix1, someVec2, someRot); if (!render_set_position(someMatrix1, 0)) { @@ -46,8 +51,10 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D002EE8); + someRot[1] = item_box->rot[1] * 2; someVec2[1] = item_box->pos[1]; + mtxf_pos_rotation_xyz(someMatrix1, someVec2, someRot); if (!render_set_position(someMatrix1, 0)) { @@ -66,6 +73,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { gSPDisplayList(gDisplayListHead++, itemBoxQuestionMarkModel); } if (item_box->state != 3) { + mtxf_pos_rotation_xyz(someMatrix1, item_box->pos, item_box->rot); if (!render_set_position(someMatrix1, 0)) { @@ -74,6 +82,13 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIA, G_CC_MODULATEIA); + + /* + * In the original game, the question mark texture would become corrupted. Thus, this code + * makes it disappear to hide the issue. Since the texture no longer becomes corrupted, this + * fix can be removed. + */ +#ifdef TARGET_N64 if ((item_box->rot[1] < 0xAA1) && (item_box->rot[1] > 0)) { gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); } else if ((item_box->rot[1] >= 0x6AA5) && (item_box->rot[1] < 0x754E)) { @@ -83,16 +98,21 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } else if ((item_box->rot[1] >= 0xC711) && (item_box->rot[1] < 0xD1BA)) { gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); } else { - gDPSetBlendMask(gDisplayListHead++, 0xFF); - gDPSetRenderMode(gDisplayListHead++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2); +#endif + gDPSetBlendMask(gDisplayListHead++, 0xFF); + gDPSetRenderMode(gDisplayListHead++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2); +#ifdef TARGET_N64 } +#endif gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPDisplayList(gDisplayListHead++, D_0D003090); + } else { gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK); gDPSetBlendMask(gDisplayListHead++, 0xFF); thing = item_box->someTimer; + mtxf_pos_rotation_xyz(someMatrix1, item_box->pos, item_box->rot); if (thing < 10.0f) { someMultiplier = 1.0f; @@ -116,6 +136,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D003158); + temp_f2_2 = 0.8f * thing; temp_f12 = 0.5f * thing; someVec1[0] = temp_f2_2; @@ -128,10 +149,12 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D0031B8); + temp_f0_2 = -0.5f * thing; someVec1[0] = temp_f2_2; someVec1[1] = 1.2f * thing; someVec1[2] = temp_f0_2; + add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1); if (!render_set_position(someMatrix2, 0)) { @@ -139,6 +162,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D003128); + if (!(item_box->someTimer & 1)) { gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); } else { @@ -147,6 +171,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { someVec1[0] = 0.0f; someVec1[1] = 1.8f * thing; someVec1[2] = -1.0f * thing; + add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1); if (!render_set_position(someMatrix2, 0)) { @@ -154,10 +179,12 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D0031E8); + temp_f0_3 = -0.8f * thing; someVec1[0] = temp_f0_3; someVec1[1] = 0.6f * thing; someVec1[2] = temp_f0_2; + add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1); if (!render_set_position(someMatrix2, 0)) { @@ -165,9 +192,11 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D003188); + someVec1[0] = temp_f0_3; someVec1[1] = temp_f2; someVec1[2] = temp_f12; + add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1); if (!render_set_position(someMatrix2, 0)) { @@ -175,8 +204,11 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) { } gSPDisplayList(gDisplayListHead++, D_0D0030F8); + gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK); } gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } diff --git a/src/actors/mario_sign/render.inc.c b/src/actors/mario_sign/render.inc.c index 1c72c8394..0bf10bf88 100644 --- a/src/actors/mario_sign/render.inc.c +++ b/src/actors/mario_sign/render.inc.c @@ -1,6 +1,7 @@ #include #include #include +#include "port/interpolation/FrameInterpolation.h" /** * @brief Renders the Mario sign actor. @@ -11,10 +12,9 @@ * @param arg2 */ void render_actor_mario_sign(Camera* arg0, UNUSED Mat4 arg1, struct Actor* arg2) { - Mat4 sp40; + Mat4 mtx; f32 unk; s16 temp = arg2->flags; - if (temp & 0x800) { return; } @@ -24,11 +24,16 @@ void render_actor_mario_sign(Camera* arg0, UNUSED Mat4 arg1, struct Actor* arg2) unk = MAX(unk, 0.0f); } if (!(unk < 0.0f)) { + + FrameInterpolation_RecordMatrixPush(mtx); + gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); - mtxf_pos_rotation_xyz(sp40, arg2->pos, arg2->rot); - if (render_set_position(sp40, 0) != 0) { + mtxf_pos_rotation_xyz(mtx, arg2->pos, arg2->rot); + if (render_set_position(mtx, 0) != 0) { gSPDisplayList(gDisplayListHead++, d_course_mario_raceway_dl_sign); } + FrameInterpolation_RecordMatrixPop(mtx); + } } diff --git a/src/actors/piranha_plant/render.inc.c b/src/actors/piranha_plant/render.inc.c index 23d018d1b..ed2281095 100644 --- a/src/actors/piranha_plant/render.inc.c +++ b/src/actors/piranha_plant/render.inc.c @@ -120,7 +120,7 @@ void render_actor_piranha_plant(Camera* arg0, Mat4 arg1, struct PiranhaPlant* ar G_TX_MIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - if (GetCourse() == GetMarioRaceway()) { + if (IsMarioRaceway()) { gSPDisplayList(gDisplayListHead++, &d_course_mario_raceway_dl_piranha_plant); } else { gSPDisplayList(gDisplayListHead++, &d_course_royal_raceway_dl_piranha_plant); diff --git a/src/actors/trees/render.inc.c b/src/actors/trees/render.inc.c index cb54275c6..9939d14ef 100644 --- a/src/actors/trees/render.inc.c +++ b/src/actors/trees/render.inc.c @@ -202,7 +202,7 @@ void func_80299864(Camera* camera, Mat4 arg1, struct Actor* arg2) { // Unless both courses use this actor and use the same addr for the texture. // Just in-case changed the code into a switch to prevent future crashes. // This comment can be removed when this is confirmed to work. - if (GetCourse() == GetLuigiRaceway()) { + if (IsLuigiRaceway()) { gSPDisplayList(gDisplayListHead++, d_course_luigi_raceway_dl_FC70); } } diff --git a/src/actors/yoshi_egg/render.inc.c b/src/actors/yoshi_egg/render.inc.c index e38625df0..f39524aa3 100644 --- a/src/actors/yoshi_egg/render.inc.c +++ b/src/actors/yoshi_egg/render.inc.c @@ -2,6 +2,7 @@ #include #include #include +#include "port/interpolation/FrameInterpolation.h" /** * @brief Renders the Yoshi egg actor. @@ -51,6 +52,9 @@ void render_actor_yoshi_egg(Camera* arg0, Mat4 arg1, struct YoshiValleyEgg* egg, sp5C[0] = 0; sp5C[1] = egg->eggRot; sp5C[2] = 0; + + FrameInterpolation_RecordMatrixPush(sp60); + mtxf_pos_rotation_xyz(sp60, egg->pos, sp5C); if (render_set_position(sp60, 0) == 0) { return; @@ -58,14 +62,18 @@ void render_actor_yoshi_egg(Camera* arg0, Mat4 arg1, struct YoshiValleyEgg* egg, gSPSetGeometryMode(gDisplayListHead++, G_LIGHTING); gSPDisplayList(gDisplayListHead++, d_course_yoshi_valley_dl_16D70); + FrameInterpolation_RecordMatrixPop(sp60); } else { arg1[3][0] = egg->pos[0]; arg1[3][1] = egg->pos[1]; arg1[3][2] = egg->pos[2]; + FrameInterpolation_RecordMatrixPush(arg1); + if (render_set_position(arg1, 0) != 0) { gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING); gSPDisplayList(gDisplayListHead++, d_course_yoshi_valley_dl_egg_lod0); } + FrameInterpolation_RecordMatrixPop(arg1); } } diff --git a/src/animation.c b/src/animation.c index d81123ae9..ed290ef7a 100644 --- a/src/animation.c +++ b/src/animation.c @@ -8,6 +8,7 @@ #include #include "code_80057C60.h" #include "engine/Matrix.h" +#include "port/interpolation/FrameInterpolation.h" Vec3s sOriginalPosAnimation; s16 isNotTheFirst; @@ -35,6 +36,9 @@ void convert_to_fixed_point_matrix_animation(Mtx* dest, Mat4 src) { } void mtxf_translate_rotate2(Mat4 dest, Vec3f pos, Vec3s angle) { + + FrameInterpolation_RecordMatrixPosRotXYZ(&dest, pos, angle); + f32 sx = sins(angle[0]); f32 cx = coss(angle[0]); @@ -92,7 +96,7 @@ void render_limb_or_add_mtx(Armature* arg0, s16* arg1, AnimationLimbVector arg2, } angle[i] = arg1[arg2[i].indexCycle + some_offset]; } - + FrameInterpolation_RecordMatrixPush(modelMatrix); mtxf_translate_rotate2(modelMatrix, pos, angle); //convert_to_fixed_point_matrix_animation(&gGfxPool->mtxHud[gMatrixHudCount], modelMatrix); sMatrixStackSize += 1; @@ -104,6 +108,7 @@ void render_limb_or_add_mtx(Armature* arg0, s16* arg1, AnimationLimbVector arg2, model = (virtualModel); gSPDisplayList(gDisplayListHead++, model); } + FrameInterpolation_RecordMatrixPop(modelMatrix); } void render_armature(Armature* animation, Animation* arg1, s16 timeCycle) { diff --git a/src/audio/external.c b/src/audio/external.c index 97a2ce7f3..3ed17f5db 100644 --- a/src/audio/external.c +++ b/src/audio/external.c @@ -2647,11 +2647,11 @@ void func_800C847C(u8 playerId) { func_800C97C4(playerId); D_800E9F74[playerId] = 1; func_800C94A4(playerId); - if (((GetCourse() == GetChocoMountain()) || (GetCourse() == GetBowsersCastle()) || - (GetCourse() == GetBansheeBoardwalk()) || (GetCourse() == GetYoshiValley()) || - (GetCourse() == GetFrappeSnowland()) || (GetCourse() == GetKoopaTroopaBeach()) || - (GetCourse() == GetRoyalRaceway()) || (GetCourse() == GetSherbetLand()) || - (GetCourse() == GetDkJungle()) || (GetCourse() == GetBigDonut())) && + if (((IsChocoMountain()) || (IsBowsersCastle()) || + (IsBansheeBoardwalk()) || (IsYoshiValley()) || + (IsFrappeSnowland()) || (IsKoopaTroopaBeach()) || + (IsRoyalRaceway()) || (IsSherbetLand()) || + (IsDkJungle()) || (IsBigDonut())) && (D_800EA0EC[playerId] == 0)) { play_sound((gPlayers[playerId].characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x05), &D_800E9F7C[playerId].pos, playerId, &D_800EA1D4, &D_800EA1D4, @@ -2664,7 +2664,7 @@ void func_800C847C(u8 playerId) { D_800E9F74[playerId] = 2; func_800C94A4(playerId); D_800E9F74[playerId] = 0; - if ((GetCourse() == GetKoopaTroopaBeach()) && (D_800EA0EC[playerId] == 0)) { + if ((IsKoopaTroopaBeach()) && (D_800EA0EC[playerId] == 0)) { play_sound((gPlayers[playerId].characterId * 0x10) + SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x08), &D_800E9F7C[playerId].pos, playerId, &D_800EA1D4, &D_800EA1D4, (u8*) &D_800E9F7C[playerId].unk_14); @@ -2746,7 +2746,7 @@ void func_800C89E4(void) { } void func_800C8AE4(void) { - if (GetCourse() == GetLuigiRaceway()) { + if (IsLuigiRaceway()) { if (D_800EA184 != 0) { if ((u8) D_800EA16C == 0) { // Has to be this way, can't be D_800EA184++ @@ -2824,11 +2824,11 @@ void func_800C8CCC() { } void play_sound2(s32 soundBits) { - if ((soundBits == SOUND_ACTION_REV_ENGINE) && (GetCourse() == GetDkJungle())) { + if ((soundBits == SOUND_ACTION_REV_ENGINE) && (IsDkJungle())) { soundBits = SOUND_ARG_LOAD(0x49, 0x00, 0x80, 0x27); } - if ((soundBits == SOUND_ACTION_REV_ENGINE_2) && (GetCourse() == GetDkJungle())) { + if ((soundBits == SOUND_ACTION_REV_ENGINE_2) && (IsDkJungle())) { soundBits = SOUND_ARG_LOAD(0x49, 0x00, 0x80, 0x28); } play_sound(soundBits, &D_800EA1C8, 4, &D_800EA1D4, &D_800EA1D4, &D_800EA1DC); @@ -3467,7 +3467,9 @@ void func_800CAEC4(u8 playerId, f32 arg1) { arg1 = 0.0f; } D_800EA120[playerId] = arg1; - play_sound(gCurrentCourseId + 0x19007020, &D_800E9F7C[playerId].pos, playerId, &D_800EA1D4, + //! @warning this used to be gCurrentCourseId + 0x19007020 + // This may not be equivallent. + play_sound(GetCourseIndex() + 0x19007020, &D_800E9F7C[playerId].pos, playerId, &D_800EA1D4, &D_800EA120[playerId], (u8*) &D_800E9F7C[playerId].unk_14); break; default: diff --git a/src/camera.c b/src/camera.c index 953f1f96b..434ad25c2 100644 --- a/src/camera.c +++ b/src/camera.c @@ -18,17 +18,19 @@ #include "spawn_players.h" #include "enhancements/freecam/freecam_engine.h" #include "enhancements/freecam/freecam.h" +#include "port/interpolation/FrameInterpolation.h" #include "engine/GameAPI.h" #include "port/Game.h" f32 D_800DDB30[] = { 0.4f, 0.6f, 0.275f, 0.3f }; -Camera cameras[4]; +Camera cameras[5]; Camera* camera1 = &cameras[0]; Camera* camera2 = &cameras[1]; Camera* camera3 = &cameras[2]; Camera* camera4 = &cameras[3]; +Camera* gFreecamCamera = &cameras[4]; UNUSED s32 D_801649D0[2]; @@ -193,6 +195,146 @@ void camera_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cam func_802B7F7C(camera->pos, camera->lookAt, camera->rot); } +// Many arrays are hard-coded to 4. Skip those. +void freecam_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cameraId) { + Player* player = gPlayerOne; + Camera* camera = &cameras[cameraId]; + + camera->cameraId = cameraId; + + //D_80152300[cameraId] = arg4; + switch (arg4) { + case 0: + case 1: + case 3: + case 8: + case 9: + case 10: + D_80164A89 = 0; + camera->pos[0] = posX; + camera->pos[1] = posY; + camera->pos[2] = posZ; + camera->someBitFlags = 0; + camera->lookAt[0] = 0.0f; + camera->lookAt[2] = 150.0f; + camera->lookAt[1] = posY - 3.0; + camera->up[0] = 0.0f; + camera->up[1] = 1.0f; + camera->up[2] = 0.0f; + camera->playerId = (s16) 0; + camera->unk_B0 = 0; + camera->unk_A0 = 0.0f; + + // D_801649D8[cameraId] = 20.0f; + // D_801649E8[cameraId] = 10.0f; + // D_801649F8[cameraId] = 7.0f; + // D_80164A2C = 0; + // D_80164A30 = 30.0f; + // D_80164A38[cameraId] = 0.0f; + // D_80164A48[cameraId] = 0.0f; + + // D_80164A90[cameraId] = 0.0f; + // D_80164AA0[cameraId] = 0.0f; + // D_80164A78[cameraId] = D_800DDB30[gActiveScreenMode]; + // D_80164A18[cameraId] = 0; + // D_80164A08[cameraId] = 0; + // D_80164498[cameraId] = 0.0f; + camera->unk_94.unk_8 = 0; + camera->unk_94.unk_0 = 0.0f; + + player += cameraId; + camera->unk_2C = player->rotation[1]; + camera->unk_AC = player->rotation[1]; + switch (gActiveScreenMode) { + case SCREEN_MODE_1P: + case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL: + if (gModeSelection == BATTLE) { + camera->unk_30[0] = 0.0f; + camera->unk_30[1] = 11.6f; + camera->unk_30[2] = -38.5f; + camera->unk_3C[0] = 0.0f; + camera->unk_3C[1] = 0.0f; + camera->unk_3C[2] = 19.2f; + D_80164A88 = 0; + } else { + camera->unk_30[0] = 0.0f; + camera->unk_30[1] = 9.5f; + camera->unk_30[2] = -50.0f; + camera->unk_3C[0] = 0.0f; + camera->unk_3C[1] = 0.0f; + camera->unk_3C[2] = 70.0f; + } + break; + case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: + if (gModeSelection == BATTLE) { + camera->unk_30[0] = 0.0f; + camera->unk_30[1] = 11.6f; + camera->unk_30[2] = -38.5f; + camera->unk_3C[0] = 0.0f; + camera->unk_3C[1] = 0.0f; + camera->unk_3C[2] = 19.2f; + } else { + camera->unk_30[0] = 0.0f; + camera->unk_30[1] = 9.6f; + camera->unk_30[2] = -35.0f; + camera->unk_3C[0] = 0.0f; + camera->unk_3C[1] = 0.0f; + camera->unk_3C[2] = 30.0f; + } + break; + case SCREEN_MODE_3P_4P_SPLITSCREEN: + if (gModeSelection == BATTLE) { + camera->unk_30[0] = 0.0f; + camera->unk_30[1] = 11.6f; + camera->unk_30[2] = -38.5f; + camera->unk_3C[0] = 0.0f; + camera->unk_3C[1] = 0.0f; + camera->unk_3C[2] = 19.2f; + } else { + camera->unk_30[0] = 0.0f; + camera->unk_30[1] = 9.0f; + camera->unk_30[2] = -40.0f; + camera->unk_3C[0] = 0.0f; + camera->unk_3C[1] = 0.0f; + camera->unk_3C[2] = 18.0f; + } + break; + } + + //func_80014DE4(cameraId); + + // if (D_80164678[cameraId] == 0) { + if (D_80164A28 == 1) { + // gCameraZoom[cameraId] = 80.0f; + } else { + // gCameraZoom[cameraId] = 40.0f; + } + camera->unk_B4 = gCameraZoom[0]; + // } + // if (D_80164678[cameraId] == 1) { + // if (D_80164A28 == 1) { + // gCameraZoom[cameraId] = 100.0f; + // } else { + // gCameraZoom[cameraId] = 60.0f; + // } + // camera->unk_B4 = gCameraZoom[cameraId]; + // // } + // if (D_80164678[cameraId] == 2) { + // if (D_80164A28 == 1) { + // gCameraZoom[cameraId] = 100.0f; + // } else { + // gCameraZoom[cameraId] = 60.0f; + // } + // camera->unk_B4 = gCameraZoom[cameraId]; + // D_80164A38[cameraId] = 20.0f; + // D_80164A48[cameraId] = 1.5f; + // D_80164A78[cameraId] = 1.0f; + // } + break; + } + func_802B7F7C(camera->pos, camera->lookAt, camera->rot); +} + // Thwomp related void func_8001CA10(Camera* camera) { camera->unk_94.unk_8 = 0; @@ -241,7 +383,7 @@ void func_8001CA78(UNUSED Player* player, Camera* camera, Vec3f arg2, f32* arg3, arg2[2] = camera->lookAt[2]; calculate_orientation_matrix(sp74, 0, 1, 0, -0x00008000); mtxf_translate_vec3f_mat3(sp5C, sp74); - if (GetCourse() == GetToadsTurnpike()) { + if (IsToadsTurnpike()) { var_f14 = sp5C[0]; } else { var_f14 = sp5C[0] + temp_s2->posX; @@ -252,7 +394,7 @@ void func_8001CA78(UNUSED Player* player, Camera* camera, Vec3f arg2, f32* arg3, arg2[1] += (temp_f18 - camera->lookAt[1]) * 1; arg2[2] += (temp_f16 - camera->lookAt[2]) * 1; mtxf_translate_vec3f_mat3(sp68, sp74); - if (GetCourse() == GetToadsTurnpike()) { + if (IsToadsTurnpike()) { var_f14 = sp68[0]; } else { var_f14 = sp68[0] + temp_s2->posX; @@ -345,7 +487,7 @@ void func_8001CCEC(Player* player, Camera* camera, Vec3f arg2, f32* arg3, f32* a move_f32_towards(&D_80164AA0[index], 10, 0.02f); break; default: - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { move_f32_towards(&D_80164A90[index], 50, 0.04f); move_f32_towards(&D_80164AA0[index], 35, 0.04f); } else { @@ -993,6 +1135,7 @@ void func_8001EE98(Player* player, Camera* camera, s8 index) { break; } freecam(camera, player, index); // Runs func_8001E45C when freecam is disabled + //func_8001E45C(camera, player, index); break; case 8: func_8001E0C4(camera, player, index); diff --git a/src/camera.h b/src/camera.h index 6abeb3aad..56cc07a94 100644 --- a/src/camera.h +++ b/src/camera.h @@ -59,6 +59,7 @@ typedef struct { } Camera; /* size = 0xB8 */ void camera_init(f32, f32, f32, s16, u32, s32); +void freecam_init(f32 posX, f32 posY, f32 posZ, s16 rot, u32 arg4, s32 cameraId); void func_8001CA10(Camera*); void func_8001CA24(Player*, f32); void func_8001CA78(Player*, Camera*, Vec3f, f32*, f32*, f32*, s32, s32); @@ -81,6 +82,7 @@ extern Camera* camera1; extern Camera* camera2; extern Camera* camera3; extern Camera* camera4; +extern Camera* gFreecamCamera; // end of camera.c variables diff --git a/src/code_800029B0.c b/src/code_800029B0.c index 73f104ed8..beba2e490 100644 --- a/src/code_800029B0.c +++ b/src/code_800029B0.c @@ -233,16 +233,18 @@ void setup_race(void) { // D_8015F8D0[1] = (f32) (D_80164490->posY - 15); // D_8015F8D0[2] = D_80164490->posZ; - // if (GetCourse() == GetToadsTurnpike()) { + // if (IsToadsTurnpike()) { // D_8015F8D0[0] = (gIsMirrorMode != 0) ? D_80164490->posX + 138.0f : D_80164490->posX - 138.0f; - // } else if (GetCourse() == GetWarioStadium()) { + // } else if (IsWarioStadium()) { // D_8015F8D0[0] = (gIsMirrorMode != 0) ? D_80164490->posX + 12.0f : D_80164490->posX - 12.0f; // } else { // D_8015F8D0[0] = D_80164490->posX; // } // } if (!gDemoMode) { - func_800CA008(gPlayerCountSelection1 - 1, gCurrentCourseId + 4); + //! @warning this used to be gCurrentCourseId + 4 + // Hopefully this is equivallent. + func_800CA008(gPlayerCountSelection1 - 1, GetCourseIndex() + 4); func_800CB2C4(); } diff --git a/src/code_80005FD0.c b/src/code_80005FD0.c index 6263883f2..3f8a0b1fc 100644 --- a/src/code_80005FD0.c +++ b/src/code_80005FD0.c @@ -1076,7 +1076,7 @@ void func_80008424(s32 playerId, f32 arg1, Player* player) { if (!(player->effects & 0x80) && !(player->effects & 0x40) && !(player->effects & 0x20000) && !(player->soundEffects & 0x400000) && !(player->soundEffects & 0x01000000) && !(player->soundEffects & 2) && !(player->soundEffects & 4)) { - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { func_80007FA4(playerId, player, var_f2); } else if ((bStopAICrossing[playerId] == 1) && !(player->effects & (STAR_EFFECT | BOO_EFFECT))) { decelerate_ai_player(player, 10.0f); @@ -1140,7 +1140,7 @@ void func_80008424(s32 playerId, f32 arg1, Player* player) { } if (var_a1 != 1) { if (var_f2 < arg1) { - if ((gDemoMode == 1) && (GetCourse() != GetPodiumCeremony())) { + if ((gDemoMode == 1) && (!IsPodiumCeremony())) { player_speed(player); } else if (D_80163330[playerId] == 1) { func_80007D04(playerId, player); @@ -1448,15 +1448,15 @@ void func_8000929C(s32 playerId, Player* player) { D_801630E2 = 1; func_80008F38(playerId); } - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { func_8000B95C(playerId, sSomeNearestWaypoint, D_80163448); return; } if ((sSomeNearestWaypoint < 0x14) || ((gWaypointCountByPathIndex[D_80163448] - 0x14) < sSomeNearestWaypoint) || - (GetCourse() == GetKalimariDesert())) { + (IsKalimariDesert())) { var_v1 = 0; var_t0 = 0; - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { D_801634EC = 0; if (player->effects & 0x200) { D_801634EC = 1; @@ -1510,7 +1510,7 @@ void func_8000929C(s32 playerId, Player* player) { } } D_80163450[playerId] = tempPos2; - if ((GetCourse() == GetYoshiValley()) && (D_801630E2 == 1)) { + if ((IsYoshiValley()) && (D_801630E2 == 1)) { func_80009000(playerId); if (((player->type & 0x4000) == 0) || (player->type & 0x1000)) { func_800090F0(playerId, player); @@ -1664,7 +1664,7 @@ void func_80009B60(s32 playerId) { if (!(player->unk_0CA & 2) && !(player->unk_0CA & 8)) { D_80163448 = gPathIndexByPlayerId[playerId]; func_80008DC0(D_80163448); - //if (GetCourse() == GetKalimariDesert()) { + //if (IsKalimariDesert()) { CM_VehicleCollision(playerId, player); //func_80012DC0(playerId, player); if (playerId == 0) { @@ -1672,9 +1672,9 @@ void func_80009B60(s32 playerId) { //func_80013054(); } //} - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { //func_80013854(player); - } else if (GetCourse() == GetToadsTurnpike()) { + } else if (IsToadsTurnpike()) { func_800148C4(playerId, player); func_80014A18(playerId, player); func_80014B6C(playerId, player); @@ -1685,11 +1685,11 @@ void func_80009B60(s32 playerId) { player->unk_044 &= ~0x0001; } func_8000929C(playerId, player); - if ((GetCourse() != GetPodiumCeremony()) && ((D_80163240[playerId] == 1) || (playerId == 0))) { + if ((!IsPodiumCeremony()) && ((D_80163240[playerId] == 1) || (playerId == 0))) { set_places(); } if (player->type & 0x1000) { - if ((D_801630E2 == 1) && (GetCourse() != GetPodiumCeremony())) { + if ((D_801630E2 == 1) && (!IsPodiumCeremony())) { kart_ai_behaviour(playerId); } if ((playerId & 1) != (D_80163378 & 1)) { @@ -1706,11 +1706,11 @@ void func_80009B60(s32 playerId) { break; } D_801631E0[playerId] = 0; - if ((player->effects & 0x1000) && (GetCourse() != GetPodiumCeremony())) { + if ((player->effects & 0x1000) && (!IsPodiumCeremony())) { D_801631E0[playerId] = 1; } - if ((D_801646CC == 1) || (player->type & 0x800) || (GetCourse() == GetPodiumCeremony())) { - if (GetCourse() != GetToadsTurnpike()) { + if ((D_801646CC == 1) || (player->type & 0x800) || (IsPodiumCeremony())) { + if (!IsToadsTurnpike()) { D_801634F8[playerId].unk4 = 0.0f; } D_801634F8[playerId].unkC = 0.0f; @@ -1731,9 +1731,9 @@ void func_80009B60(s32 playerId) { // Old vehicle draw method was here - if ((GetCourse() == GetYoshiValley()) || (GetCourse() == GetPodiumCeremony())) { + if ((IsYoshiValley()) || (IsPodiumCeremony())) { D_801634F8[playerId].unk4 = 0.0f; - } else if (GetCourse() == GetToadsTurnpike()) { + } else if (IsToadsTurnpike()) { // func_8001490C(playerId); // func_80014A60(playerId); // func_80014BB4(playerId); @@ -1840,10 +1840,10 @@ void func_80009B60(s32 playerId) { } D_801630B8[playerId] = func_8000B7E4(playerId, sSomeNearestWaypoint); func_8000D438(playerId, sSomeNearestWaypoint); - if (GetCourse() != GetPodiumCeremony()) { + if (!IsPodiumCeremony()) { if (D_80164450[playerId] < 0xB) { stackPadding1A = D_801630E0; - if ((D_80164450[playerId] > 0) && (GetCourse() == GetToadsTurnpike())) { + if ((D_80164450[playerId] > 0) && (IsToadsTurnpike())) { stackPadding1A += 0x14; stackPadding1A %= D_80164430; func_8000BBD8(stackPadding1A, 0.0f, 0); @@ -1877,7 +1877,7 @@ void func_80009B60(s32 playerId) { } } } - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { switch (D_80163410[playerId]) { /* switch 3; irregular */ case 3: /* switch 3 */ D_80162FA0[0] = D_80163418[playerId]; @@ -2297,7 +2297,7 @@ s16 find_closest_waypoint_track_section(f32 posX, f32 posY, f32 posZ, u16 trackS considerWaypoint = &pathWaypoints[0]; for (considerWaypointIndex = 0; considerWaypointIndex < pathWaypointCount; considerWaypointIndex++, considerWaypoint++) { - if ((considerWaypoint->trackSectionId == trackSectionId) || (GetCourse() == GetPodiumCeremony())) { + if ((considerWaypoint->trackSectionId == trackSectionId) || (IsPodiumCeremony())) { var_t1 = 1; x_dist = (f32) considerWaypoint->posX - posX; y_dist = (f32) considerWaypoint->posY - posY; @@ -2463,7 +2463,7 @@ void func_8000CBA4(UNUSED f32 posX, f32 posY, UNUSED f32 posZ, s16* waypointInde s16 var_v0; var_v0 = *waypointIndex; - if ((GetCourse() == GetWarioStadium()) && (var_v0 >= 0x475) && (var_v0 < 0x480) && (posY < 0.0f)) { + if ((IsWarioStadium()) && (var_v0 >= 0x475) && (var_v0 < 0x480) && (posY < 0.0f)) { var_v0 = 0x0398; } *waypointIndex = var_v0; @@ -2666,11 +2666,11 @@ void func_8000D438(s32 arg0, u16 arg1) { sp2C = func_8000D3B8(arg0); thing = arg1; - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { var_a2 = 1; - } else if (GetCourse() == GetToadsTurnpike()) { + } else if (IsToadsTurnpike()) { var_a2 = 7; - } else if (GetCourse() == GetYoshiValley()) { + } else if (IsYoshiValley()) { } else { if (temp_v1 < 6) { var_a2 = 8; @@ -2908,11 +2908,11 @@ void set_bomb_kart_spawn_positions(void) { for (var_s3 = 0; var_s3 < NUM_BOMB_KARTS_VERSUS; var_s3++) { //bombKartSpawn = &gBombKartSpawns[gCurrentCourseId][var_s3]; - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { startingXPos = bombKartSpawn->startingXPos; startingZPos = bombKartSpawn->startingZPos; startingYPos = spawn_actor_on_surface(startingXPos, 2000.0f, startingZPos); - } else if (GetCourse() == GetPodiumCeremony()) { + } else if (IsPodiumCeremony()) { temp_v0 = &D_80164550[3][bombKartSpawn->waypointIndex]; startingXPos = temp_v0->posX; startingYPos = temp_v0->posY; @@ -3014,7 +3014,7 @@ void func_8000DF8C(s32 bombKartId) { return; } - if (((bombKart->unk_4A != 1) || (GetCourse() == GetPodiumCeremony()))) { + if (((bombKart->unk_4A != 1) || (IsPodiumCeremony()))) { var_f22 = bombKart->bombPos[0]; var_f20 = bombKart->bombPos[1]; var_f24 = bombKart->bombPos[2]; @@ -3025,7 +3025,7 @@ void func_8000DF8C(s32 bombKartId) { var_s1 = bombKart->circleTimer; if ((sp7E != 0) && (sp7E != 4)) { if (1) {} - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { if (D_8016347E == 1) { var_v0 = gPlayerFour; temp_f0 = var_f22 - var_v0->pos[0]; @@ -3049,7 +3049,7 @@ void func_8000DF8C(s32 bombKartId) { if ((((temp_f0 * temp_f0) + (temp_f2 * temp_f2)) + (temp_f12 * temp_f12)) < 25.0f) { sp7E = 4; var_s1 = 0; - if (GetCourse() == GetFrappeSnowland()) { + if (IsFrappeSnowland()) { var_v0->soundEffects |= 0x01000000; } else { var_v0->soundEffects |= 0x400000; @@ -3466,7 +3466,7 @@ void func_8000F628(void) { D_80163050[i] = 0; D_80162FF8[i] = 0; D_80163010[i] = 0; - if (GetCourse() != GetPodiumCeremony()) { + if (!IsPodiumCeremony()) { func_8000B95C(i, 0, 0); } //! todo: @BUG this doesn't seem right. This variable is metadata. @@ -3551,7 +3551,7 @@ void func_8000F628(void) { } } } - if ((gDemoUseController == 1) && (GetCourse() != GetPodiumCeremony())) { + if ((gDemoUseController == 1) && (!IsPodiumCeremony())) { for (i = 0; i < NUM_PLAYERS; i++) { D_80163330[i] = 0; } @@ -3635,7 +3635,7 @@ void func_800100F0(s32 pathIndex) { if (CM_GetProps()->AIMaximumSeparation >= 1.0f) { pathDest = D_80164550[pathIndex]; bInvalidPath = 1; - if (GetCourse() != GetPodiumCeremony()) { + if (!IsPodiumCeremony()) { TrackWaypoint* pathSrc = CM_GetProps()->PathTable2[pathIndex]; if (pathSrc == NULL) { @@ -3879,7 +3879,7 @@ void func_80010E6C(s32 pathIndex) { } else { break; } - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { break; } } @@ -3934,7 +3934,7 @@ s32 func_80011014(TrackWaypoint* pathDest, TrackWaypoint* path, s32 numPathPoint var_s0 = 0; temp_f20 = (f32) path[0].posX; temp_f22 = (f32) path[0].posZ; - var_f28 = func_80010F40(temp_f20, 2000.0f, temp_f22, gCurrentCourseId, 0); + var_f28 = func_80010F40(temp_f20, 2000.0f, temp_f22, 0, 0); for (i = 0; i < numPathPoints; i++) { point1 = &path[i % numPathPoints]; @@ -3969,10 +3969,10 @@ s32 func_80011014(TrackWaypoint* pathDest, TrackWaypoint* path, s32 numPathPoint if (gIsMirrorMode) { // temp_f12 = -temp_f24_2; pathDest->posX = (s16) -temp_f24_2; - var_f20_2 = func_80010FA0(-temp_f24_2, var_f28, x1_2, gCurrentCourseId, var_s0); + var_f20_2 = func_80010FA0(-temp_f24_2, var_f28, x1_2, 0, var_s0); } else { pathDest->posX = (s16) temp_f24_2; - var_f20_2 = func_80010FA0(temp_f24_2, var_f28, x1_2, gCurrentCourseId, var_s0); + var_f20_2 = func_80010FA0(temp_f24_2, var_f28, x1_2, 0, var_s0); } pathDest->posZ = (s16) temp_f22; @@ -3982,11 +3982,11 @@ s32 func_80011014(TrackWaypoint* pathDest, TrackWaypoint* path, s32 numPathPoint var_f20_2 = var_f28; } else { - if (GetCourse() == GetRainbowRoad()) { + if (IsRainbowRoad()) { if (var_f20_2 < (var_f28 - 15.0)) { var_f20_2 = (f32) var_f28 - 15.0; } - } else if (GetCourse() == GetWarioStadium()) { + } else if (IsWarioStadium()) { if ((var_s0 >= 1140) && (var_s0 <= 1152)) { var_f20_2 = var_f28; } else { @@ -3994,7 +3994,7 @@ s32 func_80011014(TrackWaypoint* pathDest, TrackWaypoint* path, s32 numPathPoint var_f20_2 = (f32) (var_f28 - 4.0); } } - } else if (GetCourse() == GetDkJungle()) { + } else if (IsDkJungle()) { if ((var_s0 > 204) && (var_s0 < 220)) { var_f20_2 = var_f28; } else { @@ -4628,7 +4628,7 @@ void func_80013054(void) { void check_ai_crossing_distance(s32 playerId) { bStopAICrossing[playerId] = 0; - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { if ((!(D_801631E0[playerId] != 0)) || (set_vehicle_render_distance_flags(gPlayers[playerId].pos, TRAIN_CROSSING_AI_DISTANCE, 0))) { @@ -5819,7 +5819,7 @@ void func_80016C3C(UNUSED s32 playerId, UNUSED f32 arg1, s32 cameraId) { D_80164688[cameraId] = -0.1f; } D_80163DD8[cameraId] = 0; - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { D_80163DD8[cameraId] = random_int(4U); D_80164688[cameraId] = 0.0f; } @@ -5892,8 +5892,7 @@ void func_80017054(Camera* camera, UNUSED Player* player, UNUSED s32 index, s32 D_80163238 = playerId; sp56 = gNearestWaypointByCameraId[cameraId]; gNearestWaypointByCameraId[cameraId] = func_8000D33C(camera->pos[0], camera->pos[1], camera->pos[2], gNearestWaypointByCameraId[cameraId], pathIndex); - // if (GetCourse() == GetYoshiValley()) { - if (gCurrentCourseId == 4) { + if (IsYoshiValley()) { if ((sp56 != gNearestWaypointByCameraId[cameraId]) && (gNearestWaypointByCameraId[cameraId] == 1)) { pathIndex = (D_80163DD8[cameraId] = random_int(4U)); gNearestWaypointByCameraId[cameraId] = func_8000D33C(camera->pos[0], camera->pos[1], camera->pos[2], gNearestWaypointByCameraId[cameraId], pathIndex); @@ -6574,7 +6573,7 @@ void func_80019D2C(Camera* camera, Player* player, s32 arg2) { s32 nearestWaypoint; playerId = camera->playerId; - if ((D_80163378 != 0) && (GetCourse() == GetLuigiRaceway())) { + if ((D_80163378 != 0) && (IsLuigiRaceway())) { calculate_camera_up_vector(camera, arg2); nearestWaypoint = gNearestWaypointByPlayerId[playerId]; if (((nearestWaypoint >= 0x65) && (nearestWaypoint < 0xFA)) || @@ -6719,7 +6718,7 @@ void func_8001A220(UNUSED s32 arg0, s32 cameraId) { } s32 func_8001A310(s32 waypoint, s32 arg1) { - if ((GetCourse() == GetBowsersCastle()) && (arg1 != 0) && (waypoint >= 0xE7) && (waypoint < 0x1C2)) { + if ((IsBowsersCastle()) && (arg1 != 0) && (waypoint >= 0xE7) && (waypoint < 0x1C2)) { arg1 = 0; } return arg1; @@ -7500,7 +7499,7 @@ void func_8001BE78(void) { void func_8001C05C(void) { init_segment_racing(); gCurrentCourseId = COURSE_AWARD_CEREMONY; - SetCourseByClass(GetPodiumCeremony()); + SelectPodiumCeremony(); D_8016347C = 0; D_8016347E = 0; D_80163480 = 0; @@ -7573,7 +7572,7 @@ void func_8001C14C(void) { } void render_bomb_karts_wrap(s32 cameraId) { - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { if (gBombKarts[0].waypointIndex >= 16) { render_bomb_karts(PLAYER_FOUR); } diff --git a/src/code_80057C60.c b/src/code_80057C60.c index 24ce0abe7..b82bba6cb 100644 --- a/src/code_80057C60.c +++ b/src/code_80057C60.c @@ -39,6 +39,7 @@ #include #include "port/Game.h" #include "engine/Matrix.h" +#include "port/interpolation/FrameInterpolation.h" //! @warning this macro is undef'd at the end of this file #define MAKE_RGB(r, g, b) (((r) << 0x10) | ((g) << 0x08) | (b << 0x00)) @@ -769,7 +770,7 @@ void render_object_for_player(s32 cameraId) { render_object_leaf_particle(cameraId); if (D_80165730 != 0) { - //render_balloons_grand_prix(cameraId); + // render_balloons_grand_prix(cameraId); } if (gModeSelection == BATTLE) { CM_DrawBattleBombKarts(cameraId); @@ -777,7 +778,7 @@ void render_object_for_player(s32 cameraId) { } void render_snowing_effect(s32 playerId) { - if (GetCourse() == GetFrappeSnowland()) { + if (IsFrappeSnowland()) { if (gGamestate != 9) { if ((D_8015F894 == 0) && (gPlayerCountSelection1 == 1)) { render_object_snowflakes_particles(); @@ -938,6 +939,10 @@ void func_80058F48(void) { void func_80058F78(void) { if (gHUDDisable == 0) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("HudMatrix", 0); + set_matrix_hud_screen(); if ((!gDemoMode) && (gIsHUDVisible != 0) && (D_801657D8 == 0)) { draw_item_window(PLAYER_ONE); @@ -950,6 +955,9 @@ void func_80058F78(void) { } } } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } @@ -1555,7 +1563,7 @@ void func_8005A3C0(void) { } void func_8005A71C(void) { - // if (GetCourse() == GetBowsersCastle()) { + // if (IsBowsersCastle()) { // func_80081210(); //} } @@ -1632,11 +1640,11 @@ void update_object(void) { // update_ferries_smoke_particle(); // break; // } - //if (D_80165730 != 0) { + // if (D_80165730 != 0) { // func_80074EE8(); // Grand prix balloons //} func_80076F2C(); - if ((s16) GetCourse() != GetFrappeSnowland()) { + if (!IsFrappeSnowland()) { update_leaf(); } } @@ -2588,8 +2596,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) { case 1: /* switch 1 */ CM_ActivateSecondLapLakitu(playerId); // func_80079084(playerId); func_800C9060(playerId, SOUND_ARG_LOAD(0x19, 0x00, 0xF0, 0x15)); - if ((GetCourse() == GetLuigiRaceway()) && (D_80165898 == 0) && - (gModeSelection != (s32) TIME_TRIALS)) { + if ((IsLuigiRaceway()) && (D_80165898 == 0) && (gModeSelection != (s32) TIME_TRIALS)) { D_80165898 = 1; } break; @@ -2610,7 +2617,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) { if (D_8018D114 == 2) { D_80165800[playerId] = 0; } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { playerHUD[playerId].unk_81 = 1; } playerHUD[playerId].lap1CompletionTimeX = 0x0140; @@ -2927,22 +2934,22 @@ void func_8005DAF4(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8 func_8005D794(player, &player->unk_258[10 + arg1], var_f2, var_f12, var_f14, (s8) surfaceType, (s8) var_t3); func_8005D7D8(&player->unk_258[10 + arg1], 2, 0.46f); - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[10 + arg1], 10, 0, 0x0080); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[10 + arg1], 11, 0, 0x0080); } player->unk_258[10 + arg1].unk_03A = random_int(0x0010U); @@ -2951,22 +2958,22 @@ void func_8005DAF4(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8 func_8005D794(player, &player->unk_258[10 + arg1], var_f2, var_f12, var_f14, (s8) surfaceType, (s8) var_t3); func_8005D7D8(&player->unk_258[10 + arg1], 2, 0.46f); - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[10 + arg1], 10, 0, 0x0080); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[10 + arg1], 11, 0, 0x0080); } player->unk_258[10 + arg1].unk_03A = random_int(0x0010U); @@ -3193,44 +3200,44 @@ void func_8005ED48(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8 ((player->unk_258[10 + arg2].unk_01E > 0) || (player->unk_258[10 + arg2].unk_01C == 0))) { func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t3); func_8005D7D8(&player->unk_258[10 + arg1], 5, 0.46f); - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[10 + arg1], 10, 0, 0x0080); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[10 + arg1], 11, 0, 0x0080); } player->unk_258[10 + arg1].unk_03A = random_int(0x0010U); } else if (player->unk_258[10 + arg2].unk_01E > 0) { func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t3); func_8005D7D8(&player->unk_258[10 + arg1], 5, 0.46f); - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[10 + arg1], 0x000A, 0, 0x0080); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[10 + arg1], 0x000B, 0, 0x0080); } player->unk_258[10 + arg1].unk_03A = random_int(0x0010U); @@ -3394,44 +3401,44 @@ void func_8005F90C(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8 ((player->unk_258[10 + arg2].unk_01E > 0) || (player->unk_258[10 + arg2].unk_01C == 0))) { func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t1); func_8005D7D8(&player->unk_258[10 + arg1], 4, 0.46f); - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[10 + arg1], 0x000A, 0, 0x0080); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[10 + arg1], 0x000B, 0, 0x0080); } player->unk_258[10 + arg1].unk_03A = random_int(0x0010U); } else if (player->unk_258[10 + arg2].unk_01E > 0) { func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t1); func_8005D7D8(&player->unk_258[10 + arg1], 4, 0.46f); - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[10 + arg1], 0x000A, 0, 0x0080); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[10 + arg1], 0x000B, 0, 0x0080); } player->unk_258[10 + arg1].unk_03A = random_int(0x0010U); @@ -3630,13 +3637,13 @@ void func_800608E0(Player* player, s16 arg1, UNUSED s32 arg2, s8 arg3, UNUSED s8 var_f0 = 0.0f; } sp4C = (D_801652A0[arg3] - player->pos[1]) - 3.0f; - if ((player->unk_0DE & 1) && (GetCourse() != GetKoopaTroopaBeach())) { + if ((player->unk_0DE & 1) && (!IsKoopaTroopaBeach())) { var_f0 = 2.5f; sp4C = (f32) ((f64) (D_801652A0[arg3] - player->pos[1]) + 0.1); } func_8005D794(player, &player->unk_258[arg1], 0.0f, 0.0f, 0.0f, (s8) 0, (s8) 0); func_8005D7D8(&player->unk_258[arg1], 3, var_f0); - if ((GetCourse() == GetBowsersCastle()) || (GetCourse() == GetBigDonut())) { + if ((IsBowsersCastle()) || (IsBigDonut())) { func_8005D800(&player->unk_258[arg1], 0, 0x00AF); } else { func_8005D800(&player->unk_258[arg1], 0x00FFFFFF, 0x00CF); @@ -3650,7 +3657,7 @@ void func_800608E0(Player* player, s16 arg1, UNUSED s32 arg2, s8 arg3, UNUSED s8 } void func_80060B14(Player* player, s16 arg1, s32 arg2, s8 arg3, s8 arg4) { - if ((GetCourse() != GetSkyscraper()) && (GetCourse() != GetRainbowRoad())) { + if ((!IsSkyscraper()) && (!IsRainbowRoad())) { if ((arg1 == 0) && ((player->unk_258[arg2].unk_01E > 0) || (player->unk_258[arg2].unk_01C == 0))) { func_800608E0(player, arg1, arg2, arg3, arg4); } else if (player->unk_258[arg2].unk_01E > 0) { @@ -3666,10 +3673,10 @@ void func_80060BCC(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8 f32 sp48; f32 sp44; - if (GetCourse() == GetSkyscraper()) { + if (IsSkyscraper()) { return; } - if (GetCourse() == GetRainbowRoad()) { + if (IsRainbowRoad()) { return; } sp54 = random_int(0x0168U) - 0xB4; @@ -3704,7 +3711,7 @@ void func_80060F50(Player* player, s16 arg1, UNUSED s32 arg2, s8 arg3, UNUSED s8 func_8005D794(player, &player->unk_258[arg1], 0.0f, 0.0f, 0.0f, 0, 0); func_8005D7D8(&player->unk_258[arg1], 5, 4.0f); - if ((GetCourse() == GetBowsersCastle()) || (GetCourse() == GetBigDonut())) { + if ((IsBowsersCastle()) || (IsBigDonut())) { func_8005D800(&player->unk_258[arg1], 0xFF0000, 0xFF); } else { func_8005D800(&player->unk_258[arg1], 0xFFFFFF, 0xFF); @@ -4050,22 +4057,22 @@ void func_800624D8(Player* player, UNUSED s32 arg1, UNUSED s32 arg2, UNUSED s8 a switch (player->surfaceType) { case DIRT: for (var_s1 = 0; var_s1 < 10; var_s1++) { - if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) { + if ((IsChocoMountain()) || (IsRoyalRaceway())) { func_8005DAD8(&player->unk_258[0x1E + var_s1], 1, 0, 0x00A8); } - if (GetCourse() == GetKalimariDesert()) { + if (IsKalimariDesert()) { func_8005DAD8(&player->unk_258[0x1E + var_s1], 7, 0, 0x00A8); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { func_8005DAD8(&player->unk_258[0x1E + var_s1], 8, 0, 0x00A8); } - if (GetCourse() == GetWarioStadium()) { + if (IsWarioStadium()) { func_8005DAD8(&player->unk_258[0x1E + var_s1], 9, 0, 0x00A8); } - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { func_8005DAD8(&player->unk_258[0x1E + var_s1], 0x000A, 0, 0x00A8); } - if (GetCourse() == GetDkJungle()) { + if (IsDkJungle()) { func_8005DAD8(&player->unk_258[0x1E + var_s1], 0x000B, 0, 0x00A8); } func_80062484(player, &player->unk_258[0x1E + var_s1], var_s1); @@ -4620,7 +4627,7 @@ void func_80064184(Player* player, s16 arg1, s8 arg2, UNUSED s8 arg3) { f32 sp3C; sp40 = D_801652A0[arg2] - player->pos[1] - 3.0f; - if (((player->unk_0DE & 1) != 0) && (GetCourse() != GetKoopaTroopaBeach())) { + if (((player->unk_0DE & 1) != 0) && (!IsKoopaTroopaBeach())) { sp40 = D_801652A0[arg2] - player->pos[1] + 0.1; } @@ -4968,9 +4975,8 @@ void func_800651F4(Player* player, UNUSED s8 arg1, UNUSED s8 arg2, s8 arg3) { void func_800652D4(Vec3f arg0, Vec3s arg1, f32 arg2) { Mat4 mtx; - mtxf_translate_rotate(mtx, arg0, arg1); - mtxf_scale2(mtx, arg2); + mtxf_scale(mtx, arg2); // convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], mtx); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]), // G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); @@ -5098,6 +5104,7 @@ void func_80065AB0(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) { spAC[0] = 0; spAC[1] = player->unk_048[arg3]; spAC[2] = 0; + func_800652D4(spB4, spAC, player->unk_258[10 + arg2].unk_00C * player->size); if (var_s0 == 0) { gSPDisplayList(gDisplayListHead++, D_0D008DB8); @@ -5667,6 +5674,7 @@ void func_800691B8(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) { sp54[1] = player->unk_048[arg3]; player->unk_258[30 + arg2].unk_03A += 0x1C71; sp54[2] = player->unk_258[30 + arg2].unk_03A; + func_800652D4(sp5C, sp54, player->size * 0.5); gSPDisplayList(gDisplayListHead++, D_0D008D58); gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE); @@ -5737,6 +5745,7 @@ void func_800696CC(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3, f32 arg4) sp54[0] = 0; sp54[1] = player->unk_048[arg3]; sp54[2] = 0; + func_800652D4(sp5C, sp54, player->size * arg4); gSPDisplayList(gDisplayListHead++, D_0D008D58); gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE); @@ -5764,6 +5773,7 @@ void func_80069938(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) { sp54[0] = 0; sp54[1] = player->unk_048[arg3]; sp54[2] = player->unk_258[30 + arg2].unk_038; + func_800652D4(sp5C, sp54, player->unk_258[30 + arg2].unk_00C * player->size); gSPDisplayList(gDisplayListHead++, D_0D008D58); gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE); @@ -6058,8 +6068,12 @@ void render_battle_balloon(Player* player, s8 arg1, s16 arg2, s8 arg3) { sp12C[1] = player->unk_048[arg3]; sp12C[2] = D_8018D7D0[arg1][arg2] - (D_8018D860[arg1][arg2] * coss(temp_t1)) - ((D_8018D890[arg1][arg2] * 8) * sins(temp_t1)); + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild((uintptr_t) player, arg1 | arg2 << 16); + mtxf_translate_rotate(mtx, sp134, sp12C); - mtxf_scale2(mtx, var_f20); + mtxf_scale(mtx, var_f20); // convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], sp140); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]), @@ -6087,6 +6101,10 @@ void render_battle_balloon(Player* player, s8 arg1, s16 arg2, s8 arg3) { gSPVertex(gDisplayListHead++, gBalloonVertexPlane2, 4, 0); gSPDisplayList(gDisplayListHead++, common_square_plain_render); gSPTexture(gDisplayListHead++, 0x0001, 0x0001, 0, G_TX_RENDERTILE, G_OFF); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); + gMatrixEffectCount++; } @@ -6184,7 +6202,7 @@ void render_balloon(Vec3f arg0, f32 arg1, s16 arg2, s16 arg3) { spF4[1] = camera1->rot[1]; spF4[2] = arg2; mtxf_translate_rotate(mtx, spFC, spF4); - mtxf_scale2(mtx, arg1); + mtxf_scale(mtx, arg1); // convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], sp108); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]), // G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); @@ -6566,6 +6584,9 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) { s16 var_s2; if ((player->unk_002 & (8 << (screenId * 4))) == (8 << (screenId * 4))) { for (var_s2 = 0; var_s2 < 10; var_s2++) { + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("SmokeDust", TAG_SMOKE_DUST((playerId << 8) + var_s2)); + switch (player->unk_258[var_s2].unk_012) { case 1: if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) { @@ -6586,6 +6607,8 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) { } break; } + FrameInterpolation_RecordCloseChild(); + FrameInterpolation_RecordOpenChild("SmokeDust", TAG_SMOKE_DUST((playerId << 8) + var_s2 + 30)); switch (player->unk_258[var_s2 + 30].unk_012) { case 1: case 9: @@ -6645,6 +6668,8 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) { } break; } + FrameInterpolation_RecordCloseChild(); + FrameInterpolation_RecordOpenChild("SmokeDust", TAG_SMOKE_DUST((playerId << 8) + var_s2 + 10)); switch (player->unk_258[var_s2 + 10].unk_012) { case 1: if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) { @@ -6686,6 +6711,8 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) { } break; } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } if ((gModeSelection == BATTLE) && (player->unk_002 & (2 << (screenId * 4)))) { @@ -6707,48 +6734,50 @@ void func_8006DC54(Player* player, s8 arg1, s8 arg2) { } } -void func_8006DD3C(Player* arg0, s8 arg1, s8 arg2) { +void func_8006DD3C(Player* player, s8 playerId, s8 arg2) { s16 temp_s0; s32 temp_v0; temp_v0 = 8 << (arg2 * 4); - if (temp_v0 == (arg0->unk_002 & temp_v0)) { + if (temp_v0 == (player->unk_002 & temp_v0)) { for (temp_s0 = 0; temp_s0 < 10; ++temp_s0) { - temp_v0 = arg0->unk_258[temp_s0].unk_012; + temp_v0 = player->unk_258[temp_s0].unk_012; if (temp_v0 != 3) { if (temp_v0 == 5) { - func_8006A280(arg0, arg1, temp_s0, arg2); + func_8006A280(player, playerId, temp_s0, arg2); } } else if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) { - if (arg2 == arg1) { - func_80066998(arg0, arg1, temp_s0, arg2); + if (arg2 == playerId) { + func_80066998(player, playerId, temp_s0, arg2); } } else { - func_80066998(arg0, arg1, temp_s0, arg2); + func_80066998(player, playerId, temp_s0, arg2); } } - if (((arg0->type & 0x4000) == 0x4000) && (arg2 == arg1)) { - switch (arg0->unk_258[20].unk_012) { + if (((player->type & 0x4000) == 0x4000) && (arg2 == playerId)) { + FrameInterpolation_RecordOpenChild("onomatopoeia", TAG_SMOKE_DUST((playerId << 8) + 20)); + switch (player->unk_258[20].unk_012) { case 2: - func_80068310(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0); + func_80068310(player, playerId, player->unk_258[20].unk_00C, arg2, 0); break; case 3: - func_80067964(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0); + func_80067964(player, playerId, player->unk_258[20].unk_00C, arg2, 0); break; case 4: - func_80068724(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0); + func_80068724(player, playerId, player->unk_258[20].unk_00C, arg2, 0); break; case 5: - func_80068AA4(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0); + func_80068AA4(player, playerId, player->unk_258[20].unk_00C, arg2, 0); break; case 6: - func_80068DA0(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0); + func_80068DA0(player, playerId, player->unk_258[20].unk_00C, arg2, 0); break; } - if (arg0->unk_258[21].unk_012 == 5) { - func_80067D3C(arg0, arg2, D_8018D480, 1, 1.6f, 0xFFFFFF); - func_8006801C(arg0, arg2, D_8018D484, 1, 1.6f, 0xFF); + FrameInterpolation_RecordCloseChild(); + if (player->unk_258[21].unk_012 == 5) { + func_80067D3C(player, arg2, D_8018D480, 1, 1.6f, 0xFFFFFF); + func_8006801C(player, arg2, D_8018D484, 1, 1.6f, 0xFF); } } } diff --git a/src/code_8006E9C0.c b/src/code_8006E9C0.c index d74346d00..55d08c423 100644 --- a/src/code_8006E9C0.c +++ b/src/code_8006E9C0.c @@ -162,7 +162,7 @@ void init_item_window(s32 objectIndex) { temp_v0->sizeScaling = 1.0f; } -void func_8006EEE8(s32 courseId) { +void get_minimap_properties() { D_8018D240 = (uintptr_t) CM_GetProps()->Minimap.Texture; // This is incredibly dumb. MinimapDimensions ought to be something more like // `u16 MinimapDimensions[][2]` but that doesn't match for some insane reason @@ -191,8 +191,8 @@ void func_8006F008(void) { xOrientation = -1.0f; } - if (GetCourse() != GetPodiumCeremony()) { - func_8006EEE8((s32) gCurrentCourseId); + if (!IsPodiumCeremony()) { + get_minimap_properties(); } // Flip the minimap player markers @@ -203,7 +203,7 @@ void func_8006F008(void) { switch(gPlayerCount) { case 2: // Set X coord - if (GetCourse() != GetToadsTurnpike()) { + if (!IsToadsTurnpike()) { CM_GetProps()->Minimap.Pos[PLAYER_ONE].X = 265; CM_GetProps()->Minimap.Pos[PLAYER_TWO].X = 265; } else { diff --git a/src/code_8006E9C0.h b/src/code_8006E9C0.h index e5e9bc8d3..e41f7da1e 100644 --- a/src/code_8006E9C0.h +++ b/src/code_8006E9C0.h @@ -11,7 +11,7 @@ void clear_object_list(void); u8* dma_misc_textures(u8*, u8*, u32, u32); void load_mario_kart_64_logo(void); void init_item_window(s32); -void func_8006EEE8(s32); +void get_minimap_properties(void); void func_8006EF60(void); void func_8006F008(void); void func_8006F824(s32); diff --git a/src/code_80086E70.c b/src/code_80086E70.c index 89f51308a..3b0b0d5a0 100644 --- a/src/code_80086E70.c +++ b/src/code_80086E70.c @@ -977,7 +977,7 @@ void func_80089020(s32 playerId, f32* arg1) { var_f2 = -*arg1; } if (player->effects & 0xC0) { - if (GetCourse() == GetSherbetLand()) { + if (IsSherbetLand()) { if (var_f2 <= 0.5) { var_f0 = 0.025f; } else if (var_f2 <= 2.0) { @@ -998,7 +998,7 @@ void func_80089020(s32 playerId, f32* arg1) { var_f0 = 0.25f; } } - } else if (GetCourse() == GetSherbetLand()) { + } else if (IsSherbetLand()) { if (var_f2 <= 0.5) { var_f0 = 0.025f; } else if (var_f2 <= 2.0) { diff --git a/src/code_800AF9B0.c b/src/code_800AF9B0.c index 732a6e8e9..9876a40cb 100644 --- a/src/code_800AF9B0.c +++ b/src/code_800AF9B0.c @@ -34,15 +34,15 @@ Light D_800E8688 = { { s16 D_8018EDB0; s16 D_8018EDB2; s16 D_8018EDB4; -Vtx* D_8018EDB8; -Vtx* D_8018EDBC; +Vtx D_8018EDB8[480]; +Vtx D_8018EDBC[480]; /*** utils **/ #define SQ(x) ((x) * (x)) void func_800AF9B0(void) { - D_8018EDB8 = (void*) calloc(480, sizeof(Vtx)); - D_8018EDBC = (void*) calloc(480, sizeof(Vtx)); + // D_8018EDB8 = (void*) calloc(480, sizeof(Vtx)); + // D_8018EDBC = (void*) calloc(480, sizeof(Vtx)); } // could be a normal vertex, not a color... diff --git a/src/effects.c b/src/effects.c index 06e476117..da583c0c4 100644 --- a/src/effects.c +++ b/src/effects.c @@ -1698,7 +1698,7 @@ void func_80090178(Player* player, s8 playerId, Vec3f arg2, Vec3f arg3) { f32 sp18[4] = { 10.0f, -10.0f, -575.0f, 575.0f }; f32 sp08[4] = { 575.0f, -575.0f, 10.0f, -10.0f }; - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { test = player->nearestWaypointId; temp_v1 = &D_80164550[gCopyPathIndexByPlayerId[playerId]][test]; arg2[0] = temp_v1->posX; @@ -1710,28 +1710,28 @@ void func_80090178(Player* player, s8 playerId, Vec3f arg2, Vec3f arg3) { arg3[0] = temp_v1->posX; arg3[1] = temp_v1->posY; arg3[2] = temp_v1->posZ; - } else if (GetCourse() == GetBlockFort()) { + } else if (IsBlockFort()) { arg2[0] = spF8[playerId]; arg2[1] = 0.0f; arg2[2] = spE8[playerId]; arg3[0] = spD8[playerId]; arg3[1] = 0.0f; arg3[2] = spC8[playerId]; - } else if (GetCourse() == GetSkyscraper()) { + } else if (IsSkyscraper()) { arg2[0] = spB8[playerId]; arg2[1] = 480.0f; arg2[2] = spA8[playerId]; arg3[0] = sp98[playerId]; arg3[1] = 480.0f; arg3[2] = sp88[playerId]; - } else if (GetCourse() == GetDoubleDeck()) { + } else if (IsDoubleDeck()) { arg2[0] = sp78[playerId]; arg2[1] = 0.0f; arg2[2] = sp68[playerId]; arg3[0] = sp58[playerId]; arg3[1] = 0.0f; arg3[2] = sp48[playerId]; - } else if (GetCourse() == GetBigDonut()) { + } else if (IsBigDonut()) { arg2[0] = sp38[playerId]; arg2[1] = 200.0f; arg2[2] = sp28[playerId]; @@ -1799,14 +1799,14 @@ void func_80090868(Player* player) { player->unk_0CA |= 2; player->unk_0C8 = 0; if ((player->unk_0DE & 1) == 1) { - if ((GetCourse() == GetBowsersCastle()) || (GetCourse() == GetBigDonut())) { + if ((IsBowsersCastle()) || (IsBigDonut())) { player->unk_0CA |= 0x1000; } else { player->unk_0CA |= 0x2000; } - if ((GetCourse() == GetSherbetLand()) || (GetCourse() == GetSkyscraper()) || - (GetCourse() == GetRainbowRoad())) { + if ((IsSherbetLand()) || (IsSkyscraper()) || + (IsRainbowRoad())) { player->unk_0CA &= ~0x3000; } } diff --git a/src/ending/code_80281780.c b/src/ending/code_80281780.c index 1085fb30c..83d75a63d 100644 --- a/src/ending/code_80281780.c +++ b/src/ending/code_80281780.c @@ -93,7 +93,7 @@ void setup_podium_ceremony(void) { Camera* camera = &cameras[0]; gCurrentCourseId = COURSE_ROYAL_RACEWAY; - SetCourseByClass(GetPodiumCeremony()); + SelectPodiumCeremony(); D_800DC5B4 = (u16) 1; gIsMirrorMode = 0; gGotoMenu = 0xFFFF; diff --git a/src/ending/podium_ceremony_actors.c b/src/ending/podium_ceremony_actors.c index 1e3911287..04edd018f 100644 --- a/src/ending/podium_ceremony_actors.c +++ b/src/ending/podium_ceremony_actors.c @@ -18,6 +18,7 @@ #include "code_80281C40.h" #include "math_util.h" #include +#include "port/interpolation/FrameInterpolation.h" #include "src/port/Game.h" #include "engine/Matrix.h" @@ -262,6 +263,9 @@ void render_fireworks(Vec3f arg0, f32 arg1, s32 rgb, s16 alpha) { void firework_update(Firework* actor) { s32 i; Vec3f pos; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("render_fireworks", (uintptr_t) actor); if (actor->unk44 < 30) { for (i = 0; i < 10; i++) { pos[0] = actor->pos[0]; @@ -290,6 +294,8 @@ void firework_update(Firework* actor) { } } actor->unk44 += 1; + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } void unused_80280FA0(UNUSED CeremonyActor* actor) { diff --git a/src/engine/Matrix.cpp b/src/engine/Matrix.cpp index 1f2301258..671489413 100644 --- a/src/engine/Matrix.cpp +++ b/src/engine/Matrix.cpp @@ -1,6 +1,7 @@ #include #include #include "engine/World.h" +#include "src/port/interpolation/FrameInterpolation.h" extern "C" { #include "common_structs.h" @@ -9,13 +10,11 @@ extern "C" { } void AddMatrix(std::vector& stack, Mat4 mtx, s32 flags) { - // Reserve space if needed to avoid reallocation overhead - stack.reserve(1000); - // Push a new matrix to the stack stack.emplace_back(); // Convert to a fixed-point matrix + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mtx, &stack.back()); guMtxF2L(mtx, &stack.back()); // Load the matrix @@ -37,25 +36,26 @@ void AddMatrixFixed(std::vector& stack, s32 flags) { // Used in func_80095BD0 Mtx* SetTextMatrix(f32 arg1, f32 arg2, f32 arg3, f32 arg4) { - Mat4 matrix; - matrix[0][0] = arg3; - matrix[0][1] = 0.0f; - matrix[0][2] = 0.0f; - matrix[0][3] = 0.0f; - matrix[1][0] = 0.0f; - matrix[1][1] = arg4; - matrix[1][2] = 0.0f; - matrix[1][3] = 0.0f; - matrix[2][0] = 0.0f; - matrix[2][1] = 0.0f; - matrix[2][2] = 1.0f; - matrix[2][3] = 0.0f; - matrix[3][0] = arg1; - matrix[3][1] = arg2; - matrix[3][2] = 0.0f; - matrix[3][3] = 1.0f; + Mat4 mf; + mf[0][0] = arg3; + mf[0][1] = 0.0f; + mf[0][2] = 0.0f; + mf[0][3] = 0.0f; + mf[1][0] = 0.0f; + mf[1][1] = arg4; + mf[1][2] = 0.0f; + mf[1][3] = 0.0f; + mf[2][0] = 0.0f; + mf[2][1] = 0.0f; + mf[2][2] = 1.0f; + mf[2][3] = 0.0f; + mf[3][0] = arg1; + mf[3][1] = arg2; + mf[3][2] = 0.0f; + mf[3][3] = 1.0f; Mtx* mtx = GetMatrix(gWorldInstance.Mtx.Effects); - guMtxF2L(matrix, mtx); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mf, mtx); + guMtxF2L(mf, mtx); return mtx; } @@ -137,6 +137,14 @@ extern "C" { AddMatrix(gWorldInstance.Mtx.Hud, mtx, flags); } + void AddPerspMatrix(Mat4 mtx, s32 flags) { + AddMatrix(gWorldInstance.Mtx.Persp, mtx, flags); + } + + void AddLookAtMatrix(Mat4 mtx, s32 flags) { + AddMatrix(gWorldInstance.Mtx.LookAt, mtx, flags); + } + void AddObjectMatrix(Mat4 mtx, s32 flags) { AddMatrix(gWorldInstance.Mtx.Objects, mtx, flags); } diff --git a/src/engine/Smoke.cpp b/src/engine/Smoke.cpp index 5fb0c0c39..6a4566df4 100644 --- a/src/engine/Smoke.cpp +++ b/src/engine/Smoke.cpp @@ -5,6 +5,7 @@ #include "World.h" #include "vehicles/Train.h" #include "vehicles/Boat.h" +#include extern "C" { #include "macros.h" @@ -69,7 +70,6 @@ void TrainSmokeTick() { if (count != 0) { boat->SmokeTimer = 100; } - } } } @@ -80,28 +80,31 @@ void TrainSmokeDraw(s32 cameraId) { for (auto& actor : gWorldInstance.Actors) { if (auto train = dynamic_cast(actor)) { - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007AE0); - load_texture_block_i8_nomirror((uint8_t*)D_0D029458, 32, 32); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007AE0); + load_texture_block_i8_nomirror((uint8_t*) D_0D029458, 32, 32); func_8004B72C(255, 255, 255, 255, 255, 255, 255); D_80183E80[0] = 0; D_80183E80[2] = 0x8000; - if ((train->SomeFlags != 0) && - (is_particle_on_screen(train->Locomotive.position, camera, 0x4000U) != 0)) { + if ((train->SomeFlags != 0) && (is_particle_on_screen(train->Locomotive.position, camera, 0x4000U) != 0)) { for (size_t i = 0; i < 128; i++) { + FrameInterpolation_RecordOpenChild("TrainSmokeParticle", train->SmokeParticles[i]); render_object_train_smoke_particle(train->SmokeParticles[i], cameraId); + FrameInterpolation_RecordCloseChild(); } } } else if (auto boat = dynamic_cast(actor)) { - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007AE0); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007AE0); - load_texture_block_i8_nomirror((uint8_t*)D_0D029458, 32, 32); + load_texture_block_i8_nomirror((uint8_t*) D_0D029458, 32, 32); func_8004B72C(255, 255, 255, 255, 255, 255, 255); D_80183E80[0] = 0; D_80183E80[2] = 0x8000; if ((boat->SomeFlags != 0) && (is_particle_on_screen(boat->Position, camera, 0x4000U) != 0)) { for (size_t i = 0; i < gObjectParticle2_SIZE; i++) { + FrameInterpolation_RecordOpenChild("BoatSmokeParticle", boat->SmokeParticles[i]); render_object_paddle_boat_smoke_particle(boat->SmokeParticles[i], cameraId); + FrameInterpolation_RecordCloseChild(); } } } diff --git a/src/engine/World.cpp b/src/engine/World.cpp index 8e20806ff..88c6717c6 100644 --- a/src/engine/World.cpp +++ b/src/engine/World.cpp @@ -22,12 +22,17 @@ extern "C" { } World::World() {} +World::~World() { + CM_CleanWorld(); +} Course* CurrentCourse; Cup* CurrentCup; -void World::AddCourse(Course* course) { - gWorldInstance.Courses.push_back(course); +Course* World::AddCourse(std::unique_ptr course) { + Course* ptr = course.get(); + gWorldInstance.Courses.push_back(std::move(course)); + return ptr; } void World::AddCup(Cup* cup) { @@ -79,6 +84,10 @@ u32 World::PreviousCup() { return 0; } +void World::SetCupIndex(size_t index) { + CupIndex = index; +} + void World::SetCup(Cup* cup) { if (cup) { CurrentCup = cup; @@ -90,7 +99,7 @@ void World::SetCourse(const char* name) { //! @todo Use content dictionary instead for (size_t i = 0; i < Courses.size(); i++) { if (strcmp(Courses[i]->Props.Name, name) == 0) { - CurrentCourse = Courses[i]; + CurrentCourse = Courses[i].get(); break; } } @@ -103,7 +112,7 @@ void World::NextCourse() { } else { CourseIndex = 0; } - gWorldInstance.CurrentCourse = Courses[CourseIndex]; + gWorldInstance.CurrentCourse = Courses[CourseIndex].get(); } void World::PreviousCourse() { @@ -112,7 +121,7 @@ void World::PreviousCourse() { } else { CourseIndex = Courses.size() - 1; } - gWorldInstance.CurrentCourse = Courses[CourseIndex]; + gWorldInstance.CurrentCourse = Courses[CourseIndex].get(); } AActor* World::AddActor(AActor* actor) { diff --git a/src/engine/World.h b/src/engine/World.h index bb8979090..f32cf00ff 100644 --- a/src/engine/World.h +++ b/src/engine/World.h @@ -46,12 +46,15 @@ class World { std::vector Shadows; std::vector Karts; std::vector Effects; + std::vector Persp; + std::vector LookAt; } Matrix; public: explicit World(); + ~World(); - void AddCourse(Course* course); + Course* AddCourse(std::unique_ptr course); AActor* AddActor(AActor* actor); struct Actor* AddBaseActor(); @@ -80,6 +83,7 @@ public: void AddCup(Cup*); void SetCup(Cup* cup); + void SetCupIndex(size_t index); const char* GetCupName(); u32 GetCupIndex(); u32 NextCup(); @@ -92,6 +96,16 @@ public: // These are only for browsing through the course list void SetCourse(const char*); + template + void SetCourseByType() { + for (const auto& course : Courses) { + if (dynamic_cast(course.get())) { + CurrentCourse = course.get(); + return; + } + } + printf("World::SetCourseByType() No course by the type found"); + } void NextCourse(void); void PreviousCourse(void); @@ -118,7 +132,7 @@ public: std::vector> Crossings; // Holds all available courses - std::vector Courses; + std::vector> Courses; size_t CourseIndex = 0; // For browsing courses. private: diff --git a/src/engine/actors/Finishline.cpp b/src/engine/actors/Finishline.cpp index 0680e60bd..fb408bd14 100644 --- a/src/engine/actors/Finishline.cpp +++ b/src/engine/actors/Finishline.cpp @@ -6,6 +6,8 @@ #include "engine/Actor.h" #include "World.h" #include "assets/common_data.h" +#include "src/port/Game.h" +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include "macros.h" @@ -17,6 +19,8 @@ extern f32 gKartHopInitialVelocityTable[]; extern f32 gKartGravityTable[]; } +size_t AFinishline::_count = 0; + AFinishline::AFinishline(std::optional pos) { Name = "Finishline"; @@ -53,6 +57,8 @@ void AFinishline::Draw(Camera *camera) { return; } + FrameInterpolation_RecordOpenChild("Finishline", _count); + mtxf_pos_rotation_xyz(mtx, Pos, Rot); maxObjectsReached = render_set_position(mtx, 0) == 0; @@ -74,6 +80,8 @@ void AFinishline::Draw(Camera *camera) { } else { gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D001BD8); } + + FrameInterpolation_RecordCloseChild(); } void AFinishline::Collision(Player* player, AActor* actor) {} diff --git a/src/engine/actors/Finishline.h b/src/engine/actors/Finishline.h index 61b561a5e..3c0e84de8 100644 --- a/src/engine/actors/Finishline.h +++ b/src/engine/actors/Finishline.h @@ -27,6 +27,7 @@ public: virtual void Collision(Player* player, AActor* actor) override; virtual bool IsMod() override; + static size_t _count; bool PickedUp = false; uint32_t Timer = 0; diff --git a/src/engine/editor/Editor.cpp b/src/engine/editor/Editor.cpp index 446da7487..23a947a09 100644 --- a/src/engine/editor/Editor.cpp +++ b/src/engine/editor/Editor.cpp @@ -30,6 +30,11 @@ namespace Editor { Editor::Editor() { } + Editor::~Editor() { + ClearObjects(); + ClearMatrixPool(); + } + void Editor::Load() { printf("Editor: Loading Editor...\n"); eObjectPicker.Load(); @@ -58,10 +63,16 @@ namespace Editor { Ship::Coords mousePos = wnd->GetMousePos(); bool isMouseDown = wnd->GetMouseState(Ship::LUS_MOUSE_BTN_LEFT); - eGameObjects.erase( - std::remove_if(eGameObjects.begin(), eGameObjects.end(), - [](const auto& object) { return (*object->DespawnFlag) == object->DespawnValue; }), - eGameObjects.end()); + auto it = std::remove_if(eGameObjects.begin(), eGameObjects.end(), + [](auto& object) { + if (*object->DespawnFlag == object->DespawnValue) { + delete object; // Free the pointed-to memory + return true; // Remove the pointer from the vector + } + return false; + }); + + eGameObjects.erase(it, eGameObjects.end()); if (isMouseDown && !wasMouseDown) { // Mouse just pressed (Pressed state) diff --git a/src/engine/editor/Editor.h b/src/engine/editor/Editor.h index 759c59355..60e578b21 100644 --- a/src/engine/editor/Editor.h +++ b/src/engine/editor/Editor.h @@ -14,6 +14,7 @@ namespace Editor { class Editor { public: Editor(); + ~Editor(); ObjectPicker eObjectPicker; std::vector eGameObjects; diff --git a/src/engine/editor/EditorMath.cpp b/src/engine/editor/EditorMath.cpp index 92d7d2a38..f3833008b 100644 --- a/src/engine/editor/EditorMath.cpp +++ b/src/engine/editor/EditorMath.cpp @@ -31,9 +31,9 @@ bool IsInGameScreen() { // Define viewport boundaries auto gfx_current_game_window_viewport = GetInterpreter()->mGameWindowViewport; - int left = gfx_current_game_window_viewport.width; + int left = gfx_current_game_window_viewport.x; int right = left + OTRGetGameRenderWidth(); - int top = gfx_current_game_window_viewport.height; + int top = gfx_current_game_window_viewport.y; int bottom = top + OTRGetGameRenderHeight(); // Check if the mouse is within the game render area @@ -46,8 +46,8 @@ FVector ScreenRayTrace() { Ship::Coords mouse = wnd->GetMousePos(); auto gfx_current_game_window_viewport = GetInterpreter()->mGameWindowViewport; - mouse.x -= gfx_current_game_window_viewport.width; - mouse.y -= gfx_current_game_window_viewport.height; + mouse.x -= gfx_current_game_window_viewport.x; + mouse.y -= gfx_current_game_window_viewport.y; // Get screen dimensions uint32_t width = OTRGetGameViewportWidth(); uint32_t height = OTRGetGameViewportHeight(); diff --git a/src/engine/objects/Bat.cpp b/src/engine/objects/Bat.cpp index 764476064..e4f3a2086 100644 --- a/src/engine/objects/Bat.cpp +++ b/src/engine/objects/Bat.cpp @@ -1,6 +1,7 @@ #include "Bat.h" #include "World.h" #include "CoreMath.h" +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include "render_objects.h" @@ -22,7 +23,7 @@ OBat::OBat(const FVector& pos, const IRotator& rot) { Name = "Bat"; find_unused_obj_index(&_objectIndex); - init_texture_object(_objectIndex, (uint8_t*)d_course_banshee_boardwalk_bat_tlut, sBoardwalkTexList, 0x20U, + init_texture_object(_objectIndex, (uint8_t*) d_course_banshee_boardwalk_bat_tlut, sBoardwalkTexList, 0x20U, (u16) 0x00000040); gObjectList[_objectIndex].orientation[0] = rot.pitch; gObjectList[_objectIndex].orientation[1] = rot.roll; @@ -101,43 +102,56 @@ void OBat::Tick() { } void OBat::Draw(s32 cameraId) { - s32 var_s2; - s32 objectIndex; - Camera* temp_s7; + s32 i; + s32 objectIndex = _objectIndex; + Camera* cam = &camera1[cameraId]; - objectIndex = _objectIndex; - temp_s7 = &camera1[cameraId]; - OBat::func_80046F60((u8*)gObjectList[objectIndex].activeTLUT, (u8*)gObjectList[objectIndex].activeTexture, 0x00000020, 0x00000040, - 5); + OBat::func_80046F60((u8*) gObjectList[objectIndex].activeTLUT, (u8*) gObjectList[objectIndex].activeTexture, + 0x00000020, 0x00000040, 5); D_80183E80[0] = gObjectList[objectIndex].orientation[0]; D_80183E80[2] = gObjectList[objectIndex].orientation[2]; + if ((D_8018CFB0 != 0) || (D_8018CFC8 != 0)) { - for (var_s2 = 0; var_s2 < 40; var_s2++) { - objectIndex = gObjectParticle2[var_s2]; + for (i = 0; i < 40; i++) { + objectIndex = gObjectParticle2[i]; if (objectIndex == -1) { continue; } if ((gObjectList[objectIndex].state >= 2) && (gMatrixHudCount < 0x2EF)) { + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Bat set 1", (uintptr_t) &gObjectList[objectIndex]); + D_80183E80[1] = - func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], temp_s7->pos); + func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], cam->pos); func_800431B0(gObjectList[objectIndex].pos, D_80183E80, gObjectList[objectIndex].sizeScaling, - (Vtx*)D_0D0062B0); + (Vtx*) D_0D0062B0); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } + if ((D_8018CFE8 != 0) || (D_8018D000 != 0)) { - for (var_s2 = 0; var_s2 < 30; var_s2++) { - objectIndex = gObjectParticle3[var_s2]; + for (i = 0; i < 30; i++) { + + objectIndex = gObjectParticle3[i]; if (objectIndex == -1) { continue; } if ((gObjectList[objectIndex].state >= 2) && (gMatrixHudCount < 0x2EF)) { + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Bat set 2", (uintptr_t) &gObjectList[objectIndex]); + D_80183E80[1] = - func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], temp_s7->pos); + func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], cam->pos); func_800431B0(gObjectList[objectIndex].pos, D_80183E80, gObjectList[objectIndex].sizeScaling, - (Vtx*)D_0D0062B0); + (Vtx*) D_0D0062B0); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -145,7 +159,7 @@ void OBat::Draw(s32 cameraId) { } void OBat::func_80046F60(u8* tlut, u8* arg1, s32 arg2, s32 arg3, s32 arg4) { - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007D78); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007D78); gDPLoadTLUT_pal256(gDisplayListHead++, tlut); rsp_load_texture_mask(arg1, arg2, arg3, arg4); } diff --git a/src/engine/objects/BombKart.cpp b/src/engine/objects/BombKart.cpp index 53b4a4262..8aaaae6cf 100644 --- a/src/engine/objects/BombKart.cpp +++ b/src/engine/objects/BombKart.cpp @@ -118,7 +118,7 @@ void OBombKart::Tick() { return; } - if (((Unk_4A != 1) || (GetCourse() == GetPodiumCeremony()))) { + if (((Unk_4A != 1) || (IsPodiumCeremony()))) { newPos[0] = Pos[0]; newPos[1] = Pos[1]; newPos[2] = Pos[2]; @@ -128,7 +128,7 @@ void OBombKart::Tick() { bounceTimer = BounceTimer; circleTimer = CircleTimer; if ((state != States::DISABLED) && (state != States::EXPLODE)) { - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { if (D_8016347E == 1) { player = gPlayerFour; temp_f0 = newPos[0] - player->pos[0]; @@ -152,7 +152,7 @@ void OBombKart::Tick() { if ((((temp_f0 * temp_f0) + (temp_f2 * temp_f2)) + (temp_f12 * temp_f12)) < 25.0f) { state = States::EXPLODE; circleTimer = 0; - if (GetCourse() == GetFrappeSnowland()) { + if (IsFrappeSnowland()) { player->soundEffects |= 0x01000000; } else { player->soundEffects |= 0x400000; @@ -346,7 +346,7 @@ void OBombKart::Draw(s32 cameraId) { return; } - if (GetCourse() == GetPodiumCeremony()) { + if (IsPodiumCeremony()) { if ((_idx == 0) && (WaypointIndex < 16)) { return; } else { diff --git a/src/engine/objects/Boos.cpp b/src/engine/objects/Boos.cpp index 5bdbd41cf..5f02d7876 100644 --- a/src/engine/objects/Boos.cpp +++ b/src/engine/objects/Boos.cpp @@ -1,6 +1,7 @@ #include "Boos.h" #include "World.h" #include "CoreMath.h" +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include "render_objects.h" @@ -88,9 +89,16 @@ void OBoos::Draw(s32 cameraId) { if (CVarGetInteger("gNoCulling", 0) == 1) { temp_s2 = MIN(temp_s2, 0x15F91U); } + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Boo", (uintptr_t)&gObjectList[objectIndex]); + if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { func_800523B8(objectIndex, cameraId, temp_s2); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } diff --git a/src/engine/objects/GrandPrixBalloons.cpp b/src/engine/objects/GrandPrixBalloons.cpp index 819bde1c6..1315589f2 100644 --- a/src/engine/objects/GrandPrixBalloons.cpp +++ b/src/engine/objects/GrandPrixBalloons.cpp @@ -3,6 +3,7 @@ #include "port/Game.h" #include "assets/other_textures.h" #include "assets/common_data.h" +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include "update_objects.h" @@ -73,7 +74,7 @@ void OGrandPrixBalloons::Draw(s32 cameraId) { return; } - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007E98); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007E98); gDPLoadTLUT_pal256(gDisplayListHead++, gTLUTOnomatopoeia); func_8004B614(0, 0, 0, 0, 0, 0, 0); gDPSetAlphaCompare(gDisplayListHead++, G_AC_THRESHOLD); @@ -84,14 +85,14 @@ void OGrandPrixBalloons::Draw(s32 cameraId) { GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); D_80183E80[0] = 0; D_80183E80[1] = 0x8000; - rsp_load_texture((uint8_t*)gTextureBalloon1, 64, 32); + rsp_load_texture((uint8_t*) gTextureBalloon1, 64, 32); for (var_s1 = 0; var_s1 < _numBalloons; var_s1++) { objectIndex = gObjectParticle3[var_s1]; if ((objectIndex != NULL_OBJECT_ID) && (gObjectList[objectIndex].state >= 2)) { OGrandPrixBalloons::func_80053D74(objectIndex, cameraId, 0); } } - rsp_load_texture((uint8_t*)gTextureBalloon2, 64, 32); + rsp_load_texture((uint8_t*) gTextureBalloon2, 64, 32); for (var_s1 = 0; var_s1 < _numBalloons; var_s1++) { objectIndex = gObjectParticle3[var_s1]; if ((objectIndex != NULL_OBJECT_ID) && (gObjectList[objectIndex].state >= 2)) { @@ -105,15 +106,24 @@ void OGrandPrixBalloons::func_80053D74(s32 objectIndex, UNUSED s32 arg1, s32 ver Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); + size_t i = 0; if (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX) { object = &gObjectList[objectIndex]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Balloon", + TAG_ITEM_ADDR((objectIndex << 32) + i++)); // Not working properly just yet + D_80183E80[2] = (s16) (object->unk_084[6] + 0x8000); rsp_set_matrix_transformation(object->pos, (u16*) D_80183E80, object->sizeScaling); set_color_render((s32) object->unk_084[0], (s32) object->unk_084[1], (s32) object->unk_084[2], (s32) object->unk_084[3], (s32) object->unk_084[4], (s32) object->unk_084[5], (s32) object->primAlpha); - gSPVertex(gDisplayListHead++, (uintptr_t)&vtx[vertexIndex], 4, 0); - gSPDisplayList(gDisplayListHead++, (Gfx*)common_rectangle_display); + gSPVertex(gDisplayListHead++, (uintptr_t) &vtx[vertexIndex], 4, 0); + gSPDisplayList(gDisplayListHead++, (Gfx*) common_rectangle_display); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } @@ -128,7 +138,7 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) { object = &gObjectList[objectIndex]; object->sizeScaling = 0.15f; - if (GetCourse() == GetMarioRaceway()) { + if (IsMarioRaceway()) { sp2C = random_int(0x00C8U); sp28 = random_int(_numBalloons3); sp24 = random_int(0x0096U); @@ -136,7 +146,7 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) { object->origin_pos[0] = (f32) ((((f64) Pos.x + 100.0) - (f64) sp2C) * (f64) xOrientation); object->origin_pos[1] = (f32) (Pos.y + sp28); object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24); - } else if (GetCourse() == GetRoyalRaceway()) { + } else if (IsRoyalRaceway()) { sp2C = random_int(0x0168U); sp28 = random_int(_numBalloons3); sp24 = random_int(0x00B4U); @@ -144,7 +154,7 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) { object->origin_pos[0] = (f32) ((((f64) Pos.x + 180.0) - (f64) sp2C) * (f64) xOrientation); object->origin_pos[1] = (f32) (Pos.y + sp28); object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24); - } else if (GetCourse() == GetLuigiRaceway()) { + } else if (IsLuigiRaceway()) { sp2C = random_int(0x012CU); sp28 = random_int(_numBalloons3); sp24 = random_int(0x0096U); @@ -187,7 +197,10 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) { void OGrandPrixBalloons::func_80074D94(s32 objectIndex) { if (gObjectList[objectIndex].unk_0AE == 1) { - if ((_numBalloons2 <= gObjectList[objectIndex].offset[1]) && + //! @warning this fades out the balloons. Original game uses _numBalloons3 here but they disappear before + //! off-screen. + // So _numBalloons replaces it for now. + if ((_numBalloons <= gObjectList[objectIndex].offset[1]) && (s16_step_down_towards(&gObjectList[objectIndex].primAlpha, 0, 8) != 0)) { func_80086F60(objectIndex); } @@ -209,7 +222,8 @@ void OGrandPrixBalloons::func_80074E28(s32 objectIndex) { case 0: break; case 3: - OGrandPrixBalloons::func_80041480(&gObjectList[objectIndex].unk_084[6], -0x1000, 0x1000, &gObjectList[objectIndex].unk_084[7]); + OGrandPrixBalloons::func_80041480(&gObjectList[objectIndex].unk_084[6], -0x1000, 0x1000, + &gObjectList[objectIndex].unk_084[7]); if (gObjectList[objectIndex].unk_0AE == 0) { func_80072428(objectIndex); } @@ -228,4 +242,4 @@ void OGrandPrixBalloons::func_80041480(s16* arg0, s16 arg1, s16 arg2, s16* arg3) *arg0 = arg1; *arg3 = -*arg3; } -} \ No newline at end of file +} diff --git a/src/engine/objects/Hedgehog.cpp b/src/engine/objects/Hedgehog.cpp index ebc5b30bb..1c2aada9d 100644 --- a/src/engine/objects/Hedgehog.cpp +++ b/src/engine/objects/Hedgehog.cpp @@ -11,6 +11,7 @@ extern "C" { #include "code_80086E70.h" #include "code_80057C60.h" } +#include "port/interpolation/FrameInterpolation.h" size_t OHedgehog::_count = 0; @@ -25,7 +26,7 @@ OHedgehog::OHedgehog(const FVector& pos, const FVector2D& patrolPoint, s16 unk) gObjectList[objectId].pos[0] = gObjectList[objectId].origin_pos[0] = pos.x * xOrientation; gObjectList[objectId].pos[1] = gObjectList[objectId].surfaceHeight = pos.y + 6.0; gObjectList[objectId].pos[2] = gObjectList[objectId].origin_pos[2] = pos.z; - gObjectList[objectId].unk_0D5 = (u8)unk; + gObjectList[objectId].unk_0D5 = (u8) unk; gObjectList[objectId].unk_09C = patrolPoint.x * xOrientation; gObjectList[objectId].unk_09E = patrolPoint.z; @@ -38,10 +39,10 @@ void OHedgehog::Tick() { OHedgehog::func_800833D0(objectIndex, _idx); OHedgehog::func_80083248(objectIndex); OHedgehog::func_80083474(objectIndex); - + // This func clears a bit from all hedgehogs. This results in setting the height of all hedgehogs to zero. // The solution is to only clear the bit from the current instance; `self` or `this` - //func_80072120(indexObjectList2, NUM_HEDGEHOGS); + // func_80072120(indexObjectList2, NUM_HEDGEHOGS); clear_object_flag(objectIndex, 0x00600000); // The fix } @@ -78,7 +79,8 @@ void OHedgehog::func_800555BC(s32 objectIndex, s32 cameraId) { func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos); draw_2d_texture_at(gObjectList[objectIndex].pos, gObjectList[objectIndex].orientation, gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, - (u8*)gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, 64, 64, 64, 32); + (u8*) gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, 64, 64, 64, + 32); } } @@ -92,13 +94,20 @@ void OHedgehog::func_8004A870(s32 objectIndex, f32 arg1) { D_80183E50[0] = object->pos[0]; D_80183E50[1] = object->surfaceHeight + 0.8; D_80183E50[2] = object->pos[2]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("hedgehog", (uintptr_t) &gObjectList[objectIndex]); + set_transform_matrix(mtx, object->unk_01C, D_80183E50, 0U, arg1); // convert_to_fixed_point_matrix(&gGfxPool->mtxHud[gMatrixHudCount], mtx); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxHud[gMatrixHudCount++]), // G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); AddHudMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007B98); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007B98); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } @@ -108,7 +117,8 @@ void OHedgehog::func_8008311C(s32 objectIndex, s32 arg1) { Object* object; Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); - init_texture_object(objectIndex, (u8*)d_course_yoshi_valley_hedgehog_tlut, sHedgehogTexList, 0x40U, (u16) 0x00000040); + init_texture_object(objectIndex, (u8*) d_course_yoshi_valley_hedgehog_tlut, sHedgehogTexList, 0x40U, + (u16) 0x00000040); object = &gObjectList[objectIndex]; object->activeTLUT = d_course_yoshi_valley_hedgehog_tlut; object->activeTexture = d_course_yoshi_valley_hedgehog; diff --git a/src/engine/objects/HotAirBalloon.cpp b/src/engine/objects/HotAirBalloon.cpp index 4e337d98e..f1e367d8d 100644 --- a/src/engine/objects/HotAirBalloon.cpp +++ b/src/engine/objects/HotAirBalloon.cpp @@ -21,7 +21,7 @@ OHotAirBalloon::OHotAirBalloon(const FVector& pos) { D_80165898 = 0; // Spawn balloon on second lap. - if (GetCourse() == GetLuigiRaceway()) { + if (IsLuigiRaceway()) { _visible = (bool*)&D_80165898; } else { // Spawn balloon on race start bool mod = true; diff --git a/src/engine/objects/Lakitu.cpp b/src/engine/objects/Lakitu.cpp index 12ca2d7db..28159b7b3 100644 --- a/src/engine/objects/Lakitu.cpp +++ b/src/engine/objects/Lakitu.cpp @@ -2,6 +2,7 @@ #include #include "Lakitu.h" #include +#include "port/interpolation/FrameInterpolation.h" #include "port/Game.h" @@ -10,6 +11,7 @@ extern "C" { #include "main.h" #include "actors.h" #include "math_util.h" +#include "math_util_2.h" #include "sounds.h" #include "update_objects.h" #include "render_player.h" @@ -21,7 +23,6 @@ extern "C" { #include "code_80057C60.h" #include "defines.h" #include "code_80005FD0.h" -#include "math_util_2.h" #include "collision.h" #include "assets/bowsers_castle_data.h" #include "ceremony_and_credits.h" @@ -95,6 +96,8 @@ void OLakitu::Draw(s32 cameraId) { s32 objectIndex; Object* object; + FrameInterpolation_RecordOpenChild("Lakitu",(uintptr_t) this); + objectIndex = gIndexLakituList[cameraId]; camera = &camera1[cameraId]; if (is_obj_flag_status_active(objectIndex, 0x00000010) != 0) { @@ -126,6 +129,7 @@ void OLakitu::Draw(s32 cameraId) { } } } + FrameInterpolation_RecordCloseChild(); } void OLakitu::func_80079114(s32 objectIndex, s32 playerId, s32 arg2) { @@ -293,7 +297,7 @@ void OLakitu::func_800729EC(s32 objectIndex) { D_8018D2BC = 1; D_8018D2A4 = 1; - if (GetCourse() != GetYoshiValley()) { + if (!IsYoshiValley()) { for (i = 0; i < gPlayerCount; i++) { playerHUD[i].unk_81 = temp_v1; } @@ -362,7 +366,7 @@ void OLakitu::func_800797AC(s32 playerId) { objectIndex = gIndexLakituList[playerId]; player = &gPlayerOne[playerId]; - //if ((GetCourse() == GetSherbetLand()) && (player->unk_0CA & 1)) { + //if ((IsSherbetLand()) && (player->unk_0CA & 1)) { if ((CM_GetProps()->LakituTowType == LakituTowType::ICE) && (player->unk_0CA & 1)) { init_object(objectIndex, 7); player->unk_0CA |= 0x10; diff --git a/src/engine/objects/Mole.cpp b/src/engine/objects/Mole.cpp index 06bd5f56c..f623b1f52 100644 --- a/src/engine/objects/Mole.cpp +++ b/src/engine/objects/Mole.cpp @@ -21,6 +21,7 @@ extern "C" { #include "sounds.h" #include "external.h" } +#include "port/interpolation/FrameInterpolation.h" size_t OMole::_count = 0; @@ -145,7 +146,7 @@ void OMole::func_80081AFC(s32 objectIndex, s32 arg1) { // sp2C = D_8018D1B8; // break; // } - //sp2C[object->type] = 0; + // sp2C[object->type] = 0; } break; case 0: @@ -179,20 +180,20 @@ void OMole::func_8008153C(s32 objectIndex) { } u8* mole = (u8*) LOAD_ASSET_RAW(d_course_moo_moo_farm_mole_dirt); - init_object(loopObjectIndex, 0); - gObjectList[loopObjectIndex].activeTLUT = d_course_moo_moo_farm_mole_dirt; - gObjectList[loopObjectIndex].tlutList = mole; - gObjectList[loopObjectIndex].sizeScaling = 0.15f; - gObjectList[loopObjectIndex].velocity[1] = random_int(0x000AU); - gObjectList[loopObjectIndex].velocity[1] = (gObjectList[loopObjectIndex].velocity[1] * 0.1) + 4.8; - gObjectList[loopObjectIndex].unk_034 = random_int(5U); - gObjectList[loopObjectIndex].unk_034 = (gObjectList[loopObjectIndex].unk_034 * 0.01) + 0.8; - gObjectList[loopObjectIndex].orientation[1] = (0x10000 / sp70) * var_s1; - gObjectList[loopObjectIndex].origin_pos[0] = gObjectList[objectIndex].origin_pos[0]; - gObjectList[loopObjectIndex].origin_pos[1] = gObjectList[objectIndex].origin_pos[1] - 13.0; - gObjectList[loopObjectIndex].origin_pos[2] = gObjectList[objectIndex].origin_pos[2]; - break; - } + init_object(loopObjectIndex, 0); + gObjectList[loopObjectIndex].activeTLUT = d_course_moo_moo_farm_mole_dirt; + gObjectList[loopObjectIndex].tlutList = mole; + gObjectList[loopObjectIndex].sizeScaling = 0.15f; + gObjectList[loopObjectIndex].velocity[1] = random_int(0x000AU); + gObjectList[loopObjectIndex].velocity[1] = (gObjectList[loopObjectIndex].velocity[1] * 0.1) + 4.8; + gObjectList[loopObjectIndex].unk_034 = random_int(5U); + gObjectList[loopObjectIndex].unk_034 = (gObjectList[loopObjectIndex].unk_034 * 0.01) + 0.8; + gObjectList[loopObjectIndex].orientation[1] = (0x10000 / sp70) * var_s1; + gObjectList[loopObjectIndex].origin_pos[0] = gObjectList[objectIndex].origin_pos[0]; + gObjectList[loopObjectIndex].origin_pos[1] = gObjectList[objectIndex].origin_pos[1] - 13.0; + gObjectList[loopObjectIndex].origin_pos[2] = gObjectList[objectIndex].origin_pos[2]; + break; + } } } @@ -243,21 +244,15 @@ void OMole::func_80081D34(s32 objectIndex) { } static const char* frames[] = { - gTextureMole1, - gTextureMole2, - gTextureMole3, - gTextureMole4, - gTextureMole5, - gTextureMole6, - gTextureMole7, - d_course_moo_moo_farm_mole_dirt, + gTextureMole1, gTextureMole2, gTextureMole3, gTextureMole4, + gTextureMole5, gTextureMole6, gTextureMole7, d_course_moo_moo_farm_mole_dirt, }; - void OMole::func_80081848(s32 objectIndex) { - init_texture_object(objectIndex, (u8*)d_course_moo_moo_farm_mole_tlut, (const char**) frames, 0x20U, (u16) 0x00000040); - //gObjectList[objectIndex].activeTexture = (const char*)d_course_moo_moo_farm_mole_frames; - //gObjectList[objectIndex].activeTLUT = (const char*)d_course_moo_moo_farm_mole_tlut; + init_texture_object(objectIndex, (u8*) d_course_moo_moo_farm_mole_tlut, (const char**) frames, 0x20U, + (u16) 0x00000040); + // gObjectList[objectIndex].activeTexture = (const char*)d_course_moo_moo_farm_mole_frames; + // gObjectList[objectIndex].activeTLUT = (const char*)d_course_moo_moo_farm_mole_tlut; gObjectList[objectIndex].sizeScaling = 0.15f; gObjectList[objectIndex].textureListIndex = 0; @@ -270,7 +265,6 @@ void OMole::func_80081848(s32 objectIndex) { object_next_state(objectIndex); } - void OMole::func_80081924(s32 objectIndex) { switch (gObjectList[objectIndex].unk_0AE) { case 1: @@ -307,7 +301,6 @@ void OMole::func_80081924(s32 objectIndex) { } } - void OMole::func_80081A88(s32 objectIndex) { switch (gObjectList[objectIndex].unk_0DD) { /* irregular */ case 0: @@ -330,9 +323,14 @@ void OMole::func_800821AC(s32 objectIndex, s32 arg1) { } } +// Holes void OMole::func_80054E10(s32 objectIndex) { if (gObjectList[objectIndex].state > 0) { if (is_obj_flag_status_active(objectIndex, 0x00800000) != 0) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("func_80054E10", TAG_OBJECT(&gObjectList[objectIndex])); + D_80183E50[0] = gObjectList[objectIndex].pos[0]; D_80183E50[1] = gObjectList[objectIndex].surfaceHeight + 0.8; D_80183E50[2] = gObjectList[objectIndex].pos[2]; @@ -340,6 +338,9 @@ void OMole::func_80054E10(s32 objectIndex) { D_80183E70[1] = gObjectList[objectIndex].velocity[1]; D_80183E70[2] = gObjectList[objectIndex].velocity[2]; func_8004A9B8(gObjectList[objectIndex].sizeScaling); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -348,8 +349,8 @@ void OMole::func_80054E10(s32 objectIndex) { void OMole::func_80054EB8() { s32 someIndex; - //for (someIndex = 0; someIndex < NUM_TOTAL_MOLES; someIndex++) { - func_80054E10(_moleIndex); + // for (someIndex = 0; someIndex < NUM_TOTAL_MOLES; someIndex++) { + func_80054E10(_moleIndex); //} } @@ -360,36 +361,52 @@ void OMole::func_80054D00(s32 objectIndex, s32 cameraId) { if (gObjectList[objectIndex].state >= 3) { func_8008A364(objectIndex, cameraId, 0x2AABU, 0x0000012C); if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("func_80054D00", (uintptr_t)&gObjectList[objectIndex]); + D_80183E80[0] = (s16) gObjectList[objectIndex].orientation[0]; D_80183E80[1] = func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos); D_80183E80[2] = (u16) gObjectList[objectIndex].orientation[2]; func_80048130(gObjectList[objectIndex].pos, (u16*) D_80183E80, gObjectList[objectIndex].sizeScaling, - (u8*) gObjectList[objectIndex].activeTLUT, (u8*)gObjectList[objectIndex].activeTexture, - (Vtx*)LOAD_ASSET_RAW(D_0D0062B0), 0x00000020, 0x00000040, 0x00000020, 0x00000040, 5); + (u8*) gObjectList[objectIndex].activeTLUT, (u8*) gObjectList[objectIndex].activeTexture, + (Vtx*) LOAD_ASSET_RAW(D_0D0062B0), 0x00000020, 0x00000040, 0x00000020, 0x00000040, 5); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } +// Mole rocks void OMole::func_80054F04(s32 cameraId) { Camera* camera = &camera1[cameraId]; - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D0079C8); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D0079C8); load_texture_block_rgba16_mirror((u8*) LOAD_ASSET_RAW(d_course_moo_moo_farm_mole_dirt), 0x00000010, 0x00000010); -if (_idx == 0) { - for (size_t i = 0; i < gObjectParticle2_SIZE; i++) { - s32 objectIndex = gObjectParticle2[i]; - Object* object = &gObjectList[objectIndex]; - if (object->state > 0) { - func_8008A364(objectIndex, cameraId, 0x2AABU, 0x000000C8); - if ((is_obj_flag_status_active(objectIndex, VISIBLE) != 0) && (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX)) { - object->orientation[1] = func_800418AC(object->pos[0], object->pos[2], camera->pos); - rsp_set_matrix_gObjectList(objectIndex); - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D006980); + if (_idx == 0) { + for (size_t i = 0; i < gObjectParticle2_SIZE; i++) { + s32 objectIndex = gObjectParticle2[i]; + Object* object = &gObjectList[objectIndex]; + if (object->state > 0) { + func_8008A364(objectIndex, cameraId, 0x2AABU, 0x000000C8); + if ((is_obj_flag_status_active(objectIndex, VISIBLE) != 0) && + (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX)) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("func_80054F04", TAG_OBJECT(object) | (i << 32)); + + object->orientation[1] = func_800418AC(object->pos[0], object->pos[2], camera->pos); + rsp_set_matrix_gObjectList(objectIndex); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D006980); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); + } } } } -} gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); } diff --git a/src/engine/objects/Snowman.cpp b/src/engine/objects/Snowman.cpp index 12beb9e47..7cbfc691d 100644 --- a/src/engine/objects/Snowman.cpp +++ b/src/engine/objects/Snowman.cpp @@ -11,6 +11,7 @@ extern "C" { #include "code_80086E70.h" #include "code_80057C60.h" } +#include "port/interpolation/FrameInterpolation.h" static const char* sSnowmanHeadList[] = { d_course_frappe_snowland_snowman_head }; @@ -27,7 +28,7 @@ OSnowman::OSnowman(const FVector& pos) { gObjectList[_headIndex].origin_pos[0] = pos.x * xOrientation; gObjectList[_headIndex].origin_pos[1] = pos.y + 5.0 + 3.0; gObjectList[_headIndex].origin_pos[2] = pos.z; - gObjectList[_headIndex].pos[0] = pos.x * xOrientation; + gObjectList[_headIndex].pos[0] = pos.x * xOrientation; gObjectList[_headIndex].pos[1] = pos.y + 5.0 + 3.0; gObjectList[_headIndex].pos[2] = pos.z; @@ -38,7 +39,7 @@ OSnowman::OSnowman(const FVector& pos) { gObjectList[_bodyIndex].origin_pos[2] = pos.z; gObjectList[_bodyIndex].unk_0D5 = 0; // Section Id no longer used. - gObjectList[_bodyIndex].pos[0] = pos.x * xOrientation; + gObjectList[_bodyIndex].pos[0] = pos.x * xOrientation; gObjectList[_bodyIndex].pos[1] = pos.y + 3.0; gObjectList[_bodyIndex].pos[2] = pos.z; @@ -71,14 +72,15 @@ void OSnowman::Tick() { } } - //for (var_s0 = 0; var_s0 < NUM_SNOWMEN; var_s0++) { + // for (var_s0 = 0; var_s0 < NUM_SNOWMEN; var_s0++) { var_s4 = _bodyIndex; var_s3 = _headIndex; OSnowman::func_80083A94(var_s3); // snowman head OSnowman::func_80083C04(var_s4); // snowman body if (is_obj_index_flag_status_inactive(var_s4, 0x00001000) != 0) { object = &gObjectList[var_s4]; - if ((are_players_in_course_section(object->unk_0D5 - 1, object->unk_0D5 + 1) != 0) && (func_80089B50(var_s4) != 0)) { + if ((are_players_in_course_section(object->unk_0D5 - 1, object->unk_0D5 + 1) != 0) && + (func_80089B50(var_s4) != 0)) { set_object_flag(var_s4, 0x00001000); clear_object_flag(var_s4, 0x00000010); func_800726CC(var_s4, 0x0000000A); @@ -93,6 +95,7 @@ void OSnowman::Tick() { } void OSnowman::Draw(s32 cameraId) { + OSnowman::DrawHead(cameraId); OSnowman::DrawBody(cameraId); } @@ -117,23 +120,29 @@ void OSnowman::DrawHead(s32 cameraId) { if (gObjectList[objectIndex].state >= 2) { func_8008A364(objectIndex, cameraId, 0x2AABU, 0x00000258); if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("OSnowman::DrawHead", (uintptr_t) &gObjectList[objectIndex]); + D_80183E80[0] = (s16) gObjectList[objectIndex].orientation[0]; D_80183E80[1] = func_800418AC(gObjectList[objectIndex].pos[0], gObjectList[objectIndex].pos[2], camera->pos); D_80183E80[2] = (u16) gObjectList[objectIndex].orientation[2]; if (is_obj_flag_status_active(objectIndex, 0x00000010) != 0) { draw_2d_texture_at(gObjectList[objectIndex].pos, (u16*) D_80183E80, - gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, - (u8*)gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, - 0x00000040, 0x00000040, 0x00000040, 0x00000020); + gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, + (u8*) gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, + 0x00000040, 0x00000040, 0x00000040, 0x00000020); } objectIndex = _headIndex; D_80183E80[0] = (s16) gObjectList[objectIndex].orientation[0]; D_80183E80[2] = (u16) gObjectList[objectIndex].orientation[2]; - draw_2d_texture_at(gObjectList[objectIndex].pos, (u16*) D_80183E80, - gObjectList[objectIndex].sizeScaling, (u8*) gObjectList[objectIndex].activeTLUT, - (u8*)gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].vertex, 0x00000040, - 0x00000040, 0x00000040, 0x00000020); + draw_2d_texture_at(gObjectList[objectIndex].pos, (u16*) D_80183E80, gObjectList[objectIndex].sizeScaling, + (u8*) gObjectList[objectIndex].activeTLUT, (u8*) gObjectList[objectIndex].activeTexture, + gObjectList[objectIndex].vertex, 0x00000040, 0x00000040, 0x00000040, 0x00000020); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -146,7 +155,8 @@ void OSnowman::DrawBody(s32 cameraId) { Object* object; sp44 = &camera1[cameraId]; - load_texture_and_tlut((u8*)d_course_frappe_snowland_snow_tlut, (u8*)d_course_frappe_snowland_snow, 0x00000020, 0x00000020); + load_texture_and_tlut((u8*) d_course_frappe_snowland_snow_tlut, (u8*) d_course_frappe_snowland_snow, 0x00000020, + 0x00000020); //! @todo quick hack to add the snow particles on hit. Need to separate into its own class if (_idx == 0) { @@ -157,9 +167,16 @@ void OSnowman::DrawBody(s32 cameraId) { if (object->state > 0) { func_8008A364(objectIndex, cameraId, 0x2AABU, 0x000001F4); if (is_obj_flag_status_active(objectIndex, VISIBLE) != 0) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("OSnowman::DrawBody", (uintptr_t) object); + object->orientation[1] = func_800418AC(object->pos[0], object->pos[2], sp44->pos); rsp_set_matrix_gObjectList(objectIndex); - gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D0069E0); + gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D0069E0); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -215,7 +232,8 @@ void OSnowman::func_80083BE4(s32 objectIndex) { void OSnowman::func_80083868(s32 objectIndex) { Object* object; Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(D_0D0061B0); - init_texture_object(objectIndex, (u8*)d_course_frappe_snowland_snowman_tlut, (const char**)sSnowmanHeadList, 0x40U, (u16) 0x00000040); + init_texture_object(objectIndex, (u8*) d_course_frappe_snowland_snowman_tlut, (const char**) sSnowmanHeadList, + 0x40U, (u16) 0x00000040); object = &gObjectList[objectIndex]; object->vertex = vtx; object->sizeScaling = 0.1f; @@ -259,7 +277,8 @@ void OSnowman::func_80083948(s32 objectIndex) { break; } object_calculate_new_pos_offset(objectIndex); - OSnowman::func_80073D0C(objectIndex, &gObjectList[objectIndex].primAlpha, -0x00001000, 0x00001000, 0x00000400, 1, -1); + OSnowman::func_80073D0C(objectIndex, &gObjectList[objectIndex].primAlpha, -0x00001000, 0x00001000, 0x00000400, 1, + -1); gObjectList[objectIndex].orientation[2] = gObjectList[objectIndex].primAlpha + 0x8000; } @@ -285,7 +304,8 @@ static const char* sSnowmanBodyList[] = { d_course_frappe_snowland_snowman_body void OSnowman::func_80083B0C(s32 objectIndex) { Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog); - init_texture_object(objectIndex, (u8*)d_course_frappe_snowland_snowman_tlut, (const char**)sSnowmanBodyList, 0x40U, (u16) 0x00000040); + init_texture_object(objectIndex, (u8*) d_course_frappe_snowland_snowman_tlut, (const char**) sSnowmanBodyList, + 0x40U, (u16) 0x00000040); gObjectList[objectIndex].vertex = vtx; gObjectList[objectIndex].sizeScaling = 0.1f; gObjectList[objectIndex].textureListIndex = 0; @@ -299,16 +319,15 @@ void OSnowman::func_80083B0C(s32 objectIndex) { set_object_flag(objectIndex, 0x04000210); } - void OSnowman::func_80083538(s32 objectIndex, Vec3f arg1, s32 arg2, s32 arg3) { Object* object; init_object(objectIndex, 0); object = &gObjectList[objectIndex]; - object->activeTexture = (const char*)d_course_frappe_snowland_snow; - object->textureList = (const char**)d_course_frappe_snowland_snow; + object->activeTexture = (const char*) d_course_frappe_snowland_snow; + object->textureList = (const char**) d_course_frappe_snowland_snow; object->activeTLUT = d_course_frappe_snowland_snow_tlut; - object->tlutList = (u8*)d_course_frappe_snowland_snow_tlut; + object->tlutList = (u8*) d_course_frappe_snowland_snow_tlut; object->sizeScaling = random_int(0x0064U); object->sizeScaling = (object->sizeScaling * 0.001) + 0.05; object->velocity[1] = random_int(0x0014U); diff --git a/src/engine/objects/Thwomp.cpp b/src/engine/objects/Thwomp.cpp index d3f99a8d9..9cee27c50 100644 --- a/src/engine/objects/Thwomp.cpp +++ b/src/engine/objects/Thwomp.cpp @@ -45,6 +45,7 @@ f32 D_800E594C[][2] = { s16 D_800E597C[] = { 0x0000, 0x0000, 0x4000, 0x8000, 0x8000, 0xc000 }; size_t OThwomp::_count = 0; +size_t OThwomp::_rand = 0; OThwomp::OThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize) { Name = "Thwomp"; @@ -88,6 +89,7 @@ void OThwomp::Tick60fps() { // func_80081210 if (_idx == 0) { D_80165834[0] += 0x100; D_80165834[1] += 0x200; + _rand += 1; } if (gObjectList[_objectIndex].state != 0) { @@ -131,26 +133,26 @@ void OThwomp::Tick60fps() { // func_80081210 } OThwomp::func_8007542C(3); - if (func_80072320(_objectIndex, 0x00000020) == 0) { - return; + if (func_80072320(_objectIndex, 0x00000020)) { + func_800722CC(_objectIndex, 0x00000020); + OThwomp::AddParticles(_objectIndex); } - func_800722CC(_objectIndex, 0x00000020); - OThwomp::AddParticles(_objectIndex); - - for (var_s4 = 0; var_s4 < gObjectParticle2_SIZE; var_s4++) { - objectIndex = gObjectParticle2[var_s4]; - if (objectIndex == DELETED_OBJECT_ID) { - return; - } - if (gObjectList[objectIndex].state == 0) { - return; - } - OThwomp::func_800810F4(objectIndex); - if (gObjectList[objectIndex].state != 0) { - return; + if (_idx == 0) { + for (var_s4 = 0; var_s4 < gObjectParticle2_SIZE; var_s4++) { + objectIndex = gObjectParticle2[var_s4]; + if (objectIndex == DELETED_OBJECT_ID) { + continue; + } + if (gObjectList[objectIndex].state == 0) { + continue; + } + OThwomp::func_800810F4(objectIndex); + if (gObjectList[objectIndex].state != 0) { + continue; + } + delete_object_wrapper(&gObjectParticle2[var_s4]); } - delete_object_wrapper(&gObjectParticle2[var_s4]); } } @@ -361,14 +363,16 @@ void OThwomp::func_8007F8D8() { s32 OThwomp::func_8007F75C(s32 playerId) { s32 someIndex; - s32 temp_s7; + static s32 temp_s7 = 0; // Must be static to sync far travelling thwomp instances s32 var_s6; s32 waypoint; waypoint = gNearestWaypointByPlayerId[playerId]; var_s6 = 0; if ((waypoint >= 0xAA) && (waypoint < 0xB5)) { - temp_s7 = random_int(0x0032U) + 0x32; + if (_idx == 0) { + temp_s7 = random_int(0x0032U) + 0x32; + } if (gObjectList[_objectIndex].unk_0D5 == 3) { var_s6 = 1; OThwomp::func_8007F660(_objectIndex, playerId, temp_s7); @@ -928,9 +932,9 @@ void OThwomp::func_8007FA08(s32 objectIndex) { set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); set_obj_direction_angle(objectIndex, 0U, 0U, 0U); if (gIsMirrorMode != 0) { - set_obj_orientation(objectIndex, 0U, 0xC000U, 0U); + set_obj_orientation(objectIndex, 0U, _faceDirection, 0U); } else { - set_obj_orientation(objectIndex, 0U, 0x4000U, 0U); + set_obj_orientation(objectIndex, 0U, -_faceDirection, 0U); } object->velocity[0] = 0.0f; object->direction_angle[1] = object->orientation[1]; @@ -970,7 +974,7 @@ void OThwomp::func_8007FB48(s32 objectIndex) { gObjectList[objectIndex].velocity[0] = player->unk_094 * xOrientation * 1.25; if (gObjectList[objectIndex].unk_048 >= gObjectList[objectIndex].unk_0B0) { if (gObjectList[objectIndex].unk_0B0 == gObjectList[objectIndex].unk_048) { - if (D_8018D400 & 1) { + if (_rand & 1) { // D_8018D400 & 1 gObjectList[objectIndex].velocity[2] = 1.5f; } else { gObjectList[objectIndex].velocity[2] = -1.5f; @@ -1169,9 +1173,9 @@ void OThwomp::func_800802C0(s32 objectIndex) { object->offset[1] = 10.0f; object->unk_01C[1] = 10.0f; if (gIsMirrorMode != 0) { - set_obj_orientation(objectIndex, 0U, 0x4000U, 0U); + set_obj_orientation(objectIndex, 0U, -_faceDirection, 0U); } else { - set_obj_orientation(objectIndex, 0U, 0xC000U, 0U); + set_obj_orientation(objectIndex, 0U, _faceDirection, 0U); } object->offset[0] = 0.0f; object->offset[2] = 0.0f; @@ -1195,7 +1199,7 @@ void OThwomp::SlidingBehaviour(s32 objectIndex) { // func_800808CC OThwomp::func_8008085C(objectIndex); func_80073514(objectIndex); if (gGamestate != 9) { - if ((D_8018D40C == 0) && (gObjectList[objectIndex].state == 2)) { + if (((_rand & 0x3F) == 0) && (gObjectList[objectIndex].state == 2)) { // D_8018D40C == 0 && func_800C98B8(gObjectList[objectIndex].pos, gObjectList[objectIndex].velocity, SOUND_ARG_LOAD(0x19, 0x03, 0x60, 0x45)); } diff --git a/src/engine/objects/Thwomp.h b/src/engine/objects/Thwomp.h index 22c674bb5..647ef126a 100644 --- a/src/engine/objects/Thwomp.h +++ b/src/engine/objects/Thwomp.h @@ -112,6 +112,7 @@ public: void func_8007E63C(s32 objectIndex); private: static size_t _count; + static size_t _rand; s32 _idx; s16 _faceDirection; //! @todo Write this better. This effects the squish size and the bounding box size. diff --git a/src/engine/objects/TrashBin.cpp b/src/engine/objects/TrashBin.cpp index c94d0352f..57c702275 100644 --- a/src/engine/objects/TrashBin.cpp +++ b/src/engine/objects/TrashBin.cpp @@ -3,6 +3,7 @@ #include "TrashBin.h" #include "World.h" #include "port/Game.h" +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include "main.h" @@ -31,7 +32,7 @@ OTrashBin::OTrashBin(const FVector& pos, const IRotator& rotation, f32 scale, OT init_object(_objectIndex, 0); - if (GetCourse() != GetBansheeBoardwalk()) { + if (!IsBansheeBoardwalk()) { _drawBin = true; } } @@ -62,11 +63,18 @@ void OTrashBin::Draw(s32 cameraId) { Mat4 mtx; Vec3f Pos = { _pos.x + 63, _pos.y + 12, _pos.z + 25 }; Vec3s Rot = { 0, 0x4000, 0 }; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("OTrashBin", (uintptr_t) object); + mtxf_pos_rotation_xyz(mtx, Pos, Rot); //mtxf_scale(mtx, 1.0f); if (render_set_position(mtx, 0) != 0) { gSPDisplayList(gDisplayListHead++, BinMod); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } diff --git a/src/engine/particles/StarEmitter.cpp b/src/engine/particles/StarEmitter.cpp index 242e1a75a..7cb9d9979 100644 --- a/src/engine/particles/StarEmitter.cpp +++ b/src/engine/particles/StarEmitter.cpp @@ -1,6 +1,7 @@ #include "StarEmitter.h" +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include "render_objects.h" @@ -107,9 +108,13 @@ void StarEmitter::Draw(s32 cameraId) { // func_80054BE8 D_80183E80[0] = 0; for (var_s0 = 0; var_s0 < gObjectParticle3_SIZE; var_s0++) { temp_a0 = ObjectIndex[var_s0]; + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Ceremony Stars", (uintptr_t) &ObjectIndex[var_s0]); if ((temp_a0 != -1) && (gObjectList[temp_a0].state >= 2)) { StarEmitter::func_80054AFC(temp_a0, camera->pos); } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } diff --git a/src/enhancements/collision_viewer.c b/src/enhancements/collision_viewer.c index fd7c542e0..f45a9872f 100644 --- a/src/enhancements/collision_viewer.c +++ b/src/enhancements/collision_viewer.c @@ -4,6 +4,8 @@ #include "code_800029B0.h" #include "mk64.h" #include "main.h" +#include +#include #include "collision_viewer.h" #include "math_util.h" diff --git a/src/enhancements/freecam/freecam.cpp b/src/enhancements/freecam/freecam.cpp index 86dfef575..36059c960 100644 --- a/src/enhancements/freecam/freecam.cpp +++ b/src/enhancements/freecam/freecam.cpp @@ -4,6 +4,7 @@ #include "port/Game.h" #include #include +#include "port/interpolation/FrameInterpolation.h" extern "C" { #include @@ -86,6 +87,8 @@ void freecam(Camera* camera, Player* player, s8 index) { freecam_loop(camera, player, index); } else { func_8001E45C(camera, player, index); + // Required if freecam were to use its own camera instead of borrowing the player camera + //func_8001EE98(gPlayerOneCopy, camera, index); } } @@ -104,7 +107,6 @@ void freecam_loop(Camera* camera, Player* player, s8 index) { // Toggle freecam CVarSetInteger("gFreecam", !CVarGetInteger("gFreecam", 0)); } - // Calculate forward direction freecam_calculate_forward_vector_allow_rotation(camera, freeCam.forwardVector); @@ -389,24 +391,33 @@ void freecam_update_controller(void) { // Note that D Pad as stick code has been removed. So if it's needed, it needs to be put back in. } -void freecam_render_setup(void) { +Mtx fPersp; +Mtx fLookAt; +void freecam_render_setup(Camera* camera) { u16 perspNorm; Mat4 matrix; - init_rdp(); - func_802A53A4(); - init_rdp(); - func_80057FC4(0); + + Mat4 persp; + Mat4 lookAt; + gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH); gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK | G_CULL_BOTH | G_CULL_FRONT); - guPerspective(&gGfxPool->mtxPersp[0], &perspNorm, gCameraZoom[0], gScreenAspect, + + // Perspective (camera movement) + FrameInterpolation_RecordOpenChild("freecam_persp", FrameInterpolation_GetCameraEpoch()); + guPerspective(&fPersp, &perspNorm, gCameraZoom[0], gScreenAspect, CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f); gSPPerspNormalize(gDisplayListHead++, perspNorm); - gSPMatrix(gDisplayListHead++, (&gGfxPool->mtxPersp[0]), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); - guLookAt(&gGfxPool->mtxLookAt[0], camera1->pos[0], camera1->pos[1], camera1->pos[2], camera1->lookAt[0], - camera1->lookAt[1], camera1->lookAt[2], camera1->up[0], camera1->up[1], camera1->up[2]); - gSPMatrix(gDisplayListHead++, (&gGfxPool->mtxLookAt[0]), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); - mtxf_identity(matrix); - gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK); - render_set_position(matrix, 0); - init_rdp(); + gSPMatrix(gDisplayListHead++, (&fPersp), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + FrameInterpolation_RecordCloseChild(); + + // LookAt (camera rotation) + FrameInterpolation_RecordOpenChild("freecam_lookAt", FrameInterpolation_GetCameraEpoch()); + guLookAt(&fLookAt, camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0], + camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]); + gSPMatrix(gDisplayListHead++, (&fLookAt), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + FrameInterpolation_RecordCloseChild(); + + gDPPipeSync(gDisplayListHead++); + } diff --git a/src/enhancements/freecam/freecam.h b/src/enhancements/freecam/freecam.h index db55866ed..86c42b0c9 100644 --- a/src/enhancements/freecam/freecam.h +++ b/src/enhancements/freecam/freecam.h @@ -13,7 +13,7 @@ void on_freecam(void); void off_freecam(void); void freecam_loop(Camera*, Player*, s8); void freecam_update_controller(void); -void freecam_render_setup(void); +void freecam_render_setup(Camera* camera); void freecam_mouse_manager(Camera*, Vec3f); void freecam_keyboard_manager(Camera*, Vec3f); diff --git a/src/enhancements/freecam/freecam_engine.c b/src/enhancements/freecam/freecam_engine.c index 350ab192b..56585e2f0 100644 --- a/src/enhancements/freecam/freecam_engine.c +++ b/src/enhancements/freecam/freecam_engine.c @@ -11,10 +11,10 @@ #include #include "freecam_engine.h" -FreeCam freeCam; - #include +FreeCam freeCam; + f32 gDampValue = 0.99f; f32 gRotDampValue = 0.96f; diff --git a/src/gbiMacro.c b/src/gbiMacro.c index 5fa0ab171..7e33bbc8f 100644 --- a/src/gbiMacro.c +++ b/src/gbiMacro.c @@ -3,6 +3,7 @@ #include "main.h" #include #include +#include "src/port/interpolation/matrix.h" #include "math_util.h" diff --git a/src/main.c b/src/main.c index 7b7e05cda..7b28393d1 100644 --- a/src/main.c +++ b/src/main.c @@ -44,6 +44,7 @@ #include "buffers/gfx_output_buffer.h" #include #include "enhancements/freecam/freecam.h" +#include "port/interpolation/FrameInterpolation.h" #include "engine/wasm.h" #include "port/Game.h" #include "engine/Matrix.h" @@ -636,6 +637,12 @@ void game_init_clear_framebuffer(void) { clear_framebuffer(0); } +//! @deprecated +// This function was made to tick the game logic at native 60 fps. +// However, many game objects are not in that special tick loop and run at native 30fps. +// Thus adding `if (gTickVisuals) { // stuff here }` would prevent double speed and allow ticking visuals once every 30 fps. +// This does not however, create extra interpolated frames. Whereas a possible solution, it is not the best solution. +// This function should be cleaned up and removed, since frame interpolation now exists. void calculate_updaterate(void) { static u32 prevtime = 0; static u32 remainder = 0; @@ -647,7 +654,7 @@ void calculate_updaterate(void) { s32 total; // Get target FPS from configuration variable - s32 targetFPS = CVarGetInteger("gInterpolationFPS", 30); + s32 targetFPS = 30; if (targetFPS < 60) { targetFPS = 30; @@ -686,7 +693,7 @@ void calculate_updaterate(void) { if (targetFPS < 60) { gTickLogic = 2; } else { - gTickLogic = 1; // Perform logic update + gTickLogic = 2; // Perform logic update } } @@ -694,8 +701,9 @@ void calculate_updaterate(void) { visualsAccumulator += total; // Increment for each frame if (visualsAccumulator >= visualsUpdateInterval) { // Check if it's time to update visuals visualsAccumulator -= visualsUpdateInterval; - gTickVisuals = 1; // Perform visual update + // gTickVisuals <-- Goes here to use the native 60fps system } + gTickVisuals = 1; // Perform visual update } void display_debug_info(void) { @@ -758,9 +766,20 @@ void process_game_tick(void) { func_800382DC(); } - // Editor requires this for camera movement. - func_8001EE98(gPlayerOneCopy, camera1, 0); + // tick camera + // This looks like it should be in the switch. + // But it needs to be here for player 1 to work in all modes. + func_8001EE98(gPlayerOneCopy, camera1, 0); + // Required if freecam was to have a new camera + //if (CVarGetInteger("gFreecam", 0) == true) { + // freecam(gFreecamCamera, gPlayerOneCopy, 0); + //} else { + + //func_8001EE98(gPlayerOneCopy, camera1, 0); + //} + + // Editor requires this so the camera keeps moving while the game is paused. if (gIsEditorPaused == true) { return; } @@ -930,6 +949,8 @@ void race_logic_loop(void) { */ void game_state_handler(void) { + FrameInterpolation_StartRecord(); + #if DVDL if ((gControllerOne->button & L_TRIG) && (gControllerOne->button & R_TRIG) && (gControllerOne->button & Z_TRIG) && (gControllerOne->button & A_BUTTON)) { @@ -966,6 +987,7 @@ void game_state_handler(void) { credits_loop(); break; } + FrameInterpolation_StopRecord(); } void interrupt_gfx_sptask(void) { diff --git a/src/math_util_2.c b/src/math_util_2.c index 444f3e4c6..b113c6a5d 100644 --- a/src/math_util_2.c +++ b/src/math_util_2.c @@ -15,9 +15,13 @@ #include "port/Engine.h" #include "engine/Matrix.h" +#include "port/interpolation/FrameInterpolation.h" #pragma intrinsic(sqrtf) +Mat4 sInterpolationMatrixStack[0x1000]; +Mat4* gInterpolationMatrix = &sInterpolationMatrixStack[0]; + UNUSED void operator_or(s32* arg0, s32 arg1) { *arg0 = (s32) (*arg0 | arg1); } @@ -600,7 +604,6 @@ void func_80041D24(void) { } void guOrtho(Mtx*, f32, f32, f32, f32, f32, f32, f32); /* extern */ -extern s8 D_801658FE; void func_80041D34(void) { guOrtho(&D_80183D60, 0.0f, 320.0f, 240.0f, 0.0f, -1.0f, 1.0f, 1.0f); @@ -687,13 +690,13 @@ UNUSED void func_800421FC(s32 x, s32 y, f32 scale) { void func_80042330(s32 x, s32 y, u16 angle, f32 scale) { Mat4 matrix; - //printf("panel %d %d %d\n", x, (s32)OTRGetDimensionFromLeftEdge(x), (s32)OTRGetDimensionFromLeftEdge(0)); + // printf("panel %d %d %d\n", x, (s32)OTRGetDimensionFromLeftEdge(x), (s32)OTRGetDimensionFromLeftEdge(0)); if (gHUDModes != 2) { if (x < (SCREEN_WIDTH / 2)) { - x = (s32)OTRGetDimensionFromLeftEdge(x); + x = (s32) OTRGetDimensionFromLeftEdge(x); } else { - x = (s32)OTRGetDimensionFromRightEdge(x); + x = (s32) OTRGetDimensionFromRightEdge(x); } } @@ -707,7 +710,7 @@ void func_80042330(s32 x, s32 y, u16 angle, f32 scale) { void func_80042330_unchanged(s32 x, s32 y, u16 angle, f32 scale) { Mat4 matrix; - //printf("panel %d %d %d\n", x, (s32)OTRGetDimensionFromLeftEdge(x), (s32)OTRGetDimensionFromLeftEdge(0)); + // printf("panel %d %d %d\n", x, (s32)OTRGetDimensionFromLeftEdge(x), (s32)OTRGetDimensionFromLeftEdge(0)); mtxf_translation_x_y_rotate_z_scale_x_y(matrix, x, y, angle, scale); // convert_to_fixed_point_matrix(&gGfxPool->mtxHud[gMatrixHudCount], matrix); @@ -720,13 +723,13 @@ void func_80042330_unchanged(s32 x, s32 y, u16 angle, f32 scale) { // Allows a different way of lining up the portraits at the end of race sequence void func_80042330_portrait(s32 x, s32 y, u16 angle, f32 scale, s16 lapCount) { Mat4 matrix; - //printf("panel %d %d %d\n", x, (s32)OTRGetDimensionFromLeftEdge(x), (s32)OTRGetDimensionFromLeftEdge(0)); + // printf("panel %d %d %d\n", x, (s32)OTRGetDimensionFromLeftEdge(x), (s32)OTRGetDimensionFromLeftEdge(0)); if ((gHUDModes != 2) && (D_801657E2 == 0) || (CVarGetInteger("gImprovements", 0) == true)) { if (x < (SCREEN_WIDTH / 2)) { - x = (s32)OTRGetDimensionFromLeftEdge(x); + x = (s32) OTRGetDimensionFromLeftEdge(x); } else { - x = (s32)OTRGetDimensionFromRightEdge(x); + x = (s32) OTRGetDimensionFromRightEdge(x); } } @@ -742,9 +745,9 @@ void func_80042330_wide(s32 x, s32 y, u16 angle, f32 scale) { Mat4 matrix; if (x < (SCREEN_WIDTH / 2)) { - x = (s32)OTRGetDimensionFromLeftEdge(x); + x = (s32) OTRGetDimensionFromLeftEdge(x); } else { - x = (s32)OTRGetDimensionFromRightEdge(x); + x = (s32) OTRGetDimensionFromRightEdge(x); } mtxf_translation_x_y_rotate_z_scale_x_y(matrix, x, y, angle, scale); @@ -805,27 +808,28 @@ UNUSED void func_8004252C(Mat4 arg0, u16 arg1, u16 arg2) { arg0[2][2] = sp28 * cos_theta_y; } -void mtxf_set_matrix_transformation(Mat4 transformMatrix, Vec3f translationVector, Vec3su rotationVector, - f32 scalingFactor) { - f32 sinX = sins(rotationVector[0]); - f32 cosX = coss(rotationVector[0]); - f32 sinY = sins(rotationVector[1]); - f32 cosY = coss(rotationVector[1]); - f32 sinZ = sins(rotationVector[2]); - f32 cosZ = coss(rotationVector[2]); - - transformMatrix[0][0] = ((cosY * cosZ) + (sinX * sinY * sinZ)) * scalingFactor; - transformMatrix[1][0] = ((-cosY * sinZ) + (sinX * sinY * cosZ)) * scalingFactor; - transformMatrix[2][0] = (cosX * sinY) * scalingFactor; - transformMatrix[3][0] = translationVector[0]; - transformMatrix[0][1] = cosX * sinZ * scalingFactor; - transformMatrix[1][1] = cosX * cosZ * scalingFactor; - transformMatrix[2][1] = -sinX * scalingFactor; - transformMatrix[3][1] = translationVector[1]; - transformMatrix[0][2] = ((-sinY * cosZ) + (sinX * cosY * sinZ)) * scalingFactor; - transformMatrix[1][2] = ((sinY * sinZ) + (sinX * cosY * cosZ)) * scalingFactor; - transformMatrix[2][2] = cosX * cosY * scalingFactor; - transformMatrix[3][2] = translationVector[2]; +void mtxf_set_matrix_transformation(Mat4 transformMatrix, Vec3f location, Vec3su rotation, f32 scale) { + + FrameInterpolation_RecordSetMatrixTransformation(transformMatrix, location, rotation, scale); + f32 sinX = sins(rotation[0]); + f32 cosX = coss(rotation[0]); + f32 sinY = sins(rotation[1]); + f32 cosY = coss(rotation[1]); + f32 sinZ = sins(rotation[2]); + f32 cosZ = coss(rotation[2]); + + transformMatrix[0][0] = ((cosY * cosZ) + (sinX * sinY * sinZ)) * scale; + transformMatrix[1][0] = ((-cosY * sinZ) + (sinX * sinY * cosZ)) * scale; + transformMatrix[2][0] = (cosX * sinY) * scale; + transformMatrix[3][0] = location[0]; + transformMatrix[0][1] = cosX * sinZ * scale; + transformMatrix[1][1] = cosX * cosZ * scale; + transformMatrix[2][1] = -sinX * scale; + transformMatrix[3][1] = location[1]; + transformMatrix[0][2] = ((-sinY * cosZ) + (sinX * cosY * sinZ)) * scale; + transformMatrix[1][2] = ((sinY * sinZ) + (sinX * cosY * cosZ)) * scale; + transformMatrix[2][2] = cosX * cosY * scale; + transformMatrix[3][2] = location[2]; transformMatrix[0][3] = 0.0f; transformMatrix[1][3] = 0.0f; transformMatrix[2][3] = 0.0f; @@ -859,7 +863,13 @@ void mtxf_set_matrix_scale_transl(Mat4 transformMatrix, Vec3f vec1, Vec3f vec2, * @param arg1 **/ -void mtxf_set_matrix_gObjectList(s32 objectIndex, Mat4 transformMatrix) { +struct ObjectInterpData2 { + s32 objectIndex; + f32 x, y; +}; +struct ObjectInterpData2 prevObject2[OBJECT_LIST_SIZE] = { 0 }; + +s32 mtxf_set_matrix_gObjectList(s32 objectIndex, Mat4 transformMatrix) { f32 sinX; Object* object = &gObjectList[objectIndex]; f32 sinY; @@ -891,6 +901,26 @@ void mtxf_set_matrix_gObjectList(s32 objectIndex, Mat4 transformMatrix) { transformMatrix[1][3] = 0.0f; transformMatrix[2][3] = 0.0f; transformMatrix[3][3] = 1.0f; + + // Search all recorded objects for the one we're drawing + for (int i = 0; i < OBJECT_LIST_SIZE; i++) { + if (objectIndex == prevObject2[i].objectIndex) { + // Coincidence! + // Skip drawing the object this frame if it warped to the other side of the screen + if ((fabsf(object->pos[0] - prevObject2[i].x) > 20) || (fabsf(object->pos[1] - prevObject2[i].y) > 20)) { + prevObject2[objectIndex].x = object->pos[0]; + prevObject2[objectIndex].y = object->pos[1]; + prevObject2[objectIndex].objectIndex = objectIndex; + // printf("IDX: %d X: %f Y: %f Z: %f\n", objectIndex, object->pos[0], object->pos[1], object->pos[2]); + return 1; + } + } + } + prevObject2[objectIndex].x = object->pos[0]; + prevObject2[objectIndex].y = object->pos[1]; + prevObject2[objectIndex].objectIndex = objectIndex; + + return 0; } UNUSED void mtxf_mult_first_column(Mat4 arg0, f32 arg1) { @@ -917,6 +947,7 @@ void set_transform_matrix(Mat4 dest, Vec3f orientationVector, Vec3f positionVect Vec3f sp38; Vec3f sp2C; + FrameInterpolation_RecordSetTransformMatrix(dest, orientationVector, positionVector, rotationAngle, scaleFactor); vec3f_set_xyz(sp44, sins(rotationAngle), 0.0f, coss(rotationAngle)); vec3f_normalize(orientationVector); vec3f_cross_product(sp38, orientationVector, sp44); @@ -1059,7 +1090,9 @@ void rsp_set_matrix_transl_rot_scale(Vec3f arg0, Vec3f arg1, f32 arg2) { void rsp_set_matrix_gObjectList(s32 transformIndex) { Mat4 matrix; - mtxf_set_matrix_gObjectList(transformIndex, matrix); + if (mtxf_set_matrix_gObjectList(transformIndex, matrix)) { + return; + } // convert_to_fixed_point_matrix(&gGfxPool->mtxHud[gMatrixHudCount], matrix); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxHud[gMatrixHudCount++]), diff --git a/src/math_util_2.h b/src/math_util_2.h index 75ad8e247..52b436301 100644 --- a/src/math_util_2.h +++ b/src/math_util_2.h @@ -5,6 +5,8 @@ #include #include "camera.h" +extern Mat4* gInterpolationMatrix; + /* Function Prototypes */ // Unused functions @@ -74,15 +76,13 @@ void func_80042330_portrait(s32, s32, u16, f32, s16); void func_80042330_wide(s32, s32, u16, f32); void mtxf_set_matrix_transformation(Mat4, Vec3f, Vec3su, f32); void mtxf_set_matrix_scale_transl(Mat4, Vec3f, Vec3f, f32); -void mtxf_set_matrix_gObjectList(s32, Mat4); -void set_transform_matrix(Mat4, Vec3f, Vec3f, u16, f32); +s32 mtxf_set_matrix_gObjectList(s32, Mat4); +void set_transform_matrix(Mat4 dest, Vec3f orientationVector, Vec3f positionVector, u16 rotationAngle, + f32 scaleFactor); void vec3f_rotate_x_y(Vec3f, Vec3f, Vec3s); void rsp_set_matrix_transformation(Vec3f, Vec3su, f32); void rsp_set_matrix_transformation_inverted_x_y_orientation(Vec3f, Vec3su, f32); void rsp_set_matrix_transl_rot_scale(Vec3f, Vec3f, f32); void rsp_set_matrix_gObjectList(s32); -/* This is where I'd put my static data, if I had any */ -extern s8 D_801658FE; - #endif // MATH_UTIL_2_H diff --git a/src/menu_items.c b/src/menu_items.c index 713250882..d65e4b2a4 100644 --- a/src/menu_items.c +++ b/src/menu_items.c @@ -2528,12 +2528,15 @@ void func_80095574(void) { } else { debug_print_str2(0x000000AA, 0x00000064, "off"); } - if ((gCurrentCourseId >= (NUM_COURSES - 1)) || (gCurrentCourseId < 0)) { - gCurrentCourseId = 0; - } + + // This reset is not necessary. It wraps around automatically. + // if ((GetCourseIndex() >= (NUM_COURSES - 1)) || (GetCourseIndex() < 0)) { + // gCurrentCourseId = 0; + // } print_str_num(0x00000050, 0x0000006E, "map_number", GetCourseIndex()); - // This isn't functionally equivallent, but who cares. - if (gCurrentCourseId < COURSE_TOADS_TURNPIKE) { + + // Bump the text over by 1 character width when the track id becomes two digits (10, 11, 12 etc.) + if (GetCourseIndex() < 10) { var_v0 = 0; } else { var_v0 = 8; @@ -4889,7 +4892,7 @@ void func_8009CE64(s32 arg0) { gCCSelection = (s32) 1; switch (gNextDemoId) { /* switch 4 */ case 0: /* switch 4 */ - SetCourseByClass(GetMarioRaceway()); + SelectMarioRaceway(); CM_SetCup(GetFlowerCup()); SetCupCursorPosition(COURSE_FOUR); gCurrentCourseId = 0; @@ -4900,7 +4903,7 @@ void func_8009CE64(s32 arg0) { gModeSelection = 0; break; case 1: /* switch 4 */ - SetCourseByClass(GetLuigiRaceway()); + SelectLuigiRaceway(); CM_SetCup(GetMushroomCup()); SetCupCursorPosition(COURSE_ONE); gCurrentCourseId = (s16) 1; @@ -4912,7 +4915,7 @@ void func_8009CE64(s32 arg0) { gModeSelection = 2; break; case 2: /* switch 4 */ - SetCourseByClass(GetKalimariDesert()); + SelectKalimariDesert(); CM_SetCup(GetMushroomCup()); SetCupCursorPosition(COURSE_FOUR); gCurrentCourseId = COURSE_KALIMARI_DESERT; @@ -4923,7 +4926,7 @@ void func_8009CE64(s32 arg0) { gModeSelection = 0; break; case 3: /* switch 4 */ - SetCourseByClass(GetWarioStadium()); + SelectWarioStadium(); CM_SetCup(GetStarCup()); SetCupCursorPosition(COURSE_ONE); gCurrentCourseId = 0x000E; @@ -4936,7 +4939,7 @@ void func_8009CE64(s32 arg0) { gModeSelection = (s32) 2; break; case 4: /* switch 4 */ - SetCourseByClass(GetBowsersCastle()); + SelectBowsersCastle(); CM_SetCup(GetStarCup()); SetCupCursorPosition(COURSE_FOUR); gCurrentCourseId = 2; @@ -4947,7 +4950,7 @@ void func_8009CE64(s32 arg0) { gModeSelection = 0; break; case 5: /* switch 4 */ - SetCourseByClass(GetSherbetLand()); + SelectSherbetLand(); CM_SetCup(GetFlowerCup()); SetCupCursorPosition(COURSE_TWO); gCurrentCourseId = 0x000C; @@ -5034,8 +5037,8 @@ void func_8009CE64(s32 arg0) { } } - if (GetCourse() == GetBlockFort() || GetCourse() == GetSkyscraper() || GetCourse() == GetDoubleDeck() || - GetCourse() == GetBigDonut()) { + if (IsBlockFort() || IsSkyscraper() || IsDoubleDeck() || + IsBigDonut()) { gModeSelection = BATTLE; if (gPlayerCountSelection1 == 1) { @@ -8230,7 +8233,9 @@ void func_800A6034(MenuItem* arg0) { set_text_color(TEXT_BLUE_GREEN_RED_CYCLE_2); print_text1_center_mode_2(arg0->column + 0x41, arg0->row + 0xA0, text, 0, 0.85f, 1.0f); text = CM_GetProps()->Name; - set_text_color((s32) gCurrentCourseId % 4); + //! @warning this used to be gCurrentCourseId % 4 + // Hopefully this is equivallent. + set_text_color((s32) GetCourseIndex() % 4); print_text1_center_mode_2(arg0->column + 0x41, arg0->row + 0xC3, text, 0, 0.65f, 0.85f); } } diff --git a/src/menus.c b/src/menus.c index d921ac740..ce9f0a643 100644 --- a/src/menus.c +++ b/src/menus.c @@ -2005,6 +2005,7 @@ void load_menu_states(s32 menuSelection) { CM_SetCup(GetBattleCup()); // gCupSelection = BATTLE_CUP; D_800DC540 = 4; + CM_SetCupIndex(BATTLE_CUP); gSubMenuSelection = SUB_MENU_MAP_SELECT_BATTLE_COURSE; } else { if (GetCup() == GetBattleCup()) { diff --git a/src/os/guLookAtF.c b/src/os/guLookAtF.c index 1e391a37c..4980c76e4 100644 --- a/src/os/guLookAtF.c +++ b/src/os/guLookAtF.c @@ -11,6 +11,7 @@ **************************************************************************/ #include "libultra_internal.h" +#include "port/interpolation/FrameInterpolation.h" void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp, float yUp, float zUp) { @@ -75,5 +76,6 @@ void guLookAt(Mtx* m, float xEye, float yEye, float zEye, float xAt, float yAt, guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mf, m); guMtxF2L(mf, m); } diff --git a/src/os/guOrthoF.c b/src/os/guOrthoF.c index f38376b72..91bef4db6 100644 --- a/src/os/guOrthoF.c +++ b/src/os/guOrthoF.c @@ -1,4 +1,5 @@ #include "libultra_internal.h" +#include "port/interpolation/FrameInterpolation.h" void guOrthoF(float m[4][4], float left, float right, float bottom, float top, float near, float far, float scale) { int row; @@ -19,7 +20,8 @@ void guOrthoF(float m[4][4], float left, float right, float bottom, float top, f } void guOrtho(Mtx* m, float left, float right, float bottom, float top, float near, float far, float scale) { - float sp28[4][4]; - guOrthoF(sp28, left, right, bottom, top, near, far, scale); - guMtxF2L(sp28, m); + float mf[4][4]; + guOrthoF(mf, left, right, bottom, top, near, far, scale); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m); + guMtxF2L(mf, m); } diff --git a/src/os/guPerspectiveF.c b/src/os/guPerspectiveF.c index 062d42751..7d682b8f9 100644 --- a/src/os/guPerspectiveF.c +++ b/src/os/guPerspectiveF.c @@ -1,4 +1,5 @@ #include "libultra_internal.h" +#include "port/interpolation/FrameInterpolation.h" void guPerspectiveF(float mf[4][4], u16* perspNorm, float fovy, float aspect, float near, float far, float scale) { float yscale; @@ -36,5 +37,6 @@ void guPerspectiveF(float mf[4][4], u16* perspNorm, float fovy, float aspect, fl void guPerspective(Mtx* m, u16* perspNorm, float fovy, float aspect, float near, float far, float scale) { float mat[4][4]; guPerspectiveF(mat, perspNorm, fovy, aspect, near, far, scale); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mat, m); guMtxF2L(mat, m); } diff --git a/src/os/guRotateF.c b/src/os/guRotateF.c index aaebf6cfe..b1e23787c 100644 --- a/src/os/guRotateF.c +++ b/src/os/guRotateF.c @@ -1,4 +1,5 @@ #include "libultra_internal.h" +#include "port/interpolation/FrameInterpolation.h" void guRotateF(float m[4][4], float a, float x, float y, float z) { float sin_a; @@ -38,5 +39,6 @@ void guRotateF(float m[4][4], float a, float x, float y, float z) { void guRotate(Mtx* m, float a, float x, float y, float z) { float mf[4][4]; guRotateF(mf, a, x, y, z); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m); guMtxF2L(mf, m); } diff --git a/src/os/guScaleF.c b/src/os/guScaleF.c index 51ee2ac8f..e6a7ef50f 100644 --- a/src/os/guScaleF.c +++ b/src/os/guScaleF.c @@ -1,4 +1,5 @@ #include "libultra_internal.h" +#include "port/interpolation/FrameInterpolation.h" void guScaleF(float mf[4][4], float x, float y, float z) { guMtxIdentF(mf); @@ -11,5 +12,6 @@ void guScaleF(float mf[4][4], float x, float y, float z) { void guScale(Mtx* m, float x, float y, float z) { float mf[4][4]; guScaleF(mf, x, y, z); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m); guMtxF2L(mf, m); } diff --git a/src/os/guTranslateF.c b/src/os/guTranslateF.c index d54af9165..ef4df09da 100644 --- a/src/os/guTranslateF.c +++ b/src/os/guTranslateF.c @@ -1,4 +1,5 @@ #include "libultra_internal.h" +#include "port/interpolation/FrameInterpolation.h" void guTranslateF(float m[4][4], float x, float y, float z) { guMtxIdentF(m); @@ -10,5 +11,6 @@ void guTranslateF(float m[4][4], float x, float y, float z) { void guTranslate(Mtx* m, float x, float y, float z) { float mf[4][4]; guTranslateF(mf, x, y, z); + FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m); guMtxF2L(mf, m); } diff --git a/src/player_controller.c b/src/player_controller.c index df4b794bb..46038dbda 100644 --- a/src/player_controller.c +++ b/src/player_controller.c @@ -1711,7 +1711,7 @@ void func_8002C11C(Player* player) { } void func_8002C17C(Player* player, s8 playerId) { - if (GetCourse() == GetYoshiValley()) { + if (IsYoshiValley()) { if ((player->collision.surfaceDistance[2] >= 600.0f) && (D_80165330[playerId] == 0)) { D_80165330[playerId] = 1; gCopyNearestWaypointByPlayerId[playerId] = gNearestWaypointByPlayerId[playerId]; @@ -1724,7 +1724,7 @@ void func_8002C17C(Player* player, s8 playerId) { D_80165330[playerId] = 0; } } - } else if (GetCourse() == GetFrappeSnowland()) { + } else if (IsFrappeSnowland()) { if ((player->surfaceType == SNOW_OFFROAD) && (D_80165330[playerId] == 0)) { D_80165330[playerId] = 1; gCopyNearestWaypointByPlayerId[playerId] = gNearestWaypointByPlayerId[playerId]; @@ -1734,7 +1734,7 @@ void func_8002C17C(Player* player, s8 playerId) { gCopyNearestWaypointByPlayerId[playerId] = gNearestWaypointByPlayerId[playerId]; gCopyPathIndexByPlayerId[playerId] = gPathIndexByPlayerId[playerId]; } - } else if (GetCourse() == GetRoyalRaceway()) { + } else if (IsRoyalRaceway()) { if (((player->effects & BOOST_RAMP_ASPHALT_EFFECT) != 0) && (D_80165330[playerId] == 0)) { D_80165330[playerId] = 1; gCopyNearestWaypointByPlayerId[playerId] = gNearestWaypointByPlayerId[playerId]; @@ -1744,7 +1744,7 @@ void func_8002C17C(Player* player, s8 playerId) { gCopyNearestWaypointByPlayerId[playerId] = gNearestWaypointByPlayerId[playerId]; gCopyPathIndexByPlayerId[playerId] = gPathIndexByPlayerId[playerId]; } - } else if (GetCourse() == GetRainbowRoad()) { + } else if (IsRainbowRoad()) { if ((player->collision.surfaceDistance[2] >= 600.0f) && (D_80165330[playerId] == 0)) { D_80165330[playerId] = 1; gCopyNearestWaypointByPlayerId[playerId] = gNearestWaypointByPlayerId[playerId]; @@ -1778,9 +1778,9 @@ void func_8002C4F8(Player* player, s8 arg1) { if ((player->unk_0DE & 4) != 4) { player->unk_0DE |= 8; player->unk_0DE |= 4; - if ((GetCourse() != GetKoopaTroopaBeach()) && (GetCourse() != GetSkyscraper()) && - (GetCourse() != GetRainbowRoad()) && ((player->type & PLAYER_HUMAN) == PLAYER_HUMAN)) { - if ((GetCourse() == GetBowsersCastle()) || (GetCourse() == GetBigDonut())) { + if ((!IsKoopaTroopaBeach()) && (!IsSkyscraper()) && + (!IsRainbowRoad()) && ((player->type & PLAYER_HUMAN) == PLAYER_HUMAN)) { + if ((IsBowsersCastle()) || (IsBigDonut())) { func_800C9060((u8) arg1, 0x1900801CU); } else { func_800C9060((u8) arg1, 0x19008008U); @@ -1788,8 +1788,8 @@ void func_8002C4F8(Player* player, s8 arg1) { } } } - if ((GetCourse() == GetKoopaTroopaBeach()) || (GetCourse() == GetSkyscraper()) || - (GetCourse() == GetRainbowRoad())) { + if ((IsKoopaTroopaBeach()) || (IsSkyscraper()) || + (IsRainbowRoad())) { player->unk_0DE &= ~0x000C; } if ((player->boundingBoxSize < (D_801652A0[arg1] - player->pos[1])) && @@ -2254,7 +2254,7 @@ void func_8002D268(Player* player, UNUSED Camera* camera, s8 screenId, s8 player player->unk_DB4.unkC = 1.5f; if (((player->type & PLAYER_HUMAN) == PLAYER_HUMAN) && ((player->type & PLAYER_INVISIBLE_OR_BOMB) != PLAYER_INVISIBLE_OR_BOMB)) { - if (((player->unk_0C2 < 0xB) && (player->unk_0C2 >= 4)) && (GetCourse() == GetBowsersCastle())) { + if (((player->unk_0C2 < 0xB) && (player->unk_0C2 >= 4)) && (IsBowsersCastle())) { func_800CADD0((u8) playerId, player->unk_0C2 / 14.0f); } else { func_800CADD0((u8) playerId, player->unk_0C2 / 25.0f); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 788af51ab..2d1ca7ab6 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -24,9 +24,10 @@ #include "window/gui/resource/FontFactory.h" #include "SpaghettiGui.h" +#include "port/interpolation/FrameInterpolation.h" #include #include -//#include +// #include #include #include @@ -51,9 +52,9 @@ float gInterpolationStep = 0.0f; Fast::Interpreter* GetInterpreter() { return static_pointer_cast(Ship::Context::GetInstance()->GetWindow()) - ->GetInterpreterWeak() - .lock() - .get(); + ->GetInterpreterWeak() + .lock() + .get(); } GameEngine* GameEngine::Instance; @@ -62,7 +63,7 @@ GameEngine::GameEngine() { const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory("mk64.o2r"); const std::string assets_path = Ship::Context::LocateFileAcrossAppDirs("spaghetti.o2r"); - + std::vector archiveFiles; #ifdef __SWITCH__ @@ -70,7 +71,6 @@ GameEngine::GameEngine() { Ship::Switch::Init(Ship::PostInitPhase); #endif - #ifdef _WIN32 AllocConsole(); #endif @@ -79,7 +79,7 @@ GameEngine::GameEngine() { archiveFiles.push_back(main_path); } else { if (ShowYesNoBox("No O2R Files", "No O2R files found. Generate one now?") == IDYES) { - if(!GenAssetFile()){ + if (!GenAssetFile()) { ShowMessage("Error", "An error occured, no O2R file was generated.\n\nExiting..."); exit(1); } else { @@ -106,11 +106,11 @@ GameEngine::GameEngine() { } } - this->context = - Ship::Context::CreateUninitializedInstance("Spaghetti Kart", "spaghettify", "spaghettify.cfg.json"); + this->context = Ship::Context::CreateUninitializedInstance("Spaghetti Kart", "spaghettify", "spaghettify.cfg.json"); - this->context->InitConfiguration(); // without this line InitConsoleVariables fails at Config::Reload() - this->context->InitConsoleVariables(); // without this line the controldeck constructor failes in ShipDeviceIndexMappingManager::UpdateControllerNamesFromConfig() + this->context->InitConfiguration(); // without this line InitConsoleVariables fails at Config::Reload() + this->context->InitConsoleVariables(); // without this line the controldeck constructor failes in + // ShipDeviceIndexMappingManager::UpdateControllerNamesFromConfig() auto controlDeck = std::make_shared(); @@ -120,8 +120,8 @@ GameEngine::GameEngine() { auto gui = std::make_shared(std::vector>({})); auto wnd = std::make_shared(gui); - //auto wnd = std::make_shared(std::vector>({})); - //auto wnd = std::dynamic_pointer_cast(Ship::Context::GetInstance()->GetWindow()); + // auto wnd = std::make_shared(std::vector>({})); + // auto wnd = std::dynamic_pointer_cast(Ship::Context::GetInstance()->GetWindow()); this->context->Init(archiveFiles, {}, 3, { 26800, 512, 1100 }, wnd, controlDeck); @@ -158,8 +158,9 @@ GameEngine::GameEngine() { loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_XML, "Vertex", static_cast(Fast::ResourceType::Vertex), 0); - loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, - "DisplayList", static_cast(Fast::ResourceType::DisplayList), 0); + loader->RegisterResourceFactory(std::make_shared(), + RESOURCE_FORMAT_BINARY, "DisplayList", + static_cast(Fast::ResourceType::DisplayList), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_XML, "DisplayList", static_cast(Fast::ResourceType::DisplayList), 0); @@ -178,24 +179,21 @@ GameEngine::GameEngine() { loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "TrackSections", static_cast(MK64::ResourceType::TrackSection), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_XML, "TrackSections", - static_cast(MK64::ResourceType::TrackSection), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_XML, + "TrackSections", static_cast(MK64::ResourceType::TrackSection), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "Waypoints", static_cast(MK64::ResourceType::Waypoints), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_XML, "Paths", - static_cast(MK64::ResourceType::Waypoints), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_XML, + "Paths", static_cast(MK64::ResourceType::Waypoints), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "SpawnData", static_cast(MK64::ResourceType::SpawnData), 0); loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, "UnkSpawnData", static_cast(MK64::ResourceType::UnkSpawnData), 0); - loader->RegisterResourceFactory(std::make_shared(), - RESOURCE_FORMAT_BINARY, "Minimap", - static_cast(MK64::ResourceType::Minimap), 0); + loader->RegisterResourceFactory(std::make_shared(), RESOURCE_FORMAT_BINARY, + "Minimap", static_cast(MK64::ResourceType::Minimap), 0); fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf"); fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf"); @@ -216,15 +214,38 @@ bool GameEngine::GenAssetFile() { auto game = extractor->ValidateChecksum(); if (!game.has_value()) { - ShowMessage("Unsupported ROM", "The provided ROM is not supported.\n\nCheck the readme for a list of supported versions."); + ShowMessage("Unsupported ROM", + "The provided ROM is not supported.\n\nCheck the readme for a list of supported versions."); exit(1); } - ShowMessage(("Found " + game.value()).c_str(), "The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION); + ShowMessage(("Found " + game.value()).c_str(), + "The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION); return extractor->GenerateOTR(); } +uint32_t GameEngine::GetInterpolationFPS() { + if (CVarGetInteger("gMatchRefreshRate", 0)) { + return Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + + } else if (CVarGetInteger("gVsyncEnabled", 1) || + !Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) { + return std::min(Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(), + CVarGetInteger("gInterpolationFPS", 30)); + } + + return CVarGetInteger("gInterpolationFPS", 30); +} + +uint32_t GameEngine::GetInterpolationFrameCount() { + return ceil((float) GetInterpolationFPS() / (60.0f / 2 /*gVIsPerFrame*/)); +} + +extern "C" uint32_t GameEngine_GetInterpolationFrameCount() { + return GameEngine::GetInterpolationFrameCount(); +} + void GameEngine::ShowMessage(const char* title, const char* message, SDL_MessageBoxFlags type) { #if defined(__SWITCH__) SPDLOG_ERROR(message); @@ -275,6 +296,9 @@ void GameEngine::Destroy() { #ifdef __SWITCH__ Ship::Switch::Exit(); #endif + GameUI::Destroy(); + delete GameEngine::Instance; + GameEngine::Instance = nullptr; } bool ShouldClearTextureCacheAtEndOfFrame = false; @@ -301,16 +325,24 @@ void GameEngine::StartFrame() const { // Instance->context->GetWindow()->MainLoop(run_one_game_iter); // } -void GameEngine::RunCommands(Gfx* Commands) { +void GameEngine::RunCommands(Gfx* Commands, const std::vector>& mtx_replacements) { auto wnd = std::dynamic_pointer_cast(Ship::Context::GetInstance()->GetWindow()); - if (nullptr == wnd) { + if (wnd == nullptr) { return; } + auto interpreter = wnd->GetInterpreterWeak().lock().get(); + + // Process window events for resize, mouse, keyboard events wnd->HandleEvents(); - wnd->DrawAndRunGraphicsCommands(Commands, {}); + interpreter->mInterpolationIndex = 0; + + for (const auto& m : mtx_replacements) { + wnd->DrawAndRunGraphicsCommands(Commands, m); + interpreter->mInterpolationIndex++; + } bool curAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0); if (prevAltAssets != curAltAssets) { @@ -321,12 +353,49 @@ void GameEngine::RunCommands(Gfx* Commands) { } void GameEngine::ProcessGfxCommands(Gfx* commands) { + std::vector> mtx_replacements; + int target_fps = GameEngine::Instance->GetInterpolationFPS(); + if (CVarGetInteger("gModifyInterpolationTargetFPS", 0)) { + target_fps = CVarGetInteger("gInterpolationTargetFPS", 60); + } + static int last_fps; + static int last_update_rate; + static int time; + int fps = target_fps; + int original_fps = 60 / 2 /*gVIsPerFrame*/; + + if (target_fps == 30 || original_fps > target_fps) { + fps = original_fps; + } + + if (last_fps != fps || last_update_rate != 2 /*gVIsPerFrame*/) { + time = 0; + } + + // time_base = fps * original_fps (one second) + int next_original_frame = fps; + + while (time + original_fps <= next_original_frame) { + time += original_fps; + if (time != next_original_frame) { + mtx_replacements.push_back(FrameInterpolation_Interpolate((float) time / next_original_frame)); + } else { + mtx_replacements.emplace_back(); + } + } + // printf("mtxf size: %d\n", mtx_replacements.size()); + + time -= fps; + auto wnd = std::dynamic_pointer_cast(Ship::Context::GetInstance()->GetWindow()); if (wnd != nullptr) { - wnd->SetTargetFps(CVarGetInteger("gInterpolationFPS", 30)); + wnd->SetTargetFps(GetInterpolationFPS()); wnd->SetMaximumFrameLatency(1); } - RunCommands(commands); + RunCommands(commands, mtx_replacements); + + last_fps = fps; + last_update_rate = 2; } // Audio @@ -444,7 +513,9 @@ ImFont* GameEngine::CreateFontWithSize(float size, std::string fontPath) { initData->Path = fontPath; std::shared_ptr fontData = std::static_pointer_cast( Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData)); - font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size); + char* fontDataPtr = (char*) malloc(fontData->DataSize); + memcpy(fontDataPtr, fontData->Data, fontData->DataSize); + font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontDataPtr, fontData->DataSize, size); } // FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly float iconFontSize = size * 2.0f / 3.0f; @@ -635,14 +706,14 @@ extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) { /** * Centers an item in a given area. - * + * * Adds the number of extended screen pixels to the location to center. * This allows stretching the game window really wide, and the item will stay in-place. - * + * * This is not for centering in the direct center of the screen. - * + * * How to use: - * + * * s32 center = OTRCalculateCenterOfAreaFromRightEdge((SCREEN_WIDTH / 4) + (SCREEN_WIDTH / 2)); * x = center - (texWidth / 2) * x2 = center + (texWidth / 2) diff --git a/src/port/Engine.h b/src/port/Engine.h index bd6cf1ce0..569009b00 100644 --- a/src/port/Engine.h +++ b/src/port/Engine.h @@ -59,8 +59,10 @@ class GameEngine { static void EndAudioFrame(); static void AudioExit(); + static uint32_t GetInterpolationFPS(); + static uint32_t GetInterpolationFrameCount(); void StartFrame() const; - static void RunCommands(Gfx* Commands); + static void RunCommands(Gfx* Commands, const std::vector>& mtx_replacements); void ProcessFrame(void (*run_one_game_iter)()) const; static void Destroy(); static void ProcessGfxCommands(Gfx* commands); diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 2c0ec3a0a..4cea9c5e2 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -69,29 +69,7 @@ extern "C" void Timer_Update(); // Create the world instance World gWorldInstance; -MarioRaceway* gMarioRaceway; -ChocoMountain* gChocoMountain; -BowsersCastle* gBowsersCastle; -BansheeBoardwalk* gBansheeBoardwalk; -YoshiValley* gYoshiValley; -FrappeSnowland* gFrappeSnowland; -KoopaTroopaBeach* gKoopaTroopaBeach; -RoyalRaceway* gRoyalRaceway; -LuigiRaceway* gLuigiRaceway; -MooMooFarm* gMooMooFarm; -ToadsTurnpike* gToadsTurnpike; -KalimariDesert* gKalimariDesert; -SherbetLand* gSherbetLand; -RainbowRoad* gRainbowRoad; -WarioStadium* gWarioStadium; -BlockFort* gBlockFort; -Skyscraper* gSkyscraper; -DoubleDeck* gDoubleDeck; -DKJungle* gDkJungle; -BigDonut* gBigDonut; -PodiumCeremony* gPodiumCeremony; -Harbour* gHarbour; -TestCourse* gTestCourse; +std::unique_ptr gPodiumCeremony; Cup* gMushroomCup; Cup* gFlowerCup; @@ -108,65 +86,52 @@ Editor::Editor gEditor; s32 gTrophyIndex = NULL; void CustomEngineInit() { - - gMarioRaceway = new MarioRaceway(); - gChocoMountain = new ChocoMountain(); - gBowsersCastle = new BowsersCastle(); - gBansheeBoardwalk = new BansheeBoardwalk(); - gYoshiValley = new YoshiValley(); - gFrappeSnowland = new FrappeSnowland(); - gKoopaTroopaBeach = new KoopaTroopaBeach(); - gRoyalRaceway = new RoyalRaceway(); - gLuigiRaceway = new LuigiRaceway(); - gMooMooFarm = new MooMooFarm(); - gToadsTurnpike = new ToadsTurnpike(); - gKalimariDesert = new KalimariDesert(); - gSherbetLand = new SherbetLand(); - gRainbowRoad = new RainbowRoad(); - gWarioStadium = new WarioStadium(); - gBlockFort = new BlockFort(); - gSkyscraper = new Skyscraper(); - gDoubleDeck = new DoubleDeck(); - gDkJungle = new DKJungle(); - gBigDonut = new BigDonut(); - gPodiumCeremony = new PodiumCeremony(); - gHarbour = new Harbour(); - gTestCourse = new TestCourse(); - /* Add all courses to the global course list */ - gWorldInstance.AddCourse(gMarioRaceway); - gWorldInstance.AddCourse(gChocoMountain); - gWorldInstance.AddCourse(gBowsersCastle); - gWorldInstance.AddCourse(gBansheeBoardwalk); - gWorldInstance.AddCourse(gYoshiValley); - gWorldInstance.AddCourse(gFrappeSnowland); - gWorldInstance.AddCourse(gKoopaTroopaBeach); - gWorldInstance.AddCourse(gRoyalRaceway); - gWorldInstance.AddCourse(gLuigiRaceway); - gWorldInstance.AddCourse(gMooMooFarm); - gWorldInstance.AddCourse(gToadsTurnpike); - gWorldInstance.AddCourse(gKalimariDesert); - gWorldInstance.AddCourse(gSherbetLand); - gWorldInstance.AddCourse(gRainbowRoad); - gWorldInstance.AddCourse(gWarioStadium); - gWorldInstance.AddCourse(gBlockFort); - gWorldInstance.AddCourse(gSkyscraper); - gWorldInstance.AddCourse(gDoubleDeck); - gWorldInstance.AddCourse(gDkJungle); - gWorldInstance.AddCourse(gBigDonut); - gWorldInstance.AddCourse(gHarbour); - gWorldInstance.AddCourse(gTestCourse); - - gMushroomCup = new Cup("mk:mushroom_cup", "mushroom cup", - std::vector{ gLuigiRaceway, gMooMooFarm, gKoopaTroopaBeach, gKalimariDesert }); - gFlowerCup = new Cup("mk:flower_cup", "flower cup", - std::vector{ gToadsTurnpike, gFrappeSnowland, gChocoMountain, gMarioRaceway }); - gStarCup = new Cup("mk:star_cup", "star cup", - std::vector{ gWarioStadium, gSherbetLand, gRoyalRaceway, gBowsersCastle }); - gSpecialCup = new Cup("mk:special_cup", "special cup", - std::vector{ gDkJungle, gYoshiValley, gBansheeBoardwalk, gRainbowRoad }); - gBattleCup = - new Cup("mk:battle_cup", "battle", std::vector{ gBigDonut, gBlockFort, gDoubleDeck, gSkyscraper }); + Course* mario = gWorldInstance.AddCourse(std::make_unique()); + Course* choco = gWorldInstance.AddCourse(std::make_unique()); + Course* bowser = gWorldInstance.AddCourse(std::make_unique()); + Course* banshee = gWorldInstance.AddCourse(std::make_unique()); + Course* yoshi = gWorldInstance.AddCourse(std::make_unique()); + Course* frappe = gWorldInstance.AddCourse(std::make_unique()); + Course* koopa = gWorldInstance.AddCourse(std::make_unique()); + Course* royal = gWorldInstance.AddCourse(std::make_unique()); + Course* luigi = gWorldInstance.AddCourse(std::make_unique()); + Course* mooMoo = gWorldInstance.AddCourse(std::make_unique()); + Course* toads = gWorldInstance.AddCourse(std::make_unique()); + Course* kalimari = gWorldInstance.AddCourse(std::make_unique()); + Course* sherbet = gWorldInstance.AddCourse(std::make_unique()); + Course* rainbow = gWorldInstance.AddCourse(std::make_unique()); + Course* wario = gWorldInstance.AddCourse(std::make_unique()); + Course* block = gWorldInstance.AddCourse(std::make_unique()); + Course* skyscraper = gWorldInstance.AddCourse(std::make_unique()); + Course* doubleDeck = gWorldInstance.AddCourse(std::make_unique()); + Course* dkJungle = gWorldInstance.AddCourse(std::make_unique()); + Course* bigDonut = gWorldInstance.AddCourse(std::make_unique()); + Course* harbour = gWorldInstance.AddCourse(std::make_unique()); + Course* testCourse = gWorldInstance.AddCourse(std::make_unique()); + + gPodiumCeremony = std::make_unique(); + + // Construct cups with vectors of Course* (non-owning references) + gMushroomCup = new Cup("mk:mushroom_cup", "Mushroom Cup", { + luigi, mooMoo, koopa, kalimari + }); + + gFlowerCup = new Cup("mk:flower_cup", "Flower Cup", { + toads, frappe, choco, mario + }); + + gStarCup = new Cup("mk:star_cup", "Star Cup", { + wario, sherbet, royal, bowser + }); + + gSpecialCup = new Cup("mk:special_cup", "Special Cup", { + dkJungle, yoshi, banshee, rainbow + }); + + gBattleCup = new Cup("mk:battle_cup", "Battle Cup", { + bigDonut, block, doubleDeck, skyscraper + }); /* Instantiate Cups */ gWorldInstance.AddCup(gMushroomCup); @@ -176,7 +141,7 @@ void CustomEngineInit() { gWorldInstance.AddCup(gBattleCup); /* Set default course; mario raceway */ - gWorldInstance.CurrentCourse = gMarioRaceway; + SelectMarioRaceway(); gWorldInstance.CurrentCup = gMushroomCup; gWorldInstance.CurrentCup->CursorPosition = 3; gWorldInstance.CupIndex = 0; @@ -198,6 +163,14 @@ void CustomEngineInit() { // gModelLoader.Load(); } +void CustomEngineDestroy() { + delete gMushroomCup; + delete gFlowerCup; + delete gStarCup; + delete gSpecialCup; + delete gBattleCup; +} + extern "C" { void HM_InitIntro() { @@ -244,6 +217,10 @@ u32 GetCupIndex(void) { return gWorldInstance.GetCupIndex(); } +void CM_SetCupIndex(size_t index) { + gWorldInstance.SetCupIndex(index); +} + const char* GetCupName(void) { return gWorldInstance.CurrentCup->Name; } @@ -275,7 +252,7 @@ void SetCourseById(s32 course) { return; } gWorldInstance.CourseIndex = course; - gWorldInstance.CurrentCourse = gWorldInstance.Courses[gWorldInstance.CourseIndex]; + gWorldInstance.CurrentCourse = gWorldInstance.Courses[gWorldInstance.CourseIndex].get(); } void CM_VehicleCollision(s32 playerId, Player* player) { @@ -394,10 +371,11 @@ void CM_BeginPlay() { if (course) { // Do not spawn finishline in credits or battle mode. And if bSpawnFinishline. - if ((gGamestate != CREDITS_SEQUENCE) && (gGamestate != BATTLE) && (course->bSpawnFinishline)) { - gWorldInstance.AddActor(new AFinishline(course->FinishlineSpawnPoint)); + if ((gGamestate != CREDITS_SEQUENCE) && (gModeSelection != BATTLE)) { + if (course->bSpawnFinishline) { + gWorldInstance.AddActor(new AFinishline(course->FinishlineSpawnPoint)); + } } - gEditor.AddLight("Sun", nullptr, D_800DC610[1].l->l.dir); course->BeginPlay(); @@ -723,89 +701,51 @@ f32 CM_GetWaterLevel(Vec3f pos, Collision* collision) { return gWorldInstance.CurrentCourse->GetWaterLevel(fPos, collision); } -void* GetMarioRaceway(void) { - return gMarioRaceway; -} - -void* GetLuigiRaceway(void) { - return gLuigiRaceway; -} - -void* GetChocoMountain(void) { - return gChocoMountain; -} - -void* GetBowsersCastle(void) { - return gBowsersCastle; -} - -void* GetBansheeBoardwalk(void) { - return gBansheeBoardwalk; -} - -void* GetYoshiValley(void) { - return gYoshiValley; -} - -void* GetFrappeSnowland(void) { - return gFrappeSnowland; -} - -void* GetKoopaTroopaBeach(void) { - return gKoopaTroopaBeach; -} - -void* GetRoyalRaceway(void) { - return gRoyalRaceway; -} - -void* GetMooMooFarm(void) { - return gMooMooFarm; -} - -void* GetToadsTurnpike(void) { - return gToadsTurnpike; -} - -void* GetKalimariDesert(void) { - return gKalimariDesert; -} - -void* GetSherbetLand(void) { - return gSherbetLand; -} - -void* GetRainbowRoad(void) { - return gRainbowRoad; -} - -void* GetWarioStadium(void) { - return gWarioStadium; -} - -void* GetBlockFort(void) { - return gBlockFort; -} - -void* GetSkyscraper(void) { - return gSkyscraper; -} - -void* GetDoubleDeck(void) { - return gDoubleDeck; -} - -void* GetDkJungle(void) { - return gDkJungle; -} - -void* GetBigDonut(void) { - return gBigDonut; -} - -void* GetPodiumCeremony(void) { - return gPodiumCeremony; -} +// clang-format off +bool IsMarioRaceway() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsLuigiRaceway() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsChocoMountain() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsBowsersCastle() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsBansheeBoardwalk() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsYoshiValley() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsFrappeSnowland() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsKoopaTroopaBeach() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsRoyalRaceway() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsMooMooFarm() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsToadsTurnpike() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsKalimariDesert() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsSherbetLand() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsRainbowRoad() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsWarioStadium() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsBlockFort() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsSkyscraper() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsDoubleDeck() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsDkJungle() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsBigDonut() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } +bool IsPodiumCeremony() { return dynamic_cast(gWorldInstance.CurrentCourse) != nullptr; } + +void SelectMarioRaceway() { gWorldInstance.SetCourseByType(); } +void SelectLuigiRaceway() { gWorldInstance.SetCourseByType(); } +void SelectChocoMountain() { gWorldInstance.SetCourseByType(); } +void SelectBowsersCastle() { gWorldInstance.SetCourseByType(); } +void SelectBansheeBoardwalk() { gWorldInstance.SetCourseByType(); } +void SelectYoshiValley() { gWorldInstance.SetCourseByType(); } +void SelectFrappeSnowland() { gWorldInstance.SetCourseByType(); } +void SelectKoopaTroopaBeach() { gWorldInstance.SetCourseByType(); } +void SelectRoyalRaceway() { gWorldInstance.SetCourseByType(); } +void SelectMooMooFarm() { gWorldInstance.SetCourseByType(); } +void SelectToadsTurnpike() { gWorldInstance.SetCourseByType(); } +void SelectKalimariDesert() { gWorldInstance.SetCourseByType(); } +void SelectSherbetLand() { gWorldInstance.SetCourseByType(); } +void SelectRainbowRoad() { gWorldInstance.SetCourseByType(); } +void SelectWarioStadium() { gWorldInstance.SetCourseByType(); } +void SelectBlockFort() { gWorldInstance.SetCourseByType(); } +void SelectSkyscraper() { gWorldInstance.SetCourseByType(); } +void SelectDoubleDeck() { gWorldInstance.SetCourseByType(); } +void SelectDkJungle() { gWorldInstance.SetCourseByType(); } +void SelectBigDonut() { gWorldInstance.SetCourseByType(); } +void SelectPodiumCeremony() { gWorldInstance.CurrentCourse = gPodiumCeremony.get(); } +// clang-format on void* GetMushroomCup(void) { return gMushroomCup; @@ -868,6 +808,7 @@ extern "C" while (WindowIsRunning()) { push_frame(); } + CustomEngineDestroy(); // GameEngine::Instance->ProcessFrame(push_frame); GameEngine::Instance->Destroy(); return 0; diff --git a/src/port/Game.h b/src/port/Game.h index 2102cb7ea..14cc0edf6 100644 --- a/src/port/Game.h +++ b/src/port/Game.h @@ -51,6 +51,8 @@ void PreviousCourse(); void CM_SetCup(void*); +void CM_SetCupIndex(size_t index); + void CM_LoadTextures(); void CM_RenderCourse(struct UnkStruct_800DC5EC* arg0); @@ -155,47 +157,49 @@ void CM_CleanWorld(void); f32 CM_GetWaterLevel(Vec3f pos, Collision* collision); -void* GetMarioRaceway(void); - -void* GetLuigiRaceway(void); - -void* GetChocoMountain(void); - -void* GetBowsersCastle(void); - -void* GetBansheeBoardwalk(void); - -void* GetYoshiValley(void); - -void* GetFrappeSnowland(void); - -void* GetKoopaTroopaBeach(void); - -void* GetRoyalRaceway(void); - -void* GetMooMooFarm(void); - -void* GetToadsTurnpike(void); - -void* GetKalimariDesert(void); - -void* GetSherbetLand(void); - -void* GetRainbowRoad(void); - -void* GetWarioStadium(void); - -void* GetBlockFort(void); - -void* GetSkyscraper(void); - -void* GetDoubleDeck(void); - -void* GetDkJungle(void); - -void* GetBigDonut(void); - -void* GetPodiumCeremony(void); +bool IsMarioRaceway(); +bool IsLuigiRaceway(); +bool IsChocoMountain(); +bool IsBowsersCastle(); +bool IsBansheeBoardwalk(); +bool IsYoshiValley(); +bool IsFrappeSnowland(); +bool IsKoopaTroopaBeach(); +bool IsRoyalRaceway(); +bool IsMooMooFarm(); +bool IsToadsTurnpike(); +bool IsKalimariDesert(); +bool IsSherbetLand(); +bool IsRainbowRoad(); +bool IsWarioStadium(); +bool IsBlockFort(); +bool IsSkyscraper(); +bool IsDoubleDeck(); +bool IsDkJungle(); +bool IsBigDonut(); +bool IsPodiumCeremony(); + +void SelectMarioRaceway(); +void SelectLuigiRaceway(); +void SelectChocoMountain(); +void SelectBowsersCastle(); +void SelectBansheeBoardwalk(); +void SelectYoshiValley(); +void SelectFrappeSnowland(); +void SelectKoopaTroopaBeach(); +void SelectRoyalRaceway(); +void SelectMooMooFarm(); +void SelectToadsTurnpike(); +void SelectKalimariDesert(); +void SelectSherbetLand(); +void SelectRainbowRoad(); +void SelectWarioStadium(); +void SelectBlockFort(); +void SelectSkyscraper(); +void SelectDoubleDeck(); +void SelectDkJungle(); +void SelectBigDonut(); +void SelectPodiumCeremony(); void* GetMushroomCup(void); diff --git a/src/port/interpolation/FrameInterpolation.cpp b/src/port/interpolation/FrameInterpolation.cpp new file mode 100644 index 000000000..836e6c70c --- /dev/null +++ b/src/port/interpolation/FrameInterpolation.cpp @@ -0,0 +1,806 @@ +#include + +#include +#include +#include +#include +#include "port/Engine.h" +#include "FrameInterpolation.h" +#include "matrix.h" + +extern "C" { +#include "math_util.h" +#include "math_util_2.h" +#include "render_player.h" + +extern Mat4* gInterpolationMatrix; +void mtxf_translate(Mat4, Vec3f); +} +/* +Frame interpolation. + +The idea of this code is to interpolate all matrices. + +The code contains two approaches. The first is to interpolate +all inputs in transformations, such as angles, scale and distances, +and then perform the same transformations with the interpolated values. +After evaluation for some reason some animations such rolling look strange. + +The second approach is to simply interpolate the final matrices. This will +more or less simply interpolate the world coordinates for movements. +This will however make rotations ~180 degrees get the "paper effect". +The mitigation is to identify this case for actors and interpolate the +matrix but in model coordinates instead, by "removing" the rotation- +translation before interpolating, create a rotation matrix with the +interpolated angle which is then applied to the matrix. + +Currently the code contains both methods but only the second one is currently +used. + +Both approaches build a tree of instructions, containing matrices +at leaves. Every node is built from OPEN_DISPS/CLOSE_DISPS and manually +inserted FrameInterpolation_OpenChild/FrameInterpolation_Close child calls. +These nodes contain information that should suffice to identify the matrix, +so we can find it in an adjacent frame. + +We can interpolate an arbitrary amount of frames between two original frames, +given a specific interpolation factor (0=old frame, 0.5=average of frames, +1.0=new frame). +*/ + +static bool invert_matrix(const float m[16], float invOut[16]); + +using namespace std; + +extern "C" { +extern Mat4* gInterpolationMatrix; +void mtxf_translate(Mat4, Vec3f); +} + +namespace { + +enum class Op { + Marker, + OpenChild, + CloseChild, + + MatrixPush, + MatrixPop, + MatrixPut, + MatrixMult, + MatrixTranslate, + MatrixScale, + MatrixRotate1Coord, + MatrixMult4x4, + MatrixPosRotXYZ, + MatrixMultVec3fNoTranslate, + MatrixMultVec3f, + MatrixMtxFToMtx, + MatrixToMtx, + MatrixRotateAxis, + SkinMatrixMtxFToMtx, + SetTransformMatrix, + SetMatrixTransformation, + SetTranslateRotate +}; + +typedef pair label; + +union Data { + Data() { + } + + struct { + Mat4** matrix; + } matrix_ptr; + + struct { + const char* file; + int line; + } marker; + + struct { + Mat4* matrix; + MtxF mf; + u8 mode; + } matrix_mult; + + struct { + Mat4* matrix; + Vec3fInterp b; + } matrix_translate; + + struct { + Mat4* matrix; + f32 scale; + } matrix_scale; + + struct { + Mat4* matrix; + u32 coord; + s16 value; + } matrix_rotate_1_coord; + + struct { + Mat4* matrix; + Vec3f src; + Vec3f dest; + } matrix_vec_translate; + + struct { + Mat4* matrix; + Vec3f src; + Vec3f dest; + } matrix_vec_no_translate; + + struct { + Mat4* dest; + Mat4 mtx1; + Mat4 mtx2; + } matrix_mult_4x4; + + struct { + Vec3fInterp pos; + Vec3sInterp orientation; + } matrix_pos_rot_xyz; + + struct { + Mat4* matrix; + Vec3f translation; + Vec3s rotation; + } matrix_translate_rotate_zyx; + + struct { + Mat4* matrix; + f32 translateX, translateY, translateZ; + Vec3s rot; + // MtxF mtx; + bool has_mtx; + } matrix_set_translate_rotate_yxz; + + struct { + MtxF src; + Mtx* dest; + } matrix_mtxf_to_mtx; + + struct { + Mtx* dest; + MtxF src; + bool has_adjusted; + } matrix_to_mtx; + + struct { + MtxF mf; + } matrix_replace_rotation; + + struct { + f32 angle; + Vec3f axis; + u8 mode; + } matrix_rotate_axis; + + struct { + Mat4* dest; + Vec3f orientationVector; + Vec3f positionVector; + u16 rotationAngle; + f32 scaleFactor; + } set_transform_matrix_data; + + struct { + Mat4* dest; + Vec3f location; + Vec3su rotation; + f32 scale; + } set_matrix_transformation_data; + + struct { + Mat4* dest; + Vec3f location; + Vec3s rotation; + } set_translate_rotate_data; + + struct { + Mat3* dest; + f32 arg1; + f32 arg2; + f32 arg3; + s16 rot; + } set_orientation_matrix_data; + + struct { + label key; + size_t idx; + } open_child; +}; + +struct Path { + map> children; + map> ops; + vector> items; +}; + +struct Recording { + Path root_path; +}; + +bool is_recording; +vector current_path; +uint32_t camera_epoch; +uint32_t previous_camera_epoch; +Recording current_recording; +Recording previous_recording; + +bool next_is_actor_pos_rot_matrix; +bool has_inv_actor_mtx; +MtxF inv_actor_mtx; +size_t inv_actor_mtx_path_index; + +Data& append(Op op) { + auto& m = current_path.back()->ops[op]; + current_path.back()->items.emplace_back(op, m.size()); + return m.emplace_back(); +} + +MtxF* Matrix_GetCurrent() { + return (MtxF*) gInterpolationMatrix; +} + +struct InterpolateCtx { + float step; + float w; + unordered_map mtx_replacements; + MtxF tmp_mtxf, tmp_mtxf2; + Mat3 tmp_mat3; + Vec3f tmp_vec3f, tmp_vec3f2; + Vec3s tmp_vec3s; + MtxF actor_mtx; + + MtxF* new_replacement(Mtx* addr) { + return &mtx_replacements[addr]; + } + + void interpolate_mtxf(MtxF* res, MtxF* o, MtxF* n) { + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + res->mf[i][j] = w * o->mf[i][j] + step * n->mf[i][j]; + } + } + } + + float lerp(f32 o, f32 n) { + return w * o + step * n; + } + + s16 lerp_s16(s16 o, s16 n) { + return w * o + step * n; + } + + void lerp_vec3s(Vec3s* res, Vec3s o, Vec3s n) { + *res[0] = lerp_s16(o[0], n[0]); + *res[1] = lerp_s16(o[1], n[1]); + *res[2] = lerp_s16(o[2], n[2]); + } + + void lerp_vec3f(Vec3f* res, Vec3f* o, Vec3f* n) { + *res[0] = lerp(*o[0], *n[0]); + *res[1] = lerp(*o[1], *n[1]); + *res[2] = lerp(*o[2], *n[2]); + } + + float interpolate_angle(f32 o, f32 n) { + if (o == n) + return n; + o = fmodf(o, 2 * M_PI); + if (o < 0.0f) { + o += 2 * M_PI; + } + n = fmodf(n, 2 * M_PI); + if (n < 0.0f) { + n += 2 * M_PI; + } + if (fabsf(o - n) > M_PI) { + if (o < n) { + o += 2 * M_PI; + } else { + n += 2 * M_PI; + } + } + if (fabsf(o - n) > M_PI / 2) { + // return n; + } + return lerp(o, n); + } + + s16 interpolate_angle(s16 os, s16 ns) { + if (os == ns) + return ns; + int o = (u16) os; + int n = (u16) ns; + u16 res; + int diff = o - n; + if (-0x8000 <= diff && diff <= 0x8000) { + if (diff < -0x4000 || diff > 0x4000) { + return ns; + } + res = (u16) (w * o + step * n); + } else { + if (o < n) { + o += 0x10000; + } else { + n += 0x10000; + } + diff = o - n; + if (diff < -0x4000 || diff > 0x4000) { + return ns; + } + res = (u16) (w * o + step * n); + } + if (os / 327 == ns / 327 && (s16) res / 327 != os / 327) { + int bp = 0; + } + return res; + } + + void interpolate_vecs(Vec3f* res, Vec3f* o, Vec3f* n) { + *res[0] = interpolate_angle(*o[0], *n[0]); + *res[1] = interpolate_angle(*o[1], *n[1]); + *res[2] = interpolate_angle(*o[2], *n[2]); + } + + void interpolate_angles(Vec3s* res, Vec3s* o, Vec3s* n) { + *res[0] = interpolate_angle(*o[0], *n[0]); + *res[1] = interpolate_angle(*o[1], *n[1]); + *res[2] = interpolate_angle(*o[2], *n[2]); + } + + void interpolate_branch(Path* old_path, Path* new_path) { + for (auto& item : new_path->items) { + Data& new_op = new_path->ops[item.first][item.second]; + + if (item.first == Op::OpenChild) { + if (auto it = old_path->children.find(new_op.open_child.key); + it != old_path->children.end() && new_op.open_child.idx < it->second.size()) { + interpolate_branch(&it->second[new_op.open_child.idx], + &new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]); + } else { + interpolate_branch(&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx], + &new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]); + } + continue; + } + + if (auto it = old_path->ops.find(item.first); it != old_path->ops.end()) { + if (item.second < it->second.size()) { + Data& old_op = it->second[item.second]; + switch (item.first) { + case Op::OpenChild: + case Op::CloseChild: + case Op::Marker: + break; + + case Op::MatrixPush: + Matrix_Push((Matrix**) &gInterpolationMatrix); + break; + + case Op::MatrixPop: + Matrix_Pop((Matrix**) &gInterpolationMatrix); + break; + + // Unused on SF64 + // case Op::MatrixPut: + // interpolate_mtxf(&tmp_mtxf, &old_op.matrix_put.src, &new_op.matrix_put.src); + // Matrix_Put(&tmp_mtxf); + // break; + + case Op::MatrixMult: + interpolate_mtxf(&tmp_mtxf, &old_op.matrix_mult.mf, &new_op.matrix_mult.mf); + mtxf_multiplication(*gInterpolationMatrix, tmp_mtxf.mf, new_op.matrix_mult.mf.mf); + // Matrix_Mult(gInterpolationMatrix, (Matrix*) &tmp_mtxf, new_op.matrix_mult.mode); + break; + + case Op::MatrixTranslate: + + Vec3f temp; + + temp[0] = lerp(old_op.matrix_translate.b.x, new_op.matrix_translate.b.x); + temp[1] = lerp(old_op.matrix_translate.b.y, new_op.matrix_translate.b.y); + temp[2] = lerp(old_op.matrix_translate.b.z, new_op.matrix_translate.b.z); + + mtxf_translate(*gInterpolationMatrix, temp); + break; + case Op::MatrixPosRotXYZ: + Vec3f tempF; + Vec3s tempS; + + tempF[0] = lerp(old_op.matrix_pos_rot_xyz.pos.x, new_op.matrix_pos_rot_xyz.pos.x); + tempF[1] = lerp(old_op.matrix_pos_rot_xyz.pos.y, new_op.matrix_pos_rot_xyz.pos.y); + tempF[2] = lerp(old_op.matrix_pos_rot_xyz.pos.z, new_op.matrix_pos_rot_xyz.pos.z); + + tempS[0] = + lerp(old_op.matrix_pos_rot_xyz.orientation.x, new_op.matrix_pos_rot_xyz.orientation.x); + tempS[1] = + lerp(old_op.matrix_pos_rot_xyz.orientation.y, new_op.matrix_pos_rot_xyz.orientation.y); + tempS[2] = + lerp(old_op.matrix_pos_rot_xyz.orientation.z, new_op.matrix_pos_rot_xyz.orientation.z); + + mtxf_pos_rotation_xyz(*gInterpolationMatrix, tempF, tempS); + break; + + case Op::MatrixScale: + mtxf_scale(*gInterpolationMatrix, lerp(old_op.matrix_scale.scale, new_op.matrix_scale.scale)); + break; + + case Op::MatrixRotate1Coord: { + s16 v = interpolate_angle(old_op.matrix_rotate_1_coord.value, + new_op.matrix_rotate_1_coord.value); + switch (new_op.matrix_rotate_1_coord.coord) { + case 0: + mtxf_rotate_x(*gInterpolationMatrix, v); + break; + + case 1: + mtxf_rotate_y(*gInterpolationMatrix, v); + break; + + case 2: + mtxf_s16_rotate_z(*gInterpolationMatrix, v); + break; + } + break; + } + case Op::MatrixMultVec3fNoTranslate: { + interpolate_vecs(&tmp_vec3f, &old_op.matrix_vec_no_translate.src, + &new_op.matrix_vec_no_translate.src); + interpolate_vecs(&tmp_vec3f2, &old_op.matrix_vec_no_translate.dest, + &new_op.matrix_vec_no_translate.dest); + // Matrix_MultVec3fNoTranslate(gInterpolationMatrix, &tmp_vec3f, &tmp_vec3f2); + break; + } + case Op::MatrixMultVec3f: { + interpolate_vecs(&tmp_vec3f, &old_op.matrix_vec_translate.src, + &new_op.matrix_vec_translate.src); + interpolate_vecs(&tmp_vec3f2, &old_op.matrix_vec_translate.dest, + &new_op.matrix_vec_translate.dest); + // Matrix_MultVec3f(gInterpolationMatrix, &tmp_vec3f, &tmp_vec3f2); + break; + } + + case Op::MatrixMtxFToMtx: + interpolate_mtxf(new_replacement(new_op.matrix_mtxf_to_mtx.dest), + &old_op.matrix_mtxf_to_mtx.src, &new_op.matrix_mtxf_to_mtx.src); + break; + + case Op::MatrixToMtx: { + //*new_replacement(new_op.matrix_to_mtx.dest) = *Matrix_GetCurrent(); + if (old_op.matrix_to_mtx.has_adjusted && new_op.matrix_to_mtx.has_adjusted) { + interpolate_mtxf(&tmp_mtxf, &old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src); + // Matrix_MtxFMtxFMult(&actor_mtx, &tmp_mtxf, + // new_replacement(new_op.matrix_to_mtx.dest)); + } else { + interpolate_mtxf(new_replacement(new_op.matrix_to_mtx.dest), &old_op.matrix_to_mtx.src, + &new_op.matrix_to_mtx.src); + } + break; + } + + case Op::MatrixRotateAxis: { + lerp_vec3f(&tmp_vec3f, &old_op.matrix_rotate_axis.axis, &new_op.matrix_rotate_axis.axis); + auto tmp = + interpolate_angle(old_op.matrix_rotate_axis.angle, new_op.matrix_rotate_axis.angle); + // Matrix_RotateAxis((Matrix*) &tmp_vec3f, tmp, 1.0f, 1.0f, 1.0f, + // new_op.matrix_rotate_axis.mode); + break; + } + + case Op::SetTransformMatrix: { + lerp_vec3f(&tmp_vec3f, &old_op.set_transform_matrix_data.orientationVector, + &new_op.set_transform_matrix_data.orientationVector); + + lerp_vec3f(&tmp_vec3f2, &old_op.set_transform_matrix_data.positionVector, + &new_op.set_transform_matrix_data.positionVector); + + u16 rotationAngleTemp = lerp_s16(old_op.set_transform_matrix_data.rotationAngle, + new_op.set_transform_matrix_data.rotationAngle); + f32 scaleFactorTemp = lerp(old_op.set_transform_matrix_data.scaleFactor, new_op.set_transform_matrix_data.scaleFactor); + + set_transform_matrix(*gInterpolationMatrix, tmp_vec3f, tmp_vec3f2, rotationAngleTemp, scaleFactorTemp); + + break; + } + + case Op::SetMatrixTransformation: { + + lerp_vec3f(&tmp_vec3f, &old_op.set_matrix_transformation_data.location, + &new_op.set_matrix_transformation_data.location); + + lerp_vec3s(&tmp_vec3s, *(Vec3s*)&old_op.set_matrix_transformation_data.rotation, + *(Vec3s*)&new_op.set_matrix_transformation_data.rotation); + + f32 scaleFactorTemp = lerp(old_op.set_matrix_transformation_data.scale, new_op.set_matrix_transformation_data.scale); + + mtxf_set_matrix_transformation(*gInterpolationMatrix, tmp_vec3f, *(Vec3su*)&tmp_vec3s, scaleFactorTemp); + break; + } + + case Op::SetTranslateRotate: { + lerp_vec3f(&tmp_vec3f, &old_op.set_translate_rotate_data.location, + &new_op.set_translate_rotate_data.location); + + lerp_vec3s(&tmp_vec3s, old_op.set_translate_rotate_data.rotation, + new_op.set_translate_rotate_data.rotation); + + mtxf_translate_rotate(*gInterpolationMatrix, tmp_vec3f, tmp_vec3s); + break; + } + } + } + } + } + } +}; + +} // anonymous namespace + +unordered_map FrameInterpolation_Interpolate(float step) { + InterpolateCtx ctx; + ctx.step = step; + ctx.w = 1.0f - step; + ctx.interpolate_branch(&previous_recording.root_path, ¤t_recording.root_path); + return ctx.mtx_replacements; +} + +bool camera_interpolation = true; + +void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate) { + camera_interpolation = shouldInterpolate; + is_recording = shouldInterpolate; +} + +void FrameInterpolation_StartRecord(void) { + previous_recording = move(current_recording); + current_recording = {}; + current_path.clear(); + current_path.push_back(¤t_recording.root_path); + if (!camera_interpolation) { + // default to interpolating + camera_interpolation = true; + is_recording = false; + return; + } + if (GameEngine::GetInterpolationFPS() != 30) { + is_recording = true; + } +} + +void FrameInterpolation_StopRecord(void) { + previous_camera_epoch = camera_epoch; + is_recording = false; +} + +void FrameInterpolation_RecordOpenChild(const void* a, uintptr_t b) { + if (!is_recording) + return; + label key = { a, b }; + auto& m = current_path.back()->children[key]; + append(Op::OpenChild).open_child = { key, m.size() }; + current_path.push_back(&m.emplace_back()); +} + +void FrameInterpolation_RecordCloseChild(void) { + if (!is_recording) + return; + // append(Op::CloseChild); + if (has_inv_actor_mtx && current_path.size() == inv_actor_mtx_path_index) { + has_inv_actor_mtx = false; + } + current_path.pop_back(); +} + +void FrameInterpolation_DontInterpolateCamera(void) { + camera_epoch = previous_camera_epoch + 1; +} + +int FrameInterpolation_GetCameraEpoch(void) { + return (int) camera_epoch; +} + +void FrameInterpolation_RecordActorPosRotMatrix(void) { + if (!is_recording) + return; + next_is_actor_pos_rot_matrix = true; +} + +void FrameInterpolation_RecordMatrixPush(Mat4* matrix) { + if (!is_recording) + return; + + append(Op::MatrixPush).matrix_ptr = { (Mat4**) matrix }; +} + +void FrameInterpolation_RecordMarker(const char* file, int line) { + if (!is_recording) + return; + + append(Op::Marker).marker = { file, line }; +} + +void FrameInterpolation_RecordMatrixPop(Mat4* matrix) { + if (!is_recording) + return; + append(Op::MatrixPop).matrix_ptr = { (Mat4**) matrix }; +} + +void FrameInterpolation_RecordMatrixPut(MtxF* src) { + if (!is_recording) + return; + // append(Op::MatrixPut).matrix_put = { matrix, *src }; +} + +void FrameInterpolation_RecordMatrixMult(Mat4* matrix, MtxF* mf, u8 mode) { + if (!is_recording) + return; + append(Op::MatrixMult).matrix_mult = { matrix, *mf, mode }; +} + +void FrameInterpolation_RecordMatrixTranslate(Mat4* matrix, Vec3f b) { + if (!is_recording) + return; + + append(Op::MatrixTranslate).matrix_translate = { matrix, *((Vec3fInterp*) &b) }; +} + +void FrameInterpolation_RecordMatrixScale(Mat4* matrix, f32 scale) { + if (!is_recording) + return; + append(Op::MatrixScale).matrix_scale = { matrix, scale }; +} + +void FrameInterpolation_RecordMatrixMultVec3fNoTranslate(Mat4* matrix, Vec3f src, Vec3f dest) { + if (!is_recording) + return; + // append(Op::MatrixMultVec3fNoTranslate).matrix_vec_no_translate = { matrix, src, dest }; +} + +void FrameInterpolation_RecordSetTransformMatrix(Mat4* dest, Vec3f orientationVector, Vec3f positionVector, u16 rotationAngle, + f32 scaleFactor) { + if (!is_recording) + return; + append(Op::SetTransformMatrix).set_transform_matrix_data = { dest, {orientationVector[0], orientationVector[1], orientationVector[2]}, { positionVector[0], positionVector[1], positionVector[2] }, rotationAngle, scaleFactor}; +} + +void FrameInterpolation_RecordTranslateRotate(Mat4* dest, Vec3f pos, Vec3s rotation) { + if (!is_recording) { return; } + + append(Op::SetTranslateRotate).set_translate_rotate_data = { dest, {pos[0], pos[1], pos[2]}, { rotation[0], rotation[1], rotation[2] }}; +} + +void FrameInterpolation_RecordSetMatrixTransformation(Mat4* dest, Vec3f location, Vec3su rotation, f32 scale) { + if (!is_recording) + return; + append(Op::SetMatrixTransformation).set_matrix_transformation_data = { dest, {location[0], location[1], location[2]}, { rotation[0], rotation[1], rotation[2] }, scale}; +} + +void FrameInterpolation_RecordCalculateOrientationMatrix(Mat3* dest, f32 x, f32 y, f32 z, s16 rot) { + if (!is_recording) return; + + // append(Op::SetMatrixTransformation).set_calculate_orientation_matrix_data = { dest, x, y, z, rot}; +} + +// Make a template for deref + +void FrameInterpolation_RecordMatrixPosRotXYZ(Mat4 out, Vec3f pos, Vec3s orientation) { + if (!is_recording) + return; + append(Op::MatrixPosRotXYZ).matrix_pos_rot_xyz = { *((Vec3fInterp*) &pos), *((Vec3sInterp*) &orientation) }; +} + +void FrameInterpolation_RecordMatrixMultVec3f(Mat4* matrix, Vec3f src, Vec3f dest) { + if (!is_recording) + return; + // append(Op::MatrixMultVec3f).matrix_vec_translate = { matrix, src, dest }; +} + +void FrameInterpolation_RecordMatrixRotate1Coord(Mat4* matrix, u32 coord, s16 value) { + if (!is_recording) + return; + append(Op::MatrixRotate1Coord).matrix_rotate_1_coord = { matrix, coord, value }; +} + +void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest) { + if (!is_recording) + return; + append(Op::MatrixMtxFToMtx).matrix_mtxf_to_mtx = { *src, dest }; +} + +void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line) { + if (!is_recording) + return; + auto& d = append(Op::MatrixToMtx).matrix_to_mtx = { dest }; + if (has_inv_actor_mtx) { + d.has_adjusted = true; + // Matrix_MtxFMtxFMult(&inv_actor_mtx, Matrix_GetCurrent(), &d.src); + } else { + d.src = *Matrix_GetCurrent(); + } +} + +void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode) { + if (!is_recording) + return; + // append(Op::MatrixRotateAxis).matrix_rotate_axis = { angle, axis, mode }; +} + +void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest) { + if (!is_recording) + return; + FrameInterpolation_RecordMatrixMtxFToMtx(src, dest); +} + +// https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix +static bool invert_matrix(const float m[16], float invOut[16]) { + float inv[16], det; + int i; + + inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; + + inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - + m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; + + inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; + + inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - + m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; + + inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - + m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; + + inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; + + inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - + m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; + + inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; + + inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; + + inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - + m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; + + inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; + + inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - + m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; + + inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - + m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; + + inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; + + inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - + m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; + + inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - + m[8] * m[2] * m[5]; + + det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; + + if (det == 0) { + return false; + } + + det = 1.0 / det; + + for (i = 0; i < 16; i++) { + invOut[i] = inv[i] * det; + } + + return true; +} \ No newline at end of file diff --git a/src/port/interpolation/FrameInterpolation.h b/src/port/interpolation/FrameInterpolation.h new file mode 100644 index 000000000..c59743681 --- /dev/null +++ b/src/port/interpolation/FrameInterpolation.h @@ -0,0 +1,85 @@ +#ifndef __FRAME_INTERPOLATION_H +#define __FRAME_INTERPOLATION_H + +// #include "sf64math.h" +#include +#include + +#ifdef __cplusplus + +#include + + + +std::unordered_map FrameInterpolation_Interpolate(float step); + +extern "C" { +#endif + +#define TAG_ITEM_ADDR(x) ((u32) 0x10000000 | (u32)x) +#define TAG_SMOKE_DUST(x) ((u32) 0x20000000 | (u32) (x)) +#define TAG_LETTER(x) ((u32)0x30000000 | (u32) (x)) +#define TAG_OBJECT(x) ((u32)0x40000000 | (u32) (uintptr_t) (x)) + +void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate); + +void FrameInterpolation_StartRecord(void); + +void FrameInterpolation_StopRecord(void); + +void FrameInterpolation_RecordMarker(const char* file, int line); + +void FrameInterpolation_RecordOpenChild(const void* a, uintptr_t b); + +void FrameInterpolation_RecordCloseChild(void); + +void FrameInterpolation_DontInterpolateCamera(void); + +int FrameInterpolation_GetCameraEpoch(void); + +void FrameInterpolation_RecordActorPosRotMatrix(void); + +void FrameInterpolation_RecordMatrixPosRotXYZ(Mat4 out, Vec3f pos, Vec3s orientation); + +void FrameInterpolation_RecordMatrixPush(Mat4* matrix); + +void FrameInterpolation_RecordMatrixPop(Mat4* matrix); + +void FrameInterpolation_RecordMatrixMult(Mat4* matrix, MtxF* mf, u8 mode); + +void FrameInterpolation_RecordMatrixTranslate(Mat4* matrix, Vec3f b); + +void FrameInterpolation_RecordMatrixScale(Mat4* matrix, f32 scale); + +void FrameInterpolation_RecordMatrixRotate1Coord(Mat4* matrix, u32 coord, s16 value); + +void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest); + +void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line); + +void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf); + +//void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode); + +void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest); + +//void FrameInterpolation_RecordMatrixMultVec3f(Matrix* matrix, Vec3f src, Vec3f dest); + +//void FrameInterpolation_RecordMatrixMultVec3fNoTranslate(Matrix* matrix, Vec3f src, Vec3f dest); + +void FrameInterpolation_RecordSetTransformMatrix(Mat4* dest, Vec3f orientationVector, Vec3f positionVector, u16 rotationAngle, + f32 scaleFactor); + +void FrameInterpolation_RecordSetMatrixTransformation(Mat4* dest, Vec3f location, Vec3su rotation, f32 scale); + +void FrameInterpolation_RecordCalculateOrientationMatrix(Mat3*, f32, f32, f32, s16); + +void FrameInterpolation_RecordTranslateRotate(Mat4* dest, Vec3f pos, Vec3s rotation); + +//void FrameInterpolation_func_80062B18(f32* arg0, f32* arg1, f32* arg2, arg3, arg4, arg5, arg6, arg7); + +#ifdef __cplusplus +} +#endif + +#endif // __FRAME_INTERPOLATION_H diff --git a/src/port/interpolation/matrix.c b/src/port/interpolation/matrix.c new file mode 100644 index 000000000..5580975a5 --- /dev/null +++ b/src/port/interpolation/matrix.c @@ -0,0 +1,451 @@ +#include +#include +#include "matrix.h" +#include "common_structs.h" +#include "FrameInterpolation.h" + +Mtx gIdentityMtx = gdSPDefMtx(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); +Matrix gIdentityMatrix = { { + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, +} }; + +Matrix* gGfxMatrix; +Matrix sGfxMatrixStack[0x20]; +Matrix* gCalcMatrix; +Matrix sCalcMatrixStack[0x20]; + +Mtx gMainMatrixStack[0x480]; +Mtx* gGfxMtx; + +void Matrix_InitPerspective(Gfx** dList) { + u16 norm; + float near = 10.0f; + float far = 12800.0f; + float fov = 45.0f; + + guPerspective(gGfxMtx, &norm, fov, 320.0f / 240.0f, near, far, 1.0f); + gSPPerspNormalize((*dList)++, norm); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + guLookAt(gGfxMtx, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -12800.0f, 0.0f, 1.0f, 0.0f); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + Matrix_Copy(gGfxMatrix, &gIdentityMatrix); +} + +void Matrix_InitOrtho(Gfx** dList) { + FrameInterpolation_RecordOpenChild("ortho", 0); + FrameInterpolation_RecordMarker(__FILE__, __LINE__); + guOrtho(gGfxMtx, -320.0f / 2, 320.0f / 2, -240.0f / 2, 240.0f / 2, 0.0f, 5.0f, 1.0f); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + guLookAt(gGfxMtx, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -12800.0f, 0.0f, 1.0f, 0.0f); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + Matrix_Copy(gGfxMatrix, &gIdentityMatrix); + FrameInterpolation_RecordCloseChild(); +} + + +// Copies src Matrix into dst +void Matrix_Copy(Matrix* dst, Matrix* src) { + int32_t i; + + for (i = 0; i < 4; i++) { + dst->mf[i][0] = src->mf[i][0]; + dst->mf[i][1] = src->mf[i][1]; + dst->mf[i][2] = src->mf[i][2]; + dst->mf[i][3] = src->mf[i][3]; + } +} + +// Makes a copy of the stack's current matrix and puts it on the top of the stack +void Matrix_Push(Matrix** mtxStack) { + Matrix_Copy(*mtxStack + 1, *mtxStack); + (*mtxStack)++; +} + +// Removes the top matrix of the stack +void Matrix_Pop(Matrix** mtxStack) { + (*mtxStack)--; +} + +// Copies tf into mtx (MTXF_NEW) or applies it to mtx (MTXF_APPLY) +void Matrix_Mult(Matrix* mtx, Matrix* tf, u8 mode) { + f32 rx; + f32 ry; + f32 rz; + f32 rw; + s32 i0; + s32 i1; + s32 i2; + s32 i3; + + if (mode == 1) { + rx = mtx->mf[0][0]; + ry = mtx->mf[1][0]; + rz = mtx->mf[2][0]; + rw = mtx->mf[3][0]; + + for (i0 = 0; i0 < 4; i0++) { + mtx->mf[i0][0] = (rx * tf->mf[i0][0]) + (ry * tf->mf[i0][1]) + (rz * tf->mf[i0][2]) + (rw * tf->mf[i0][3]); + } + + rx = mtx->mf[0][1]; + ry = mtx->mf[1][1]; + rz = mtx->mf[2][1]; + rw = mtx->mf[3][1]; + + for (i1 = 0; i1 < 4; i1++) { + mtx->mf[i1][1] = (rx * tf->mf[i1][0]) + (ry * tf->mf[i1][1]) + (rz * tf->mf[i1][2]) + (rw * tf->mf[i1][3]); + } + + rx = mtx->mf[0][2]; + ry = mtx->mf[1][2]; + rz = mtx->mf[2][2]; + rw = mtx->mf[3][2]; + + for (i2 = 0; i2 < 4; i2++) { + mtx->mf[i2][2] = (rx * tf->mf[i2][0]) + (ry * tf->mf[i2][1]) + (rz * tf->mf[i2][2]) + (rw * tf->mf[i2][3]); + } + + rx = mtx->mf[0][3]; + ry = mtx->mf[1][3]; + rz = mtx->mf[2][3]; + rw = mtx->mf[3][3]; + + for (i3 = 0; i3 < 4; i3++) { + mtx->mf[i3][3] = (rx * tf->mf[i3][0]) + (ry * tf->mf[i3][1]) + (rz * tf->mf[i3][2]) + (rw * tf->mf[i3][3]); + } + } else { + Matrix_Copy(mtx, tf); + } +} + +// Creates a translation matrix in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_Translate(Matrix* mtx, f32 x, f32 y, f32 z, u8 mode) { + f32 rx; + f32 ry; + s32 i; + + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + ry = mtx->mf[1][i]; + + mtx->mf[3][i] += (rx * x) + (ry * y) + (mtx->mf[2][i] * z); + } + } else { + mtx->mf[3][0] = x; + mtx->mf[3][1] = y; + mtx->mf[3][2] = z; + mtx->mf[0][1] = mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][0] = + mtx->mf[2][1] = mtx->mf[2][3] = 0.0f; + mtx->mf[0][0] = mtx->mf[1][1] = mtx->mf[2][2] = mtx->mf[3][3] = 1.0f; + } +} + +// Creates a scale matrix in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_Scale(Matrix* mtx, f32 xScale, f32 yScale, f32 zScale, u8 mode) { + f32 rx; + f32 ry; + s32 i; + + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + ry = mtx->mf[1][i]; + + mtx->mf[0][i] = rx * xScale; + mtx->mf[1][i] = ry * yScale; + mtx->mf[2][i] *= zScale; + } + } else { + mtx->mf[0][0] = xScale; + mtx->mf[1][1] = yScale; + mtx->mf[2][2] = zScale; + mtx->mf[0][1] = mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][0] = + mtx->mf[2][1] = mtx->mf[2][3] = mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + mtx->mf[3][3] = 1.0f; + } +} + +// Creates rotation matrix about the X axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_RotateX(Matrix* mtx, f32 angle, u8 mode) { + f32 cs; + f32 sn; + f32 ry; + f32 rz; + s32 i; + + sn = sinf(angle); + cs = cosf(angle); + if (mode == 1) { + for (i = 0; i < 4; i++) { + ry = mtx->mf[1][i]; + rz = mtx->mf[2][i]; + + mtx->mf[1][i] = (ry * cs) + (rz * sn); + mtx->mf[2][i] = (rz * cs) - (ry * sn); + } + } else { + mtx->mf[1][1] = mtx->mf[2][2] = cs; + mtx->mf[1][2] = sn; + mtx->mf[2][1] = -sn; + mtx->mf[0][0] = mtx->mf[3][3] = 1.0f; + mtx->mf[0][1] = mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][3] = mtx->mf[2][0] = mtx->mf[2][3] = + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + } +} + +// Creates rotation matrix about the Y axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_RotateY(Matrix* mtx, f32 angle, u8 mode) { + f32 cs; + f32 sn; + f32 rx; + f32 rz; + s32 i; + + sn = sinf(angle); + cs = cosf(angle); + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + rz = mtx->mf[2][i]; + + mtx->mf[0][i] = (rx * cs) - (rz * sn); + mtx->mf[2][i] = (rx * sn) + (rz * cs); + } + } else { + mtx->mf[0][0] = mtx->mf[2][2] = cs; + mtx->mf[0][2] = -sn; + mtx->mf[2][0] = sn; + mtx->mf[1][1] = mtx->mf[3][3] = 1.0f; + mtx->mf[0][1] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][1] = mtx->mf[2][3] = + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + } +} + +// Creates rotation matrix about the Z axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_RotateZ(Matrix* mtx, f32 angle, u8 mode) { + f32 cs; + f32 sn; + f32 rx; + f32 ry; + s32 i; + + sn = sinf(angle); + cs = cosf(angle); + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + ry = mtx->mf[1][i]; + + mtx->mf[0][i] = (rx * cs) + (ry * sn); + mtx->mf[1][i] = (ry * cs) - (rx * sn); + } + } else { + mtx->mf[0][0] = mtx->mf[1][1] = cs; + mtx->mf[0][1] = sn; + mtx->mf[1][0] = -sn; + mtx->mf[2][2] = mtx->mf[3][3] = 1.0f; + mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][0] = mtx->mf[2][1] = mtx->mf[2][3] = + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + } +} + +// Creates rotation matrix about a given vector axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY). +// The vector specifying the axis does not need to be a unit vector. +void Matrix_RotateAxis(Matrix* mtx, f32 angle, f32 axisX, f32 axisY, f32 axisZ, u8 mode) { + f32 rx; + f32 ry; + f32 rz; + f32 norm; + f32 cxx; + f32 cyx; + f32 czx; + f32 cxy; + f32 cyy; + f32 czy; + f32 cxz; + f32 cyz; + f32 czz; + f32 xx; + f32 yy; + f32 zz; + f32 xy; + f32 yz; + f32 xz; + f32 sinA; + f32 cosA; + + norm = sqrtf((axisX * axisX) + (axisY * axisY) + (axisZ * axisZ)); + if (norm != 0.0) { + axisX /= norm; + axisY /= norm; + axisZ /= norm; + sinA = sinf(angle); + cosA = cosf(angle); + xx = axisX * axisX; + yy = axisY * axisY; + zz = axisZ * axisZ; + xy = axisX * axisY; + yz = axisY * axisZ; + xz = axisX * axisZ; + + if (mode == 1) { + cxx = (1.0f - xx) * cosA + xx; + cyx = (1.0f - cosA) * xy + axisZ * sinA; + czx = (1.0f - cosA) * xz - axisY * sinA; + + cxy = (1.0f - cosA) * xy - axisZ * sinA; + cyy = (1.0f - yy) * cosA + yy; + czy = (1.0f - cosA) * yz + axisX * sinA; + + cxz = (1.0f - cosA) * xz + axisY * sinA; + cyz = (1.0f - cosA) * yz - axisX * sinA; + czz = (1.0f - zz) * cosA + zz; + + // loop doesn't seem to work here. + rx = mtx->mf[0][0]; + ry = mtx->mf[0][1]; + rz = mtx->mf[0][2]; + mtx->mf[0][0] = (rx * cxx) + (ry * cxy) + (rz * cxz); + mtx->mf[0][1] = (rx * cyx) + (ry * cyy) + (rz * cyz); + mtx->mf[0][2] = (rx * czx) + (ry * czy) + (rz * czz); + + rx = mtx->mf[1][0]; + ry = mtx->mf[1][1]; + rz = mtx->mf[1][2]; + mtx->mf[1][0] = (rx * cxx) + (ry * cxy) + (rz * cxz); + mtx->mf[1][1] = (rx * cyx) + (ry * cyy) + (rz * cyz); + mtx->mf[1][2] = (rx * czx) + (ry * czy) + (rz * czz); + + rx = mtx->mf[2][0]; + ry = mtx->mf[2][1]; + rz = mtx->mf[2][2]; + mtx->mf[2][0] = (rx * cxx) + (ry * cxy) + (rz * cxz); + mtx->mf[2][1] = (rx * cyx) + (ry * cyy) + (rz * cyz); + mtx->mf[2][2] = (rx * czx) + (ry * czy) + (rz * czz); + } else { + mtx->mf[0][0] = (1.0f - xx) * cosA + xx; + mtx->mf[0][1] = (1.0f - cosA) * xy + axisZ * sinA; + mtx->mf[0][2] = (1.0f - cosA) * xz - axisY * sinA; + mtx->mf[0][3] = 0.0f; + + mtx->mf[1][0] = (1.0f - cosA) * xy - axisZ * sinA; + mtx->mf[1][1] = (1.0f - yy) * cosA + yy; + mtx->mf[1][2] = (1.0f - cosA) * yz + axisX * sinA; + mtx->mf[1][3] = 0.0f; + + mtx->mf[2][0] = (1.0f - cosA) * xz + axisY * sinA; + mtx->mf[2][1] = (1.0f - cosA) * yz - axisX * sinA; + mtx->mf[2][2] = (1.0f - zz) * cosA + zz; + mtx->mf[2][3] = 0.0f; + + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + mtx->mf[3][3] = 1.0f; + } + } +} + +// Converts the current Gfx matrix to a Mtx +void Matrix_ToMtx(Mtx* dest) { + // LTODO: We need to validate this + guMtxF2L(gGfxMatrix->mf, dest); +} + +// Converts the Mtx src to a Matrix, putting the result in dest +void Matrix_FromMtx(Mtx* src, Matrix* dest) { + guMtxF2L(src->m, dest->mf); +} + +// Applies the transform matrix mtx to the vector src, putting the result in dest +void Matrix_MultVec3f(Matrix* mtx, Vec3f* src, Vec3f* dest) { + *dest[0] = (mtx->mf[0][0] * *src[0]) + (mtx->mf[1][0] * *src[1]) + (mtx->mf[2][0] * *src[2]) + mtx->mf[3][0]; + *dest[1] = (mtx->mf[0][1] * *src[0]) + (mtx->mf[1][1] * *src[1]) + (mtx->mf[2][1] * *src[2]) + mtx->mf[3][1]; + *dest[2] = (mtx->mf[0][2] * *src[0]) + (mtx->mf[1][2] * *src[1]) + (mtx->mf[2][2] * *src[2]) + mtx->mf[3][2]; +} + +// Applies the linear part of the transformation matrix mtx to the vector src, ignoring any translation that mtx might +// have. Puts the result in dest. +void Matrix_MultVec3fNoTranslate(Matrix* mtx, Vec3f* src, Vec3f* dest) { + *dest[0] = (mtx->mf[0][0] * *src[0]) + (mtx->mf[1][0] * *src[1]) + (mtx->mf[2][0] * *src[2]); + *dest[1] = (mtx->mf[0][1] * *src[0]) + (mtx->mf[1][1] * *src[1]) + (mtx->mf[2][1] * *src[2]); + *dest[2] = (mtx->mf[0][2] * *src[0]) + (mtx->mf[1][2] * *src[1]) + (mtx->mf[2][2] * *src[2]); +} + +// Expresses the rotational part of the transform mtx as Tait-Bryan angles, in the yaw-pitch-roll (intrinsic YXZ) +// convention used in worldspace calculations +void Matrix_GetYRPAngles(Matrix* mtx, Vec3f* rot) { + Matrix invYP; + Vec3f origin = { 0.0f, 0.0f, 0.0f }; + Vec3f originP; + Vec3f zHat = { 0.0f, 0.0f, 1.0f }; + Vec3f zHatP; + Vec3f xHat = { 1.0f, 0.0f, 0.0f }; + Vec3f xHatP; + + Matrix_MultVec3fNoTranslate(mtx, &origin, &originP); + Matrix_MultVec3fNoTranslate(mtx, &zHat, &zHatP); + Matrix_MultVec3fNoTranslate(mtx, &xHat, &xHatP); + zHatP[0] -= originP[0]; + zHatP[1] -= originP[1]; + zHatP[2] -= originP[2]; + xHatP[0] -= originP[0]; + xHatP[1] -= originP[1]; + xHatP[2] -= originP[2]; + *rot[1] = atan2f(zHatP[0], zHatP[2]); + *rot[0] = -atan2f(zHatP[1], sqrtf(SQ(zHatP[0]) + SQ(zHatP[2]))); + Matrix_RotateX(&invYP, -*rot[0], MTXF_NEW); + Matrix_RotateY(&invYP, -*rot[1], MTXF_APPLY); + Matrix_MultVec3fNoTranslate(&invYP, &xHatP, &xHat); + *rot[0] *= M_RTOD; + *rot[1] *= M_RTOD; + *rot[2] = atan2f(xHat[1], xHat[0]) * M_RTOD; +} + +// Expresses the rotational part of the transform mtx as Tait-Bryan angles, in the extrinsic XYZ convention used in +// modelspace calculations +void Matrix_GetXYZAngles(Matrix* mtx, Vec3f* rot) { + Matrix invYZ; + Vec3f origin = { 0.0f, 0.0f, 0.0f }; + Vec3f originP; + Vec3f xHat = { 1.0f, 0.0f, 0.0f }; + Vec3f xHatP; + Vec3f yHat = { 0.0f, 1.0f, 0.0f }; + Vec3f yHatP; + + Matrix_MultVec3fNoTranslate(mtx, &origin, &originP); + Matrix_MultVec3fNoTranslate(mtx, &xHat, &xHatP); + Matrix_MultVec3fNoTranslate(mtx, &yHat, &yHatP); + xHatP[0] -= originP[0]; + xHatP[1] -= originP[1]; + xHatP[2] -= originP[2]; + yHatP[0] -= originP[0]; + yHatP[1] -= originP[1]; + yHatP[2] -= originP[2]; + *rot[2] = atan2f(xHatP[1], xHatP[0]); + *rot[1] = -atan2f(xHatP[2], sqrtf(SQ(xHatP[0]) + SQ(xHatP[1]))); + Matrix_RotateY(&invYZ, -*rot[1], MTXF_NEW); + Matrix_RotateZ(&invYZ, -*rot[2], MTXF_APPLY); + Matrix_MultVec3fNoTranslate(&invYZ, &yHatP, &yHat); + *rot[0] = atan2f(yHat[2], yHat[1]) * M_RTOD; + *rot[1] *= M_RTOD; + *rot[2] *= M_RTOD; +} + +// Creates a look-at matrix from Eye, At, and Up in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY). +// A look-at matrix is a rotation-translation matrix that maps y to Up, z to (At - Eye), and translates to Eye +void Matrix_LookAt(Matrix* mtx, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f32 xUp, f32 yUp, f32 zUp, + u8 mode) { + Matrix lookAt; + + guLookAtF(lookAt.mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp); + Matrix_Mult(mtx, &lookAt, mode); +} + +// Converts the current Gfx matrix to a Mtx and sets it to the display list +void Matrix_SetGfxMtx(Gfx** gfx) { + Matrix_ToMtx(gGfxMtx); + gSPMatrix((*gfx)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); +} \ No newline at end of file diff --git a/src/port/interpolation/matrix.h b/src/port/interpolation/matrix.h new file mode 100644 index 000000000..f71ef6ab0 --- /dev/null +++ b/src/port/interpolation/matrix.h @@ -0,0 +1,94 @@ +#pragma once + +#define MTXF_NEW 0 +#define MTXF_APPLY 1 +#include "common_structs.h" + +typedef struct { + float r; + float g; + float b; +} Color; + +typedef struct { + float x; + float y; + float z; +} Vec3fInterp; + +typedef struct { + s16 x; + s16 y; + s16 z; +} Vec3sInterp; + +typedef struct { + f32 m1; f32 m2; f32 m3; f32 m4; + f32 m5; f32 m6; f32 m7; f32 m8; +} Mat4Interp; + +#define M_PI 3.14159265358979323846f +#define M_RTOD (180.0f / M_PI) +#define SQ(val) ((val) * (val)) + +#define qs1616(e) ((s32) ((e) *0x00010000)) + +#define IPART(x) ((qs1616(x) >> 16) & 0xFFFF) +#define FPART(x) (qs1616(x) & 0xFFFF) + +#define gdSPDefMtx(xx, yx, zx, wx, xy, yy, zy, wy, xz, yz, zz, wz, xw, yw, zw, ww) \ + { \ + { \ + (IPART(xx) << 0x10) | IPART(xy), (IPART(xz) << 0x10) | IPART(xw), (IPART(yx) << 0x10) | IPART(yy), \ + (IPART(yz) << 0x10) | IPART(yw), (IPART(zx) << 0x10) | IPART(zy), (IPART(zz) << 0x10) | IPART(zw), \ + (IPART(wx) << 0x10) | IPART(wy), (IPART(wz) << 0x10) | IPART(ww), (FPART(xx) << 0x10) | FPART(xy), \ + (FPART(xz) << 0x10) | FPART(xw), (FPART(yx) << 0x10) | FPART(yy), (FPART(yz) << 0x10) | FPART(yw), \ + (FPART(zx) << 0x10) | FPART(zy), (FPART(zz) << 0x10) | FPART(zw), (FPART(wx) << 0x10) | FPART(wy), \ + (FPART(wz) << 0x10) | FPART(ww), \ + } \ + } + + +typedef MtxF Matrix; + +#ifdef __cplusplus +extern "C" { +#endif + +extern Mtx gIdentityMtx; +extern Matrix gIdentityMatrix; + +extern Matrix* gGfxMatrix; +extern Matrix sGfxMatrixStack[]; +extern Matrix* gCalcMatrix; +extern Matrix sCalcMatrixStack[]; + +extern Mtx gMainMatrixStack[]; +extern Mtx* gGfxMtx; + +void Matrix_InitPerspective(Gfx** dList); +void Matrix_InitOrtho(Gfx** dList); +void Matrix_Copy(Matrix* dst, Matrix* src); +void Matrix_Push(Matrix** mtxStack); +void Matrix_Pop(Matrix** mtxStack); +void Matrix_Mult(Matrix* mtx, Matrix* tf, u8 mode); +void Matrix_Translate(Matrix* mtx, f32 x, f32 y, f32 z, u8 mode); +void Matrix_Scale(Matrix* mtx, f32 xScale, f32 yScale, f32 zScale, u8 mode); +void Matrix_RotateX(Matrix* mtx, f32 angle, u8 mode); +void Matrix_RotateY(Matrix* mtx, f32 angle, u8 mode); +void Matrix_RotateZ(Matrix* mtx, f32 angle, u8 mode); +void Matrix_RotateAxis(Matrix* mtx, f32 angle, f32 axisX, f32 axisY, f32 axisZ, u8 mode); +void Matrix_ToMtx(Mtx* dest); +void Matrix_FromMtx(Mtx* src, Matrix* dest); +void Matrix_MultVec3f(Matrix* mtx, Vec3f* src, Vec3f* dest); +void Matrix_MultVec3fNoTranslate(Matrix* mtx, Vec3f* src, Vec3f* dest); +void Matrix_GetYRPAngles(Matrix* mtx, Vec3f* rot); +void Matrix_GetXYZAngles(Matrix* mtx, Vec3f* rot); +void Matrix_LookAt(Matrix* mtx, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f32 xUp, f32 yUp, f32 zUp, + u8 mode); +void Matrix_SetGfxMtx(Gfx** gfx); +void Lights_SetOneLight(Gfx** dList, s32 dirX, s32 dirY, s32 dirZ, s32 colR, s32 colG, s32 colB, s32 ambR, s32 ambG, s32 ambB); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/port/resource/importers/AudioBankFactory.cpp b/src/port/resource/importers/AudioBankFactory.cpp index ee400c1b5..650767881 100644 --- a/src/port/resource/importers/AudioBankFactory.cpp +++ b/src/port/resource/importers/AudioBankFactory.cpp @@ -21,6 +21,7 @@ SM64::AudioBankFactoryV0::ReadResource(std::shared_ptr file, auto* instrument = new Instrument(); bool valid = reader->ReadUByte(); if(!valid){ + delete instrument; bank->instruments.push_back(nullptr); continue; } diff --git a/src/port/resource/type/AudioBank.cpp b/src/port/resource/type/AudioBank.cpp index f91b767d2..7cbe3073a 100644 --- a/src/port/resource/type/AudioBank.cpp +++ b/src/port/resource/type/AudioBank.cpp @@ -8,4 +8,21 @@ CtlEntry* AudioBank::GetPointer() { size_t AudioBank::GetPointerSize() { return sizeof(mData); } +AudioBank::~AudioBank() { + for (auto& instrument : instruments) { + if (instrument != nullptr) { + if (instrument->envelope != nullptr) { + delete[] instrument->envelope; + instrument->envelope = nullptr; + } + delete instrument; + } + + } + for (auto& drum : drums) { + delete drum; + } + instruments.clear(); + drums.clear(); +} } \ No newline at end of file diff --git a/src/port/resource/type/AudioBank.h b/src/port/resource/type/AudioBank.h index a8541fe84..b9beefa78 100644 --- a/src/port/resource/type/AudioBank.h +++ b/src/port/resource/type/AudioBank.h @@ -47,6 +47,7 @@ class AudioBank : public Ship::Resource { using Resource::Resource; AudioBank() : Resource(std::shared_ptr()) {} + ~AudioBank() override; CtlEntry* GetPointer(); size_t GetPointerSize(); diff --git a/src/port/resource/type/AudioSample.cpp b/src/port/resource/type/AudioSample.cpp index cbdbd6573..f9b087af7 100644 --- a/src/port/resource/type/AudioSample.cpp +++ b/src/port/resource/type/AudioSample.cpp @@ -8,4 +8,18 @@ AudioBankSample* AudioSample::GetPointer() { size_t AudioSample::GetPointerSize() { return sizeof(mData); } +AudioSample::~AudioSample() { + if (mData.sampleAddr != nullptr) { + // delete[] mData.sampleAddr; + mData.sampleAddr = nullptr; + } + if (mData.book->book != nullptr) { + delete[] mData.book->book; + mData.book->book = nullptr; + } + if (mData.loop->state != nullptr) { + delete[] mData.loop->state; + mData.loop->state = nullptr; + } +} } \ No newline at end of file diff --git a/src/port/resource/type/AudioSample.h b/src/port/resource/type/AudioSample.h index 35f1d8d33..2d6f46c96 100644 --- a/src/port/resource/type/AudioSample.h +++ b/src/port/resource/type/AudioSample.h @@ -34,6 +34,7 @@ class AudioSample : public Ship::Resource { using Resource::Resource; AudioSample() : Resource(std::shared_ptr()) {} + ~AudioSample() override; AudioBankSample* GetPointer(); size_t GetPointerSize(); diff --git a/src/port/ui/ContentBrowser.cpp b/src/port/ui/ContentBrowser.cpp index 826477ea5..5390d8a9d 100644 --- a/src/port/ui/ContentBrowser.cpp +++ b/src/port/ui/ContentBrowser.cpp @@ -147,12 +147,13 @@ namespace Editor { } } + // When resetting the known content, we need to also pop the custom courses + // out of World::Courses vector. Otherwise, duplicate courses would show up for users. void ContentBrowserWindow::RemoveCustomTracksFromTrackList() { for (auto& track : Tracks) { auto it = gWorldInstance.Courses.begin(); while (it != gWorldInstance.Courses.end()) { - if (track.course == *it) { - delete *it; + if (track.course == it->get()) { it = gWorldInstance.Courses.erase(it); } else { ++it; @@ -233,27 +234,31 @@ namespace Editor { std::string name = dir.substr(dir.find_last_of('/') + 1); std::string sceneFile = dir + "/scene.json"; std::string minimapFile = dir + "/minimap.png"; + // The track has a valid scene file if (manager->HasFile(sceneFile)) { auto archive = manager->GetArchiveFromFile(sceneFile); - Course* course = new Course(); + auto course = std::make_unique(); course->LoadO2R(dir); - gWorldInstance.Courses.push_back(course); - LoadLevel(archive, course, sceneFile); - LoadMinimap(archive, course, minimapFile); - Tracks.push_back({course, sceneFile, name, dir, archive}); - } else { + gWorldInstance.Courses.push_back(std::move(course)); + LoadLevel(archive, course.get(), sceneFile); + LoadMinimap(archive, course.get(), minimapFile); + Tracks.push_back({course.get(), sceneFile, name, dir, archive}); + } else { // The track does not have a valid scene file const std::string file = dir + "/data_track_sections"; + // If the track has a data_track_sections file, + // then it must at least be a valid track. + // So lets add it as an uninitialized track. if (manager->HasFile(file)) { - Course* course = new Course(); + auto course = std::make_unique(); course->Id = (std::string("mods:") + name).c_str(); course->Props.SetText(course->Props.Name, name.c_str(), sizeof(course->Props.Name)); course->Props.SetText(course->Props.DebugName, name.c_str(), sizeof(course->Props.Name)); auto archive = manager->GetArchiveFromFile(file); - Tracks.push_back({course, "", name, dir, archive}); + Tracks.push_back({course.get(), "", name, dir, archive}); } else { printf("ContentBrowser.cpp: Track '%s' missing required track files. Cannot add to game\n Missing %s/data_track_sections file\n", name.c_str(), dir.c_str()); } diff --git a/src/port/ui/PortMenu.cpp b/src/port/ui/PortMenu.cpp index b21ddc1fa..3c2e61db2 100644 --- a/src/port/ui/PortMenu.cpp +++ b/src/port/ui/PortMenu.cpp @@ -15,10 +15,10 @@ #endif extern "C" { - extern s32 gGamestateNext; - extern s32 gMenuSelection; - #include "audio/external.h" - #include "defines.h" +extern s32 gGamestateNext; +extern s32 gMenuSelection; +#include "audio/external.h" +#include "defines.h" } namespace GameUI { @@ -158,9 +158,8 @@ void PortMenu::AddSettings() { .IsPercentage()); AddWidget(path, "Main Music Volume: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gMainMusicVolume") - .Callback([](WidgetInfo& info) { - audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f)); - }) + .Callback( + [](WidgetInfo& info) { audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f)); }) .Options(FloatSliderOptions() .Tooltip("Adjust the background music volume.") .ShowButtons(false) @@ -168,16 +167,17 @@ void PortMenu::AddSettings() { .IsPercentage()); AddWidget(path, "Sound Effects Volume: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gSFXMusicVolume") - .Callback([](WidgetInfo& info) { - audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); - }) - .Options( - FloatSliderOptions().Tooltip("Adjust the sound effects volume.").ShowButtons(false).Format("").IsPercentage()); + .Callback( + [](WidgetInfo& info) { audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); }) + .Options(FloatSliderOptions() + .Tooltip("Adjust the sound effects volume.") + .ShowButtons(false) + .Format("") + .IsPercentage()); AddWidget(path, "Sound Effects Volume: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gEnvironmentVolume") - .Callback([](WidgetInfo& info) { - audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f)); - }) + .Callback( + [](WidgetInfo& info) { audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f)); }) .Options(FloatSliderOptions() .Tooltip("Adjust the environment volume.") .ShowButtons(false) @@ -244,25 +244,25 @@ void PortMenu::AddSettings() { .DefaultValue(1)); #endif - // AddWidget(path, "Current FPS: %d", WIDGET_CVAR_SLIDER_INT) - // .CVar("gInterpolationFPS") - // .Callback([](WidgetInfo& info) { - // int32_t defaultValue = std::static_pointer_cast(info.options)->defaultValue; - // if (CVarGetInteger(info.cVar, defaultValue) == defaultValue) { - // info.name = "Current FPS: Original (%d)"; - // } else { - // info.name = "Current FPS: %d"; - // } - // }) - // .PreFunc([](WidgetInfo& info) { - // if (mPortMenu->disabledMap.at(DISABLE_FOR_MATCH_REFRESH_RATE_ON).active) - // info.activeDisables.push_back(DISABLE_FOR_MATCH_REFRESH_RATE_ON); - // }) - // .Options(IntSliderOptions().Tooltip(tooltip).Min(20).Max(maxFps).DefaultValue(20)); + AddWidget(path, "Current FPS: %d", WIDGET_CVAR_SLIDER_INT) + .CVar("gInterpolationFPS") + .Callback([](WidgetInfo& info) { + int32_t defaultValue = std::static_pointer_cast(info.options)->defaultValue; + if (CVarGetInteger(info.cVar, defaultValue) == defaultValue) { + info.name = "Current FPS: Original (%d)"; + } else { + info.name = "Current FPS: %d"; + } + }) + .PreFunc([](WidgetInfo& info) { + if (mPortMenu->disabledMap.at(DISABLE_FOR_MATCH_REFRESH_RATE_ON).active) + info.activeDisables.push_back(DISABLE_FOR_MATCH_REFRESH_RATE_ON); + }) + .Options(IntSliderOptions().Tooltip(tooltip).Min(30).Max(maxFps).DefaultValue(30)); AddWidget(path, "Match Refresh Rate", WIDGET_BUTTON) .Callback([](WidgetInfo& info) { int hz = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); - if (hz >= 20 && hz <= 360) { + if (hz >= 30 && hz <= 360) { CVarSetInteger("gInterpolationFPS", hz); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); } @@ -332,31 +332,36 @@ void PortMenu::AddEnhancements() { AddMenuEntry("Enhancements", "gSettings.Menu.EnhancementsSidebarSection"); WidgetPath path = { "Enhancements", "General", SECTION_COLUMN_1 }; AddSidebarEntry("Enhancements", "General", 3); - //UIWidgets::WindowButton("Multiplayer", "gMultiplayerWindowEnabled", GameUI::mMultiplayerWindow, - // { .tooltip = "Shows the multiplayer window" }); - // UIWidgets::WindowButton("Freecam", "gFreecam", GameUI::mFreecamWindow, - // { .tooltip = "Allows you to fly around the course" }); + // UIWidgets::WindowButton("Multiplayer", "gMultiplayerWindowEnabled", GameUI::mMultiplayerWindow, + // { .tooltip = "Shows the multiplayer window" }); + // UIWidgets::WindowButton("Freecam", "gFreecam", GameUI::mFreecamWindow, + // { .tooltip = "Allows you to fly around the course" }); AddWidget(path, "No multiplayer feature cuts", WIDGET_CVAR_CHECKBOX) .CVar("gMultiplayerNoFeatureCuts") .Options(CheckboxOptions().Tooltip("Allows full train and jumbotron in multiplayer, etc.")); AddWidget(path, "General Improvements", WIDGET_CVAR_CHECKBOX) - .CVar("gImprovements").Options(CheckboxOptions().Tooltip("General improvements to the game experience.")); + .CVar("gImprovements") + .Options(CheckboxOptions().Tooltip("General improvements to the game experience.")); AddWidget(path, "No Level of Detail (LOD)", WIDGET_CVAR_CHECKBOX) .CVar("gDisableLod") - .Options(CheckboxOptions().Tooltip("Disable Level of Detail (LOD) to avoid models using lower poly versions at a distance")); + .Options(CheckboxOptions().Tooltip( + "Disable Level of Detail (LOD) to avoid models using lower poly versions at a distance")); AddWidget(path, "Disable Culling", WIDGET_CVAR_CHECKBOX) - .CVar("gNoCulling").Options(CheckboxOptions().Tooltip("Disable original culling of mk64")); + .CVar("gNoCulling") + .Options(CheckboxOptions().Tooltip("Disable original culling of mk64")); AddWidget(path, "Far Frustrum", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gFarFrustrum") - .Options(FloatSliderOptions().Min(0.0f).Max(10000.0f).DefaultValue(10000.0f) - .Tooltip("Say how Far the Frustrum are when 'Disable Culling' are enable").Step(10.0f)); + .Options(FloatSliderOptions() + .Min(0.0f) + .Max(10000.0f) + .DefaultValue(10000.0f) + .Tooltip("Say how Far the Frustrum are when 'Disable Culling' are enable") + .Step(10.0f)); path = { "Enhancements", "Cheats", SECTION_COLUMN_1 }; AddSidebarEntry("Enhancements", "Cheats", 3); - AddWidget(path, "Moon Jump", WIDGET_CVAR_CHECKBOX) - .CVar("gEnableMoonJump"); - AddWidget(path, "Enable Custom CC", WIDGET_CVAR_CHECKBOX) - .CVar("gEnableCustomCC"); + AddWidget(path, "Moon Jump", WIDGET_CVAR_CHECKBOX).CVar("gEnableMoonJump"); + AddWidget(path, "Enable Custom CC", WIDGET_CVAR_CHECKBOX).CVar("gEnableCustomCC"); AddWidget(path, "Custom CC", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gCustomCC") .Options(FloatSliderOptions().Min(0.0f).Max(1000.0f).DefaultValue(150.0f).Step(10.0f)); @@ -365,21 +370,23 @@ void PortMenu::AddEnhancements() { .Options(CheckboxOptions().Tooltip("Disable wall collision.")); AddWidget(path, "Min Height", WIDGET_CVAR_SLIDER_FLOAT) .CVar("gMinHeight") - .Options(FloatSliderOptions().Min(-50.0f).Max(50.0f).DefaultValue(0.0f) - .Tooltip("When Disable Wall Collision are enable what is the minimal height you can get.")); + .Options(FloatSliderOptions().Min(-50.0f).Max(50.0f).DefaultValue(0.0f).Tooltip( + "When Disable Wall Collision are enable what is the minimal height you can get.")); +#if not defined(__SWITCH__) and not defined(__WIIU__) path = { "Enhancements", "HM64 Lab", SECTION_COLUMN_1 }; AddSidebarEntry("Enhancements", "HM64 Lab", 4); AddWidget(path, "Enable HM64 Labs", WIDGET_CVAR_CHECKBOX) - .CVar("gEditorEnabled") - .Callback([](WidgetInfo& info) { - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Tools")->ToggleVisibility(); - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Scene Explorer")->ToggleVisibility(); - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Content Browser")->ToggleVisibility(); - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Track Properties")->ToggleVisibility(); - Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Properties")->ToggleVisibility(); - }) - .Options(UIWidgets::CheckboxOptions({{ .tooltip = "Edit the universe!"}})); + .CVar("gEditorEnabled") + .Callback([](WidgetInfo& info) { + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Tools")->ToggleVisibility(); + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Scene Explorer")->ToggleVisibility(); + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Content Browser")->ToggleVisibility(); + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Track Properties")->ToggleVisibility(); + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Properties")->ToggleVisibility(); + }) + .Options(UIWidgets::CheckboxOptions({ { .tooltip = "Edit the universe!" } })); +#endif } #ifdef __SWITCH__ @@ -400,11 +407,11 @@ void PortMenu::AddDevTools() { WidgetPath path = { "Developer", "General", SECTION_COLUMN_1 }; #ifdef __SWITCH__ AddWidget(path, "Switch CPU Profile", WIDGET_CVAR_COMBOBOX) - .CVar("gSwitchPerfMode") - .Options(ComboboxOptions() - .Tooltip("Switches the CPU profile to a different one") - .ComboMap(switchCPUProfiles) - .DefaultIndex(Ship::SwitchProfiles::STOCK)) + .CVar("gSwitchPerfMode") + .Options(ComboboxOptions() + .Tooltip("Switches the CPU profile to a different one") + .ComboMap(switchCPUProfiles) + .DefaultIndex(Ship::SwitchProfiles::STOCK)) .Callback([](WidgetInfo& info) { Ship::Switch::ApplyOverclock(); }); #endif AddWidget(path, "Popout Menu", WIDGET_CVAR_CHECKBOX) @@ -413,6 +420,17 @@ void PortMenu::AddDevTools() { AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX) .CVar("gEnableDebugMode") .Options(CheckboxOptions().Tooltip("Enables Debug Mode.")); + AddWidget(path, "Modify Interpolation Target FPS", WIDGET_CVAR_CHECKBOX) + .CVar("gModifyInterpolationTargetFPS") + .Options(CheckboxOptions().Tooltip("Enables Debug Mode.")); + AddWidget(path, "Interpolation Target FPS", WIDGET_CVAR_SLIDER_INT) + .CVar("gInterpolationTargetFPS") + .PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger("gModifyInterpolationTargetFPS", 0); }) + .Options(IntSliderOptions() + .Tooltip("Sets the target FPS for interpolation. When Modify Interpolation Target FPS are enable") + .Min(15) + .Max(360) + .DefaultValue(60)); AddWidget(path, "Render Collision", WIDGET_CVAR_CHECKBOX) .CVar("gRenderCollisionMesh") .Options(CheckboxOptions().Tooltip("Renders the collision mesh instead of the course mesh")); @@ -429,7 +447,8 @@ void PortMenu::AddDevTools() { AddSidebarEntry("Developer", "Stats", 1); AddWidget(path, "Popout Stats", WIDGET_WINDOW_BUTTON) .CVar("gStatsEnabled") - .Options(ButtonOptions().Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on")) + .Options(ButtonOptions().Tooltip( + "Shows the stats window, with your FPS and frametimes, and the OS you're playing on")) .WindowName("Stats"); path = { "Developer", "Console", SECTION_COLUMN_1 }; @@ -445,9 +464,9 @@ PortMenu::PortMenu(const std::string& consoleVariable, const std::string& name) : Menu(consoleVariable, name, 0, UIWidgets::Colors::LightBlue) { } -//bool CheckNetworkConnected(disabledInfo& info) { -// return gNetwork.isConnected; -//} +// bool CheckNetworkConnected(disabledInfo& info) { +// return gNetwork.isConnected; +// } void PortMenu::InitElement() { Ship::Menu::InitElement(); @@ -531,4 +550,4 @@ void PortMenu::Draw() { void PortMenu::DrawElement() { Ship::Menu::DrawElement(); } -} // namespace BenGui +} // namespace GameUI diff --git a/src/racing/actors.c b/src/racing/actors.c index 9344bd3eb..137e3556e 100644 --- a/src/racing/actors.c +++ b/src/racing/actors.c @@ -34,6 +34,7 @@ #include #include #include "port/Game.h" +#include "port/interpolation/FrameInterpolation.h" // Appears to be textures // or tluts @@ -509,6 +510,7 @@ void render_cows(Camera* camera, Mat4 arg1) { gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_TEX_EDGE, G_RM_AA_ZB_TEX_EDGE2); var_s5 = NULL; var_s1 = var_t1; + while (var_s1->pos[0] != END_OF_SPAWN_DATA) { sp88[0] = var_s1->pos[0] * gCourseDirection; sp88[1] = var_s1->pos[1]; @@ -523,6 +525,12 @@ void render_cows(Camera* camera, Mat4 arg1) { arg1[3][0] = sp88[0]; arg1[3][1] = sp88[1]; arg1[3][2] = sp88[2]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("render_actor_cow", ((var_s1->pos[0] & 0xFFFF) << 32) | + ((var_s1->pos[1] & 0xFFFF) << 16) | + (var_s1->pos[2] & 0xFFFF)); + if ((gMatrixObjectCount < MTX_OBJECT_POOL_SIZE) && (render_set_position(arg1, 0) != 0)) { switch (var_s1->someId) { case 0: @@ -544,6 +552,9 @@ void render_cows(Camera* camera, Mat4 arg1) { } else { return; } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } var_s1++; } @@ -654,6 +665,11 @@ void render_palm_trees(Camera* camera, Mat4 arg1) { continue; } + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("render_actor_cow", ((var_s1->pos[0] & 0xFFFF) << 32) | + ((var_s1->pos[1] & 0xFFFF) << 16) | + (var_s1->pos[2] & 0xFFFF)); + test &= 0xF; test = (s16) test; if (test == 6) { @@ -690,6 +706,8 @@ void render_palm_trees(Camera* camera, Mat4 arg1) { } var_s1++; } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } @@ -708,6 +726,9 @@ void render_actor_shell(Camera* camera, Mat4 matrix, struct ShellActor* shell) { // Is it doing this by modifying a an address? uintptr_t phi_t3; + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Shell", TAG_ITEM_ADDR(shell)); + f32 temp_f0 = is_within_render_distance(camera->pos, shell->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 490000.0f); if (CVarGetInteger("gNoCulling", 0) == 1) { @@ -749,6 +770,9 @@ void render_actor_shell(Camera* camera, Mat4 matrix, struct ShellActor* shell) { } else { gSPDisplayList(gDisplayListHead++, D_0D005368); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } UNUSED s16 D_802B8808[] = { 0x0014, 0x0028, 0x0000, 0x0000 }; @@ -920,15 +944,15 @@ void spawn_foliage(struct ActorSpawnData* actor) { position[2] = var_s3->pos[2]; position[1] = var_s3->pos[1]; - if (GetCourse() == GetMarioRaceway()) { + if (IsMarioRaceway()) { actorType = 2; - } else if (GetCourse() == GetBowsersCastle()) { + } else if (IsBowsersCastle()) { actorType = 0x0021; - } else if (GetCourse() == GetYoshiValley()) { + } else if (IsYoshiValley()) { actorType = 3; - } else if (GetCourse() == GetFrappeSnowland()) { + } else if (IsFrappeSnowland()) { actorType = 0x001D; - } else if (GetCourse() == GetRoyalRaceway()) { + } else if (IsRoyalRaceway()) { switch (var_s3->signedSomeId) { case 6: actorType = 0x001C; @@ -937,11 +961,11 @@ void spawn_foliage(struct ActorSpawnData* actor) { actorType = 4; break; } - } else if (GetCourse() == GetLuigiRaceway()) { + } else if (IsLuigiRaceway()) { actorType = 0x001A; - } else if (GetCourse() == GetMooMooFarm()) { + } else if (IsMooMooFarm()) { actorType = 0x0013; - } else if (GetCourse() == GetKalimariDesert()) { + } else if (IsKalimariDesert()) { switch (var_s3->signedSomeId) { case 5: actorType = 0x001E; @@ -1682,8 +1706,8 @@ bool collision_tree(Player* player, struct Actor* actor) { actorPos[0] = actor->pos[0]; actorPos[1] = actor->pos[1]; actorPos[2] = actor->pos[2]; - if (((GetCourse() == GetMarioRaceway()) || (GetCourse() == GetYoshiValley()) || - (GetCourse() == GetRoyalRaceway()) || (GetCourse() == GetLuigiRaceway())) && + if (((IsMarioRaceway()) || (IsYoshiValley()) || + (IsRoyalRaceway()) || (IsLuigiRaceway())) && (player->unk_094 > 1.0f)) { spawn_leaf(actorPos, 0); } @@ -2437,11 +2461,15 @@ void render_course_actors(struct UnkStruct_800DC5EC* arg0) { if (actor->flags == 0) { continue; } + + FrameInterpolation_RecordOpenChild(actor, i); + switch (actor->type) { default: // Draw custom actor CM_DrawActors(D_800DC5EC->camera, actor); break; case ACTOR_TREE_MARIO_RACEWAY: + render_actor_tree_mario_raceway(camera, sBillBoardMtx, actor); break; case ACTOR_TREE_YOSHI_VALLEY: @@ -2541,10 +2569,11 @@ void render_course_actors(struct UnkStruct_800DC5EC* arg0) { render_actor_yoshi_egg(camera, sBillBoardMtx, (struct YoshiValleyEgg*) actor, pathCounter); break; } + FrameInterpolation_RecordCloseChild(); } - if (GetCourse() == GetMooMooFarm()) { + if (IsMooMooFarm()) { render_cows(camera, sBillBoardMtx); - } else if (GetCourse() == GetDkJungle()) { + } else if (IsDkJungle()) { render_palm_trees(camera, sBillBoardMtx); } } @@ -2645,7 +2674,7 @@ void update_course_actors(void) { } const char* get_actor_name(s32 id) { - switch(id) { + switch (id) { case ACTOR_FALLING_ROCK: return "Falling Rock"; case ACTOR_GREEN_SHELL: diff --git a/src/racing/framebuffer_effects.c b/src/racing/framebuffer_effects.c index 9a166b448..8c27cade6 100644 --- a/src/racing/framebuffer_effects.c +++ b/src/racing/framebuffer_effects.c @@ -3,6 +3,7 @@ #include "mk64.h" #include #include "port/Engine.h" +#include "port/interpolation/matrix.h" #include "math_util.h" #include diff --git a/src/racing/math_util.c b/src/racing/math_util.c index ac34ceda7..55c953a1f 100644 --- a/src/racing/math_util.c +++ b/src/racing/math_util.c @@ -8,16 +8,18 @@ #include "math.h" #include "memory.h" #include "engine/Matrix.h" +#include "course.h" #include "port/Game.h" - +#include +#include #pragma intrinsic(sqrtf, fabs) s32 D_802B91C0[2] = { 13, 13 }; Vec3f D_802B91C8 = { 0.0f, 0.0f, 0.0f }; -Mtx gIdentityMatrix = { - toFixedPointMatrix(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0), -}; +// Mtx gIdentityMatrix = { +// toFixedPointMatrix(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0), +// }; // This functions looks similar to a segment of code from func_802A4A0C in skybox_and_splitscreen.c UNUSED s32 func_802B4F60(UNUSED s32 arg0, Vec3f arg1, UNUSED s32 arg2, UNUSED f32 arg3, UNUSED f32 arg4) { @@ -53,7 +55,7 @@ s32 render_set_position(Mat4 mtx, s32 arg1) { if (gMatrixObjectCount >= MTX_OBJECT_POOL_SIZE) { return 0; } - //mtxf_to_mtx(&gGfxPool->mtxObject[gMatrixObjectCount], arg0); + // mtxf_to_mtx(&gGfxPool->mtxObject[gMatrixObjectCount], arg0); switch (arg1) { /* irregular */ case 0: AddObjectMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); @@ -188,6 +190,7 @@ void mtxf_identity(Mat4 mtx) { // Add a translation vector to a matrix, mat is the matrix to add, dest is the destination matrix, pos is the // translation vector void add_translate_mat4_vec3f(Mat4 mat, Mat4 dest, Vec3f pos) { + FrameInterpolation_RecordMatrixTranslate(dest, pos); dest[3][0] = mat[3][0] + pos[0]; dest[3][1] = mat[3][1] + pos[1]; dest[3][2] = mat[3][2] + pos[2]; @@ -222,6 +225,7 @@ UNUSED void add_translate_mat4_vec3f_lite(Mat4 mat, Mat4 dest, Vec3f pos) { // create a translation matrix void mtxf_translate(Mat4 dest, Vec3f b) { + FrameInterpolation_RecordMatrixTranslate(dest, b); mtxf_identity(dest); dest[3][0] = b[0]; dest[3][1] = b[1]; @@ -329,6 +333,7 @@ void func_802B5794(Mat4 mtx, Vec3f from, Vec3f to) { // create a rotation matrix around the x axis void mtxf_rotate_x(Mat4 mat, s16 angle) { + FrameInterpolation_RecordMatrixRotate1Coord(&mat, 0, angle); f32 sin_theta = sins(angle); f32 cos_theta = coss(angle); @@ -348,6 +353,7 @@ void mtxf_rotate_x(Mat4 mat, s16 angle) { // create a rotation matrix around the y axis void mtxf_rotate_y(Mat4 mat, s16 angle) { + FrameInterpolation_RecordMatrixRotate1Coord(&mat, 1, angle); f32 sin_theta = sins(angle); f32 cos_theta = coss(angle); @@ -367,6 +373,7 @@ void mtxf_rotate_y(Mat4 mat, s16 angle) { // create a rotation matrix around the z axis void mtxf_s16_rotate_z(Mat4 mat, s16 angle) { + FrameInterpolation_RecordMatrixRotate1Coord(&mat, 2, angle); f32 sin_theta = sins(angle); f32 cos_theta = coss(angle); @@ -384,39 +391,6 @@ void mtxf_s16_rotate_z(Mat4 mat, s16 angle) { */ } -void func_802B5B14(Vec3f b, Vec3s rotate) { - Mat4 mtx; - Vec3f copy; - - f32 sx = sins(rotate[0]); - f32 cx = coss(rotate[0]); - - f32 sy = sins(rotate[1]); - f32 cy = coss(rotate[1]); - - f32 sz = sins(rotate[2]); - f32 cz = coss(rotate[2]); - - copy[0] = b[0]; - copy[1] = b[1]; - - mtx[0][0] = cy * cz + sx * sy * sz; - mtx[1][0] = -cy * sz + sx * sy * cz; - mtx[2][0] = cx * sy; - - mtx[0][1] = cx * sz; - mtx[1][1] = cx * cz; - mtx[2][1] = -sx; - - mtx[0][2] = -sy * cz + sx * cy * sz; - mtx[1][2] = sy * sz + sx * cy * cz; - mtx[2][2] = cx * cy; - - b[0] = copy[0] * mtx[0][0] + copy[1] * mtx[0][1] + copy[1] * mtx[0][2]; - b[1] = copy[0] * mtx[1][0] + copy[1] * mtx[1][1] + copy[1] * mtx[1][2]; - b[2] = copy[0] * mtx[2][0] + copy[1] * mtx[2][1] + copy[1] * mtx[2][2]; -} - void func_802B5CAC(s16 arg0, s16 arg1, Vec3f arg2) { f32 sp2C = sins(arg1); f32 sp28 = coss(arg1); @@ -460,6 +434,7 @@ void set_track_light_direction(Lights1* addr, s16 pitch, s16 yaw, s32 numLights) // multiply a matrix with a number void mtxf_scale(Mat4 mat, f32 coef) { + FrameInterpolation_RecordMatrixScale(mat, coef); mat[0][0] *= coef; mat[1][0] *= coef; mat[2][0] *= coef; @@ -479,6 +454,7 @@ void mtxf_pos_rotation_xyz(Mat4 out, Vec3f pos, Vec3s orientation) { f32 cosine2; f32 sine3; f32 cosine3; + FrameInterpolation_RecordMatrixPosRotXYZ(out, pos, orientation); sine1 = sins(orientation[0]); cosine1 = coss(orientation[0]); @@ -623,7 +599,9 @@ void func_802B64C4(Vec3f arg0, s16 arg1) { arg0[2] = sp2C * temp1 + (temp_f0 * temp3); } -void calculate_orientation_matrix(Mat3 dest, f32 arg1, f32 arg2, f32 arg3, s16 rotationAngle) { +// Rotates the object around the Y axis. +// x,y,z is a direction (not a rotator). +void calculate_orientation_matrix(Mat3 dest, f32 x, f32 y, f32 z, s16 rotationAngle) { Mat3 mtx_rot_y; Mat3 matrix; s32 i, j; @@ -634,6 +612,7 @@ void calculate_orientation_matrix(Mat3 dest, f32 arg1, f32 arg2, f32 arg3, s16 r UNUSED s32 pad[3]; f32 sinValue; f32 cossValue; + FrameInterpolation_RecordCalculateOrientationMatrix(dest, x, y, z, rotationAngle); sinValue = sins(rotationAngle); cossValue = coss(rotationAngle); @@ -649,7 +628,7 @@ void calculate_orientation_matrix(Mat3 dest, f32 arg1, f32 arg2, f32 arg3, s16 r mtx_rot_y[1][0] = 0; mtx_rot_y[0][1] = 0; - if (arg2 == 1) { // set matrix to identity + if (y == 1) { // set matrix to identity for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { @@ -657,7 +636,7 @@ void calculate_orientation_matrix(Mat3 dest, f32 arg1, f32 arg2, f32 arg3, s16 r } } - } else if (arg2 == -1) { // set matrix to identity with the second column negative + } else if (y == -1) { // set matrix to identity with the second column negative for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { @@ -668,10 +647,10 @@ void calculate_orientation_matrix(Mat3 dest, f32 arg1, f32 arg2, f32 arg3, s16 r matrix[1][1] = -1; } else { - a = (f32) - (360.0 - ((f64) (calculate_vector_angle_xy(arg2) * 180.0f) / M_PI)); - b = -arg3 / sqrtf((arg1 * arg1) + (arg3 * arg3)); + a = (f32) - (360.0 - ((f64) (calculate_vector_angle_xy(y) * 180.0f) / M_PI)); + b = -z / sqrtf((x * x) + (z * z)); c = 0; - d = arg1 / sqrtf((arg1 * arg1) + (arg3 * arg3)); + d = x / sqrtf((x * x) + (z * z)); calculate_rotation_matrix(matrix, a, b, c, d); } dest[0][0] = (mtx_rot_y[0][0] * matrix[0][0]) + (mtx_rot_y[0][1] * matrix[1][0]) + (mtx_rot_y[0][2] * matrix[2][0]); @@ -752,7 +731,7 @@ void calculate_rotation_matrix(Mat3 destMatrix, s16 rotationAngle, f32 rotationX destMatrix[0][1] = temp + (rotationZ * sinValue); } -void func_802B6BC0(Mat4 arg0, s16 arg1, f32 arg2, f32 arg3, f32 arg4) { +UNUSED void func_802B6BC0(Mat4 arg0, s16 arg1, f32 arg2, f32 arg3, f32 arg4) { f32 sine; f32 cosine; f32 temp_f0; @@ -823,40 +802,40 @@ void func_802B6D58(Mat4 arg0, Vec3f arg1, Vec3f arg2) { } void mtxf_multiplication(Mat4 dest, Mat4 mat1, Mat4 mat2) { - Mat4 product; - product[0][0] = + FrameInterpolation_RecordMatrixMult(dest, dest, 0); + + dest[0][0] = (mat1[0][0] * mat2[0][0]) + (mat1[0][1] * mat2[1][0]) + (mat1[0][2] * mat2[2][0]) + (mat1[0][3] * mat2[3][0]); - product[0][1] = + dest[0][1] = (mat1[0][0] * mat2[0][1]) + (mat1[0][1] * mat2[1][1]) + (mat1[0][2] * mat2[2][1]) + (mat1[0][3] * mat2[3][1]); - product[0][2] = + dest[0][2] = (mat1[0][0] * mat2[0][2]) + (mat1[0][1] * mat2[1][2]) + (mat1[0][2] * mat2[2][2]) + (mat1[0][3] * mat2[3][2]); - product[0][3] = + dest[0][3] = (mat1[0][0] * mat2[0][3]) + (mat1[0][1] * mat2[1][3]) + (mat1[0][2] * mat2[2][3]) + (mat1[0][3] * mat2[3][3]); - product[1][0] = + dest[1][0] = (mat1[1][0] * mat2[0][0]) + (mat1[1][1] * mat2[1][0]) + (mat1[1][2] * mat2[2][0]) + (mat1[1][3] * mat2[3][0]); - product[1][1] = + dest[1][1] = (mat1[1][0] * mat2[0][1]) + (mat1[1][1] * mat2[1][1]) + (mat1[1][2] * mat2[2][1]) + (mat1[1][3] * mat2[3][1]); - product[1][2] = + dest[1][2] = (mat1[1][0] * mat2[0][2]) + (mat1[1][1] * mat2[1][2]) + (mat1[1][2] * mat2[2][2]) + (mat1[1][3] * mat2[3][2]); - product[1][3] = + dest[1][3] = (mat1[1][0] * mat2[0][3]) + (mat1[1][1] * mat2[1][3]) + (mat1[1][2] * mat2[2][3]) + (mat1[1][3] * mat2[3][3]); - product[2][0] = + dest[2][0] = (mat1[2][0] * mat2[0][0]) + (mat1[2][1] * mat2[1][0]) + (mat1[2][2] * mat2[2][0]) + (mat1[2][3] * mat2[3][0]); - product[2][1] = + dest[2][1] = (mat1[2][0] * mat2[0][1]) + (mat1[2][1] * mat2[1][1]) + (mat1[2][2] * mat2[2][1]) + (mat1[2][3] * mat2[3][1]); - product[2][2] = + dest[2][2] = (mat1[2][0] * mat2[0][2]) + (mat1[2][1] * mat2[1][2]) + (mat1[2][2] * mat2[2][2]) + (mat1[2][3] * mat2[3][2]); - product[2][3] = + dest[2][3] = (mat1[2][0] * mat2[0][3]) + (mat1[2][1] * mat2[1][3]) + (mat1[2][2] * mat2[2][3]) + (mat1[2][3] * mat2[3][3]); - product[3][0] = + dest[3][0] = (mat1[3][0] * mat2[0][0]) + (mat1[3][1] * mat2[1][0]) + (mat1[3][2] * mat2[2][0]) + (mat1[3][3] * mat2[3][0]); - product[3][1] = + dest[3][1] = (mat1[3][0] * mat2[0][1]) + (mat1[3][1] * mat2[1][1]) + (mat1[3][2] * mat2[2][1]) + (mat1[3][3] * mat2[3][1]); - product[3][2] = + dest[3][2] = (mat1[3][0] * mat2[0][2]) + (mat1[3][1] * mat2[1][2]) + (mat1[3][2] * mat2[2][2]) + (mat1[3][3] * mat2[3][2]); - product[3][3] = + dest[3][3] = (mat1[3][0] * mat2[0][3]) + (mat1[3][1] * mat2[1][3]) + (mat1[3][2] * mat2[2][3]) + (mat1[3][3] * mat2[3][3]); - mtxf_copy_n_element((s32*) dest, (s32*) product, 16); } /** @@ -1121,16 +1100,22 @@ s32 is_visible_between_angle(u16 arg0, u16 arg1, u16 arg2) { f32 is_within_render_distance(Vec3f cameraPos, Vec3f objectPos, u16 orientationY, f32 minDistance, f32 fov, f32 maxDistance) { u16 angleObject; - UNUSED u16 pad; u16 temp_v0; f32 distanceX; f32 distance; f32 distanceY; + f32 scaleFov; + f32 maxDistance2; s32 plus_fov_angle; s32 minus_fov_angle; u16 temp; - UNUSED s32 pad2[3]; - u16 extended_fov = ((u16) fov * 0xB6); + s32 count = 0; + + maxDistance *= 6.5f; + maxDistance2 = 1.0f; + scaleFov = 1.25; + + f32 extended_fov = ((f32) fov * 0xB6 * scaleFov); // Sets the Culling for objects on the left and right distanceX = objectPos[0] - cameraPos[0]; distanceX = distanceX * distanceX; @@ -1159,14 +1144,23 @@ f32 is_within_render_distance(Vec3f cameraPos, Vec3f objectPos, u16 orientationY if (minDistance == 0.0f) { if (is_visible_between_angle((orientationY + extended_fov), (orientationY - extended_fov), angleObject) == 1) { - return distance; + if (IsKalimariDesert()) { + return distance / 6.5f; // set for better DD settings in Desert + } else { + return distance / 10.0f; // Items + } } return -1.0f; } if (is_visible_between_angle((u16) plus_fov_angle, (u16) minus_fov_angle, angleObject) == 1) { - return distance; + if (IsKalimariDesert()) { + return distance / 2.0f; + } else { + return distance / 10.0f; // DD Vhicles + } } + temp_v0 = func_802B7CA8(minDistance / distance); temp = angleObject + temp_v0; diff --git a/src/racing/math_util.h b/src/racing/math_util.h index b767e9068..7c230ca87 100644 --- a/src/racing/math_util.h +++ b/src/racing/math_util.h @@ -10,6 +10,10 @@ // #define min(a, b) ((a) <= (b) ? (a) : (b)) // #define max(a, b) ((a) > (b) ? (a) : (b)) +#ifdef __cplusplus +extern "C" { +#endif + #define sqr(x) ((x) * (x)) // Here to appease the pragma gods @@ -38,7 +42,6 @@ void func_802B5794(Mat4, Vec3f, Vec3f); void mtxf_rotate_x(Mat4, s16); void mtxf_rotate_y(Mat4, s16); void mtxf_s16_rotate_z(Mat4, s16); -void func_802B5B14(Vec3f b, Vec3s rotate); // unused void func_802B5CAC(s16, s16, Vec3f); void func_802B5D30(s16, s16, s32); void set_track_light_direction(Lights1*, s16, s16, s32); @@ -70,6 +73,10 @@ f32 is_within_render_distance(Vec3f, Vec3f, u16, f32, f32, f32); extern s32 D_802B91C0[]; extern Vec3f D_802B91C8; -extern Mtx gIdentityMatrix; +//extern Mtx gIdentityMatrix; + +#ifdef __cplusplus +} +#endif #endif // MATH_UTIL_H diff --git a/src/racing/race_logic.c b/src/racing/race_logic.c index 4b9cf1af9..4247cd88c 100644 --- a/src/racing/race_logic.c +++ b/src/racing/race_logic.c @@ -418,7 +418,7 @@ void func_8028EC38(s32 arg0) { void func_8028EC98(s32 arg0) { - // We want music in mutilplayer + // We want music in multiplayer, so this was removed //if (gScreenModeSelection == SCREEN_MODE_3P_4P_SPLITSCREEN) { // return; //} @@ -897,9 +897,9 @@ void func_8028FCBC(void) { func_8028F914(); if (D_802BA034 == 1.0f) { if (gActiveScreenMode != SCREEN_MODE_1P) { - if (GetCourse() == GetLuigiRaceway()) { + if (IsLuigiRaceway()) { func_802A7940(); - } else if (GetCourse() == GetWarioStadium()) { + } else if (IsWarioStadium()) { func_802A7728(); } } @@ -909,7 +909,9 @@ void func_8028FCBC(void) { CM_SpawnStarterLakitu(); // func_80078F64(); if ((gModeSelection == TIME_TRIALS) && (D_80162DD6 == 0)) { phi_v0_4 = 0x1; - for (i = 0; i < gCurrentCourseId; i++) { + //! @warning this used to be < gCurrentCourseId + // Hopefully this is equivallent. + for (i = 0; i < GetCourseIndex(); i++) { phi_v0_4 <<= 1; } if ((D_8015F890 == 0) && (!(D_800DC5AC & phi_v0_4))) { diff --git a/src/racing/render_courses.c b/src/racing/render_courses.c index 71b182544..a94369e69 100644 --- a/src/racing/render_courses.c +++ b/src/racing/render_courses.c @@ -7,6 +7,7 @@ #include #include "../camera.h" #include "framebuffer_effects.h" +#include "port/interpolation/FrameInterpolation.h" #include "render_courses.h" #include "code_800029B0.h" @@ -132,7 +133,7 @@ void render_course_segments(const char* addr[], struct UnkStruct_800DC5EC* arg1) index = sp1E; } } else { - if (GetCourse() == GetBowsersCastle()) { + if (IsBowsersCastle()) { if ((temp_v0_3 >= 0x11) && (temp_v0_3 < 0x18)) { index = temp_v0_3; } else if ((temp_v0_3 == 255) && (sp1E != 255)) { @@ -142,7 +143,7 @@ void render_course_segments(const char* addr[], struct UnkStruct_800DC5EC* arg1) } else { index = arg1->pathCounter; } - } else if (GetCourse() == GetChocoMountain()) { + } else if (IsChocoMountain()) { if ((temp_v0_3 >= 0xE) && (temp_v0_3 < 0x16)) { index = temp_v0_3; } else if ((temp_v0_3 == 255) && (sp1E != 255)) { @@ -175,7 +176,7 @@ void render_course_segments(const char* addr[], struct UnkStruct_800DC5EC* arg1) index = ((index - 1) * 4) + direction; gSPDisplayList(gDisplayListHead++, addr[index]); - if (CVarGetInteger("gDisableLod", 1) == 1 && (GetCourse() == GetBowsersCastle()) && + if (CVarGetInteger("gDisableLod", 1) == 1 && (IsBowsersCastle()) && (index < 20 || index > 99)) { // always render higher version of bowser statue gDisplayListHead--; gSPDisplayList(gDisplayListHead++, d_course_bowsers_castle_dl_9148); // use credit version of the course @@ -240,9 +241,14 @@ void func_8029122C(struct UnkStruct_800DC5EC* arg0, s32 playerId) { G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); break; } + + FrameInterpolation_RecordOpenChild("track_water", playerId); + mtxf_identity(matrix); render_set_position(matrix, 0); + CM_DrawWater(arg0, pathCounter, cameraRot, playerDirection); + FrameInterpolation_RecordCloseChild(); // switch (gCurrentCourseId) { // case COURSE_BOWSER_CASTLE: // if (gActiveScreenMode != SCREEN_MODE_1P) { diff --git a/src/racing/skybox_and_splitscreen.c b/src/racing/skybox_and_splitscreen.c index 77b1c03ff..eecac8375 100644 --- a/src/racing/skybox_and_splitscreen.c +++ b/src/racing/skybox_and_splitscreen.c @@ -21,6 +21,8 @@ #include "engine/courses/Course.h" #include "port/Game.h" #include "math_util.h" +#include "src/enhancements/freecam/freecam.h" +#include "port/interpolation/FrameInterpolation.h" Vp D_802B8880[] = { { { { 640, 480, 511, 0 }, { 640, 480, 511, 0 } } }, @@ -397,11 +399,15 @@ void func_802A450C(Vtx* skybox) { skybox[7].v.cn[2] = prop->FloorTopLeft.b; } +Mtx gIdentityMatrix2 = { + toFixedPointMatrix(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0), +}; + void func_802A487C(Vtx* arg0, UNUSED struct UnkStruct_800DC5EC* arg1, UNUSED s32 arg2, UNUSED s32 arg3, UNUSED f32* arg4) { init_rdp(); - if (GetCourse() != GetRainbowRoad()) { + if (!IsRainbowRoad()) { gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER | G_LIGHTING); @@ -409,7 +415,7 @@ void func_802A487C(Vtx* arg0, UNUSED struct UnkStruct_800DC5EC* arg1, UNUSED s32 gSPPerspNormalize(gDisplayListHead++, 0xFFFF); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxScreen), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); - gSPMatrix(gDisplayListHead++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPMatrix(gDisplayListHead++, &gIdentityMatrix2, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPVertex(gDisplayListHead++, &arg0[4], 4, 0); gSP2Triangles(gDisplayListHead++, 0, 3, 1, 0, 1, 3, 2, 0); } @@ -476,10 +482,10 @@ void func_802A4A0C(Vtx* vtx, struct UnkStruct_800DC5EC* arg1, UNUSED s32 arg2, U gSPPerspNormalize(gDisplayListHead++, 0xFFFF); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxScreen), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); - gSPMatrix(gDisplayListHead++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPMatrix(gDisplayListHead++, &gIdentityMatrix2, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPVertex(gDisplayListHead++, &vtx[0], 4, 0); gSP2Triangles(gDisplayListHead++, 0, 3, 1, 0, 1, 3, 2, 0); - if (GetCourse() == GetRainbowRoad()) { + if (IsRainbowRoad()) { gSPVertex(gDisplayListHead++, &vtx[4], 4, 0); gSP2Triangles(gDisplayListHead++, 0, 3, 1, 0, 1, 3, 2, 0); } @@ -750,11 +756,35 @@ void func_802A5760(void) { } } -void render_screens(s32 mode, s32 cameraId, s32 playerId) { - UNUSED s32 pad[4]; +// Setup the cameras perspective and lookAt (movement/rotation) +void setup_camera(Camera* camera, s32 playerId, s32 cameraId, struct UnkStruct_800DC5EC* screen) { + Mat4 matrix; u16 perspNorm; - UNUSED s32 pad2[2]; - UNUSED s32 pad3; + + // This allows freecam to create a new separate camera + // if (CVarGetInteger("gFreecam", 0) == true) { + // freecam_render_setup(gFreecamCamera); + // return; + // } + + // Setup perspective (camera movement) + FrameInterpolation_RecordOpenChild("camera", + (FrameInterpolation_GetCameraEpoch() | (((playerId | cameraId) << 8)))); + guPerspective(&gGfxPool->mtxPersp[cameraId], &perspNorm, gCameraZoom[cameraId], gScreenAspect, + CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f); + gSPPerspNormalize(gDisplayListHead++, perspNorm); + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[cameraId]), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + + // Setup lookAt (camera rotation) + guLookAt(&gGfxPool->mtxLookAt[cameraId], camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0], + camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]); + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]), + G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + FrameInterpolation_RecordCloseChild(); +} + +void render_screens(s32 mode, s32 cameraId, s32 playerId) { Mat4 matrix; s32 screenId = 0; @@ -817,8 +847,16 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) { } struct UnkStruct_800DC5EC* screen = &D_8015F480[screenId]; - Camera* camera = &cameras[cameraId]; - + Camera* camera; + + // Required for freecam to have its own camera + //if (CVarGetInteger("gFreecam", 0) == true) { + // camera = &gFreecamCamera; + // cameraId = 4; + //} else { + camera = &cameras[cameraId]; + //} + if (screenMode == SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL) { gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH); } @@ -828,34 +866,21 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) { gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH); gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2); - guPerspective(&gGfxPool->mtxPersp[cameraId], &perspNorm, gCameraZoom[cameraId], gScreenAspect, - CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f); + // Setup camera perspective and lookAt + setup_camera(camera, playerId, cameraId, screen); - gSPPerspNormalize(gDisplayListHead++, perspNorm); - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[cameraId]), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + // Create a matrix for the track and game objects + FrameInterpolation_RecordOpenChild("track", (playerId | cameraId) << 8); + Mat4 trackMatrix; + mtxf_identity(trackMatrix); + render_set_position(trackMatrix, 0); - guLookAt(&gGfxPool->mtxLookAt[cameraId], camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0], - camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]); - if (D_800DC5C8 == 0) { - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]), - G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); - mtxf_identity(matrix); - render_set_position(matrix, 0); - } else { - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - } + // Draw course and game objects render_course(screen); - if (D_800DC5C8 == 1) { - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]), - G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); - mtxf_identity(matrix); - render_set_position(matrix, 0); - } render_course_actors(screen); CM_DrawStaticMeshActors(); render_object(mode); + switch (screenId) { case 0: render_players_on_screen_one(); @@ -902,6 +927,7 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) { if (mode != RENDER_SCREEN_MODE_1P_PLAYER_ONE) { gNumScreens += 1; } + FrameInterpolation_RecordCloseChild(); } void func_802A74BC(void) { diff --git a/src/render_objects.c b/src/render_objects.c index cd9d8bf76..7aa06dcaf 100644 --- a/src/render_objects.c +++ b/src/render_objects.c @@ -46,6 +46,8 @@ #include "engine/courses/Course.h" #include "engine/Matrix.h" +#include "port/interpolation/FrameInterpolation.h" + Lights1 D_800E45C0[] = { gdSPDefLights1(100, 0, 0, 100, 0, 0, 0, -120, 0), gdSPDefLights1(100, 100, 0, 255, 255, 0, 0, -120, 0), @@ -1679,7 +1681,7 @@ void render_texture_rectangle_wide_left(s32 x, s32 y, s32 width, s32 height, s32 if (gPlayerCount == 3) { // Center item in area of screen s32 center = (s32) ((OTRGetDimensionFromLeftEdge(SCREEN_WIDTH) - SCREEN_WIDTH) / 2) + - ((SCREEN_WIDTH / 4) + (SCREEN_WIDTH / 2)); + ((SCREEN_WIDTH / 4) + (SCREEN_WIDTH / 2)); s32 coordX = (s32) (center - (width / 2)) << 2; s32 coordX2 = (s32) (center + (width / 2)) << 2; gSPWideTextureRectangle(gDisplayListHead++, coordX, yl, coordX2, yh2, G_TX_RENDERTILE, arg4 << 5, @@ -2627,6 +2629,8 @@ void draw_simplified_lap_count(s32 playerId) { } void func_8004E800(s32 playerId) { + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Player place HUD", playerId); if (playerHUD[playerId].unk_81 != 0) { if (playerHUD[playerId].lapCount != 3) { func_8004A384(playerHUD[playerId].rankX + playerHUD[playerId].slideRankX, @@ -2642,6 +2646,8 @@ void func_8004E800(s32 playerId) { 0x00000040, 0x00000080, 0x00000040); } } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } void func_8004E998(s32 playerId) { @@ -2682,23 +2688,25 @@ void func_8004EB38(s32 playerId) { } if ((u8) temp_s0->unk_7E != 0) { func_8004C9D8_wide((s32) temp_s0->lapAfterImage1X, temp_s0->lapY + 3, 0x00000080, (u8*) common_texture_hud_lap, - 0x00000020, 8, 0x00000020, 8); + 0x00000020, 8, 0x00000020, 8); func_8004C9D8_wide(temp_s0->lapAfterImage1X + 0x1C, (s32) temp_s0->lapY, 0x00000080, - (u8*) gHudLapTextures[temp_s0->alsoLapCount], 0x00000020, 0x00000010, 0x00000020, 0x00000010); + (u8*) gHudLapTextures[temp_s0->alsoLapCount], 0x00000020, 0x00000010, 0x00000020, + 0x00000010); } if ((u8) temp_s0->unk_7F != 0) { func_8004C9D8_wide((s32) temp_s0->lapAfterImage2X, temp_s0->lapY + 3, 0x00000050, (u8*) common_texture_hud_lap, - 0x00000020, 8, 0x00000020, 8); + 0x00000020, 8, 0x00000020, 8); func_8004C9D8_wide(temp_s0->lapAfterImage2X + 0x1C, (s32) temp_s0->lapY, 0x00000050, - (u8*) gHudLapTextures[temp_s0->alsoLapCount], 0x00000020, 0x00000010, 0x00000020, 0x00000010); + (u8*) gHudLapTextures[temp_s0->alsoLapCount], 0x00000020, 0x00000010, 0x00000020, + 0x00000010); } } void func_8004ED40(s32 arg0) { func_8004A2F4(playerHUD[arg0].speedometerX, playerHUD[arg0].speedometerY, 0U, 1.0f, // RGBA - CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, 0xFF, - LOAD_ASSET(common_texture_speedometer), LOAD_ASSET(D_0D0064B0), 64, 96, 64, 48); + CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, + 0xFF, LOAD_ASSET(common_texture_speedometer), LOAD_ASSET(D_0D0064B0), 64, 96, 64, 48); func_8004A258(D_8018CFEC, D_8018CFF4, D_8016579E, 1.0f, common_texture_speedometer_needle, D_0D005FF0, 0x40, 0x20, 0x40, 0x20); } @@ -2708,14 +2716,14 @@ void func_8004EE54(s32 playerId) { if (gIsMirrorMode != 0) { func_8004D4E8(CM_GetProps()->Minimap.Pos[playerId].X, CM_GetProps()->Minimap.Pos[playerId].Y, (u8*) D_8018D240, // RGBA - CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, 0xFF, - CM_GetProps()->Minimap.Width, CM_GetProps()->Minimap.Height, CM_GetProps()->Minimap.Width, + CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, + 0xFF, CM_GetProps()->Minimap.Width, CM_GetProps()->Minimap.Height, CM_GetProps()->Minimap.Width, CM_GetProps()->Minimap.Height); } else { func_8004D37C(CM_GetProps()->Minimap.Pos[playerId].X, CM_GetProps()->Minimap.Pos[playerId].Y, (u8*) D_8018D240, // RGBA - CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, 0xFF, - CM_GetProps()->Minimap.Width, CM_GetProps()->Minimap.Height, CM_GetProps()->Minimap.Width, + CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, + 0xFF, CM_GetProps()->Minimap.Width, CM_GetProps()->Minimap.Height, CM_GetProps()->Minimap.Width, CM_GetProps()->Minimap.Height); } } @@ -2745,8 +2753,10 @@ void set_minimap_finishline_position(s32 playerId) { } // minimap center pos - minimap left edge + offset - var_f2 = (center - (CM_GetProps()->Minimap.Width / 2)) + CM_GetProps()->Minimap.PlayerX; // (center - (gMinimapWidth / 2)) + gMinimapPlayerX; - var_f0 = (CM_GetProps()->Minimap.Pos[playerId].Y - (CM_GetProps()->Minimap.Height / 2)) + CM_GetProps()->Minimap.PlayerY; // (gMinimapY[arg0] - (gMinimapHeight / 2)) + gMinimapPlayerY + var_f2 = (center - (CM_GetProps()->Minimap.Width / 2)) + + CM_GetProps()->Minimap.PlayerX; // (center - (gMinimapWidth / 2)) + gMinimapPlayerX; + var_f0 = (CM_GetProps()->Minimap.Pos[playerId].Y - (CM_GetProps()->Minimap.Height / 2)) + + CM_GetProps()->Minimap.PlayerY; // (gMinimapY[arg0] - (gMinimapHeight / 2)) + gMinimapPlayerY var_f2 += CM_GetProps()->Minimap.FinishlineX; var_f0 += CM_GetProps()->Minimap.FinishlineY; @@ -2780,7 +2790,8 @@ void func_8004F168(s32 arg0, s32 playerId, s32 characterId) { } temp_a0 = (center - (CM_GetProps()->Minimap.Width / 2)) + CM_GetProps()->Minimap.PlayerX + (s16) (thing0); - temp_a1 = (CM_GetProps()->Minimap.Pos[arg0].Y - (CM_GetProps()->Minimap.Height / 2)) + CM_GetProps()->Minimap.PlayerY + (s16) (thing1); + temp_a1 = (CM_GetProps()->Minimap.Pos[arg0].Y - (CM_GetProps()->Minimap.Height / 2)) + + CM_GetProps()->Minimap.PlayerY + (s16) (thing1); if (characterId != 8) { if ((gGPCurrentRaceRankByPlayerId[playerId] == 0) && (gModeSelection != 3) && (gModeSelection != 1)) { #if EXPLICIT_AND == 1 @@ -3002,7 +3013,7 @@ void draw_lap_count(s16 lapX, s16 lapY, s8 lap) { } void func_8004FDB4(f32 arg0, f32 arg1, s16 arg2, s16 arg3, s16 characterId, s32 arg5, s32 arg6, s32 arg7, s32 arg8) { - if ((GetCourse() == GetYoshiValley()) && (arg3 < 3) && (arg8 == 0)) { + if ((IsYoshiValley()) && (arg3 < 3) && (arg8 == 0)) { func_80042330((s32) arg0, (s32) arg1, 0U, 1.0f); gSPDisplayList(gDisplayListHead++, D_0D007DB8); func_8004B35C(0x000000FF, 0x000000FF, 0x000000FF, D_8018D3E0); @@ -3044,47 +3055,57 @@ void func_8004FDB4(f32 arg0, f32 arg1, s16 arg2, s16 arg3, s16 characterId, s32 void func_80050320(void) { s16 temp_v0; s16 characterId; - s32 var_s0; + s32 i; s32 lapCount; s32 var_a0; if (D_801657E2 == 0) { - for (var_s0 = 0; var_s0 < 4; var_s0++) { + for (i = 0; i < 4; i++) { var_a0 = 0; - if (D_8018D050[var_s0] >= 0.0f) { - if (D_8018D078[var_s0] < 0.0) { + if (D_8018D050[i] >= 0.0f) { + if (D_8018D078[i] < 0.0) { var_a0 = 1; } - temp_v0 = gGPCurrentRacePlayerIdByRank[var_s0]; - characterId = gGPCurrentRaceCharacterIdByRank[var_s0]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("ranking portraits", i | var_a0 << 16); + + temp_v0 = gGPCurrentRacePlayerIdByRank[i]; + characterId = gGPCurrentRaceCharacterIdByRank[i]; lapCount = gLapCountByPlayerId[temp_v0]; if (characterId == gPlayerOne->characterId) { - func_8004FDB4(D_8018D028[var_s0], D_8018D050[var_s0], var_s0, lapCount, characterId, 0x000000FF, 1, - var_a0, 0); + func_8004FDB4(D_8018D028[i], D_8018D050[i], i, lapCount, characterId, 0x000000FF, 1, var_a0, 0); } else { - func_8004FDB4(D_8018D028[var_s0], D_8018D050[var_s0], var_s0, lapCount, characterId, D_8018D3E0, 0, - var_a0, 0); + func_8004FDB4(D_8018D028[i], D_8018D050[i], i, lapCount, characterId, D_8018D3E0, 0, var_a0, 0); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } else { - for (var_s0 = 0; var_s0 < 8; var_s0++) { + for (i = 0; i < 8; i++) { var_a0 = 0; - if (D_8018D050[var_s0] >= 0.0f) { - if (D_8018D078[var_s0] <= 0.0) { + if (D_8018D050[i] >= 0.0f) { + if (D_8018D078[i] <= 0.0) { var_a0 = 1; } - temp_v0 = gGPCurrentRacePlayerIdByRank[var_s0]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("ranking portraits 2", i | var_a0 << 16); + + temp_v0 = gGPCurrentRacePlayerIdByRank[i]; // ???? characterId = (gPlayerOne + temp_v0)->characterId; lapCount = gLapCountByPlayerId[temp_v0]; if (temp_v0 == 0) { - func_8004FDB4(D_8018D028[var_s0], D_8018D050[var_s0], var_s0, lapCount, characterId, 0x000000FF, 1, - var_a0, 1); + func_8004FDB4(D_8018D028[i], D_8018D050[i], i, lapCount, characterId, 0x000000FF, 1, var_a0, 1); } else { - func_8004FDB4(D_8018D028[var_s0], D_8018D050[var_s0], var_s0, lapCount, characterId, 0x000000FF, 0, - var_a0, 1); + func_8004FDB4(D_8018D028[i], D_8018D050[i], i, lapCount, characterId, 0x000000FF, 0, var_a0, 1); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -3299,7 +3320,7 @@ void func_80050E34(s32 playerId, s32 arg1) { spB8 = 0; } - if ((GetCourse() == GetYoshiValley()) && (lapCount < 3)) { + if ((IsYoshiValley()) && (lapCount < 3)) { gSPDisplayList(gDisplayListHead++, D_0D007DB8); gDPLoadTLUT_pal256(gDisplayListHead++, common_tlut_portrait_bomb_kart_and_question_mark); rsp_load_texture(common_texture_portrait_question_mark, 0x00000020, 0x00000020); @@ -3380,15 +3401,19 @@ void func_800514BC(void) { } void render_object_leaf_particle(UNUSED s32 cameraId) { - s32 someIndex; + size_t i; s32 leafIndex; Object* object; gSPDisplayList(gDisplayListHead++, D_0D0079C8); gSPClearGeometryMode(gDisplayListHead++, G_CULL_BOTH); load_texture_block_rgba16_mirror((u8*) common_texture_particle_leaf, 0x00000020, 0x00000010); - for (someIndex = 0; someIndex < gLeafParticle_SIZE; someIndex++) { - leafIndex = gLeafParticle[someIndex]; + for (i = 0; i < gLeafParticle_SIZE; i++) { + leafIndex = gLeafParticle[i]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Leaves", leafIndex); + if (leafIndex != -1) { object = &gObjectList[leafIndex]; if ((object->state >= 2) && (object->unk_0D5 == 7) && (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX)) { @@ -3396,40 +3421,83 @@ void render_object_leaf_particle(UNUSED s32 cameraId) { gSPDisplayList(gDisplayListHead++, D_0D0069C8); } } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK); gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); } void render_object_snowflakes_particles(void) { - s32 someIndex; + size_t i; s32 snowflakeIndex; gSPDisplayList(gDisplayListHead++, D_0D007AE0); gDPSetCombineLERP(gDisplayListHead++, 1, 0, SHADE, 0, 0, 0, 0, TEXEL0, 1, 0, SHADE, 0, 0, 0, 0, TEXEL0); func_80044F34(D_0D0293D8, 0x10, 0x10); - for (someIndex = 0; someIndex < NUM_SNOWFLAKES; someIndex++) { - snowflakeIndex = gObjectParticle1[someIndex]; + for (i = 0; i < NUM_SNOWFLAKES; i++) { + snowflakeIndex = gObjectParticle1[i]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("SnowFlakes", snowflakeIndex); + if (gObjectList[snowflakeIndex].state >= 2) { rsp_set_matrix_gObjectList(snowflakeIndex); gSPDisplayList(gDisplayListHead++, D_0D006980); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); } -void func_800518F8(s32 objectIndex, s16 arg1, s16 arg2) { - UNUSED s32 pad[1]; +struct ObjectInterpData { + s32 objectIndex; + s16 x, y; +}; + +struct ObjectInterpData prevObject[OBJECT_LIST_SIZE] = { 0 }; + +void func_800518F8(s32 objectIndex, s16 x, s16 y) { + + // Search all recorded objects for the one we're drawing + for (int i = 0; i < OBJECT_LIST_SIZE; i++) { + if (objectIndex == prevObject[i].objectIndex) { + // Coincidence! + // Skip drawing the object this frame if it warped to the other side of the screen + if ((fabs(x - prevObject[i].x) > SCREEN_WIDTH / 2) || (fabs(y - prevObject[i].y) > SCREEN_HEIGHT / 2)) { + prevObject[objectIndex].x = x; + prevObject[objectIndex].y = y; + prevObject[objectIndex].objectIndex = objectIndex; + return; + } + } + } + if (gObjectList[objectIndex].status & 0x10) { + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("func_800518F8", (uintptr_t) &gObjectList[objectIndex]); + if (D_8018D228 != gObjectList[objectIndex].unk_0D5) { D_8018D228 = gObjectList[objectIndex].unk_0D5; func_80044DA0(gObjectList[objectIndex].activeTexture, gObjectList[objectIndex].textureWidth, gObjectList[objectIndex].textureHeight); } - func_80042330_unchanged(arg1, arg2, 0U, gObjectList[objectIndex].sizeScaling); + func_80042330_unchanged(x, y, 0, gObjectList[objectIndex].sizeScaling); gSPVertex(gDisplayListHead++, gObjectList[objectIndex].vertex, 4, 0); gSPDisplayList(gDisplayListHead++, common_rectangle_display); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } + + // Save current cloud index and x position + prevObject[objectIndex].x = x; + prevObject[objectIndex].y = y; + prevObject[objectIndex].objectIndex = objectIndex; } void func_800519D4(s32 objectIndex, s16 arg1, s16 arg2) { @@ -3446,6 +3514,7 @@ void func_800519D4(s32 objectIndex, s16 arg1, s16 arg2) { } } +// Render clouds void func_80051ABC(s16 arg0, s32 arg1) { s32 var_s0; s32 objectIndex; @@ -3465,7 +3534,14 @@ void func_80051ABC(s16 arg0, s32 arg1) { for (var_s0 = 0; var_s0 < D_8018D1F0; var_s0++) { objectIndex = D_8018CC80[arg1 + var_s0]; object = &gObjectList[objectIndex]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("func_80051ABC", TAG_OBJECT(object)); + func_800518F8(objectIndex, object->unk_09C, arg0 - object->unk_09E); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -3477,16 +3553,16 @@ void func_80051C60(s16 arg0, s32 arg1) { Object* object; if (D_801658FE == 0) { - if (GetCourse() == GetKoopaTroopaBeach()) { + if (IsKoopaTroopaBeach()) { var_s5 = arg0; - } else if (GetCourse() == GetMooMooFarm()) { + } else if (IsMooMooFarm()) { var_s5 = arg0 - 16; - } else if (GetCourse() == GetYoshiValley()) { + } else if (IsYoshiValley()) { var_s5 = arg0 - 16; } else { var_s5 = arg0 + 16; } - } else if (GetCourse() == GetKoopaTroopaBeach()) { + } else if (IsKoopaTroopaBeach()) { var_s5 = arg0 * 2; } else { var_s5 = arg0 + 32; @@ -3520,11 +3596,11 @@ void func_80051EF8(void) { s16 temp_a0; temp_a0 = 0xF0 - D_800DC5EC->cameraHeight; - if (GetCourse() == GetKoopaTroopaBeach()) { + if (IsKoopaTroopaBeach()) { temp_a0 = temp_a0 - 0x30; - } else if (GetCourse() == GetMooMooFarm()) { + } else if (IsMooMooFarm()) { temp_a0 = temp_a0 - 0x40; - } else if (GetCourse() == GetYoshiValley()) { + } else if (IsYoshiValley()) { temp_a0 = temp_a0 - 0x40; } else { temp_a0 = temp_a0 - 0x30; @@ -3536,11 +3612,11 @@ void func_80051F9C(void) { s16 temp_a0; temp_a0 = 0xF0 - D_800DC5F0->cameraHeight; - if (GetCourse() == GetKoopaTroopaBeach()) { + if (IsKoopaTroopaBeach()) { temp_a0 = temp_a0 - 0x30; - } else if (GetCourse() == GetMooMooFarm()) { + } else if (IsMooMooFarm()) { temp_a0 = temp_a0 - 0x40; - } else if (GetCourse() == GetYoshiValley()) { + } else if (IsYoshiValley()) { temp_a0 = temp_a0 - 0x40; } else { temp_a0 = temp_a0 - 0x30; @@ -3796,6 +3872,9 @@ void render_object_bowser_flame_particle(s32 objectIndex, s32 cameraId) { camera = &camera1[cameraId]; if (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX) { object = &gObjectList[objectIndex]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Bowser Statue Flame", TAG_ITEM_ADDR(object)); if (object->unk_0D5 == 9) { func_8004B72C(0xFF, (s32) object->type, 0, (s32) object->unk_0A2, 0, 0, (s32) object->primAlpha); } else { @@ -3803,6 +3882,9 @@ void render_object_bowser_flame_particle(s32 objectIndex, s32 cameraId) { } D_80183E80[1] = func_800418AC(object->pos[0], object->pos[2], camera->pos); func_800431B0(object->pos, D_80183E80, object->sizeScaling, D_0D005AE0); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } @@ -3849,20 +3931,23 @@ void func_8005477C(s32 objectIndex, u8 arg1, Vec3f arg2) { void render_object_smoke_particles(s32 cameraId) { UNUSED s32 stackPadding[2]; Camera* sp54; - s32 var_s0; + s32 i; s32 objectIndex; Object* object; sp54 = &camera1[cameraId]; + gSPDisplayList(gDisplayListHead++, D_0D007AE0); load_texture_block_i8_nomirror(common_texture_particle_smoke[D_80165598], 32, 32); func_8004B72C(255, 255, 255, 255, 255, 255, 255); D_80183E80[0] = 0; D_80183E80[2] = 0x8000; - for (var_s0 = 0; var_s0 < gObjectParticle4_SIZE; var_s0++) { - objectIndex = gObjectParticle4[var_s0]; + for (i = 0; i < gObjectParticle4_SIZE; i++) { + objectIndex = gObjectParticle4[i]; if (objectIndex != NULL_OBJECT_ID) { object = &gObjectList[objectIndex]; + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("SmokeParticles", (uintptr_t) object); if (object->state >= 2) { if (object->unk_0D8 == 3) { func_8008A364(objectIndex, cameraId, 0x4000U, 0x00000514); @@ -3873,6 +3958,8 @@ void render_object_smoke_particles(s32 cameraId) { func_8005477C(objectIndex, object->unk_0D8, sp54->pos); } } + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } } } @@ -3885,6 +3972,9 @@ void func_800557B4(s32 objectIndex, u32 arg1, u32 arg2) { Object* object; object = &gObjectList[objectIndex]; + + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Penguin", (uintptr_t) object); if (object->state >= 2) { if (is_obj_flag_status_active(objectIndex, 0x00000020) != 0) { if (func_80072320(objectIndex, 4) != 0) { @@ -3907,6 +3997,9 @@ void func_800557B4(s32 objectIndex, u32 arg1, u32 arg2) { render_animated_model((Armature*) object->model, (Animation**) object->vertex, (s16) object->unk_0D8, (s16) object->textureListIndex); } + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } void func_80055EF4(s32 objectIndex, UNUSED s32 arg1) { @@ -3920,15 +4013,15 @@ void func_80055EF4(s32 objectIndex, UNUSED s32 arg1) { void render_object_neon(s32 cameraId) { Camera* camera; - s32 var_s2; s32 objectIndex; Object* object; camera = &camera1[cameraId]; - for (var_s2 = 0; var_s2 < 10; var_s2++) { - objectIndex = indexObjectList1[var_s2]; + for (size_t i = 0; i < 10; i++) { + objectIndex = indexObjectList1[i]; if (D_8018E838[cameraId] == 0) { object = &gObjectList[objectIndex]; + FrameInterpolation_RecordOpenChild(object, TAG_OBJECT((objectIndex << 8) + i)); if ((object->state >= 2) && (is_obj_index_flag_status_inactive(objectIndex, 0x00080000) != 0) && (is_object_visible_on_camera(objectIndex, camera, 0x2AABU) != 0)) { Vtx* vtx = (Vtx*) LOAD_ASSET(common_vtx_hedgehog); @@ -3936,6 +4029,7 @@ void render_object_neon(s32 cameraId) { draw_2d_texture_at(object->pos, object->orientation, object->sizeScaling, (u8*) object->activeTLUT, object->activeTexture, vtx, 0x00000040, 0x00000040, 0x00000040, 0x00000020); } + FrameInterpolation_RecordCloseChild(); } } } @@ -4019,8 +4113,8 @@ void func_8005669C(s32 objectIndex, UNUSED s32 arg1, s32 arg2) { gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); } +Mat4 mtx; void func_800568A0(s32 objectIndex, s32 playerId) { - Mat4 mtx; Player* player; player = &gPlayerOne[playerId]; @@ -4040,13 +4134,12 @@ void func_800569F4(s32 playerIndex) { CM_DisplayBattleBombKart(playerIndex, 0); } - void func_80056A40(s32 playerIndex, s32 arg1) { CM_DisplayBattleBombKart(playerIndex, arg1); } void func_80056A94(s32 playerIndex) { - //func_80072428(gIndexObjectBombKart[playerIndex]); + // func_80072428(gIndexObjectBombKart[playerIndex]); CM_DisplayBattleBombKart(playerIndex, 0); } diff --git a/src/render_player.c b/src/render_player.c index 1c4d78a7e..5061826f6 100644 --- a/src/render_player.c +++ b/src/render_player.c @@ -32,6 +32,7 @@ #include #include "port/Game.h" #include "engine/Matrix.h" +#include "port/interpolation/FrameInterpolation.h" s8 gRenderingFramebufferByPlayer[] = { 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02 }; @@ -47,7 +48,6 @@ s16 gMatrixEffectCount; s32 D_80164AF4[3]; struct_D_802F1F80* gPlayerPalette; static const char* sKartUpperTexture; -static const char* sKartLowerTexture; u16 gPlayerRedEffect[8]; u16 gPlayerGreenEffect[8]; u16 gPlayerBlueEffect[8]; @@ -722,7 +722,7 @@ const char** wheelPtr[] = { donkeykong_kart_wheels, wario_kart_wheels, peach_kart_wheels, bowser_kart_wheels, }; -s32 D_800DDE74[] = { 96, 128, 192, 256, 288, 384, 512, 544, 576, 0, 0}; +s32 D_800DDE74[] = { 96, 128, 192, 256, 288, 384, 512, 544, 576, 0, 0 }; void render_players_on_screen_two(void) { gPlayersToRenderCount = 0; @@ -902,6 +902,8 @@ void mtxf_translate_rotate(Mat4 dest, Vec3f pos, Vec3s orientation) { f32 sinZ = sins(orientation[2]); f32 cosZ = coss(orientation[2]); + FrameInterpolation_RecordTranslateRotate(dest, pos, orientation); + dest[0][0] = (cosY * cosZ) + ((sinX * sinY) * sinZ); dest[1][0] = (-cosY * sinZ) + ((sinX * sinY) * cosZ); dest[2][0] = cosX * sinY; @@ -926,18 +928,6 @@ UNUSED void func_80021F50(Mat4 arg0, Vec3f arg1) { arg0[3][2] += arg1[2]; } -void mtxf_scale2(Mat4 arg0, f32 scale) { - arg0[0][0] *= scale; - arg0[1][0] *= scale; - arg0[2][0] *= scale; - arg0[0][1] *= scale; - arg0[1][1] *= scale; - arg0[2][1] *= scale; - arg0[0][2] *= scale; - arg0[1][2] *= scale; - arg0[2][2] *= scale; -} - /** * This function writes a fixed-point value to each Mtx entry. This is not how the Mtx struct works. * The first half of Mtx only holds s16 whole numbers and the second half holds the s16 decimal (fractional) parts. @@ -1287,7 +1277,7 @@ void change_player_color_effect_cmy(UNUSED Player* player, s8 arg1, s32 arg2, f3 * Sort of an atmospheric effect. */ bool is_player_under_light_luigi_raceway(Player* player, s8 arg1) { - if (GetCourse() == GetLuigiRaceway()) { + if (IsLuigiRaceway()) { if (((gNearestWaypointByPlayerId[arg1] >= 0x14F) && (gNearestWaypointByPlayerId[arg1] < 0x158)) || ((gNearestWaypointByPlayerId[arg1] >= 0x15E) && (gNearestWaypointByPlayerId[arg1] < 0x164)) || ((gNearestWaypointByPlayerId[arg1] >= 0x169) && (gNearestWaypointByPlayerId[arg1] < 0x170)) || @@ -1305,7 +1295,7 @@ bool is_player_under_light_luigi_raceway(Player* player, s8 arg1) { } void render_light_environment_on_player(Player* player, s8 arg1) { - if (GetCourse() == GetBowsersCastle()) { + if (IsBowsersCastle()) { if (((gNearestWaypointByPlayerId[arg1] >= 0x15) && (gNearestWaypointByPlayerId[arg1] < 0x2A)) || ((gNearestWaypointByPlayerId[arg1] >= 0x14D) && (gNearestWaypointByPlayerId[arg1] < 0x15C)) || ((gNearestWaypointByPlayerId[arg1] >= 0x1D1) && (gNearestWaypointByPlayerId[arg1] < 0x1E4)) || @@ -1328,7 +1318,7 @@ void render_light_environment_on_player(Player* player, s8 arg1) { change_player_color_effect_cmy(player, arg1, 0, 0.3f); D_80164B80[arg1] = 0; } - } else if (GetCourse() == GetBansheeBoardwalk()) { + } else if (IsBansheeBoardwalk()) { if (((gNearestWaypointByPlayerId[arg1] >= 0xD) && (gNearestWaypointByPlayerId[arg1] < 0x15)) || ((gNearestWaypointByPlayerId[arg1] >= 0x29) && (gNearestWaypointByPlayerId[arg1] < 0x39)) || ((gNearestWaypointByPlayerId[arg1] >= 0x46) && (gNearestWaypointByPlayerId[arg1] < 0x4E)) || @@ -1483,6 +1473,8 @@ void render_player_shadow(Player* player, s8 playerId, s8 screenId) { UNUSED Vec3f pad2; f32 var_f2; + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("Kart Shadow", TAG_ITEM_ADDR(player)); temp_t9 = (u16) (player->unk_048[screenId] + player->rotation[1] + player->unk_0C0) / 128; // << 7) & 0xFFFF; spC0 = -player->rotation[1] - player->unk_0C0; @@ -1520,7 +1512,7 @@ void render_player_shadow(Player* player, s8 playerId, s8 screenId) { spCC[1] = player->unk_074 + 1.0f; spCC[2] = player->pos[2] + ((spB0 * coss(spC0)) - (spAC * sins(spC0))); mtxf_translate_rotate(mtx, spCC, spC4); - mtxf_scale2(mtx, gCharacterSize[player->characterId] * player->size); + mtxf_scale(mtx, gCharacterSize[player->characterId] * player->size); } // convert_to_fixed_point_matrix(&gGfxPool->mtxShadow[playerId + (screenId * 8)], mtx); @@ -1546,6 +1538,9 @@ void render_player_shadow(Player* player, s8 playerId, s8 screenId) { gSPDisplayList(gDisplayListHead++, common_square_plain_render); gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } void render_player_shadow_credits(Player* player, s8 playerId, s8 arg2) { @@ -1576,7 +1571,7 @@ void render_player_shadow_credits(Player* player, s8 playerId, s8 arg2) { spCC[1] = gObjectList[indexObjectList1[playerId]].pos[1] + sp94[playerId]; mtxf_translate_rotate(mtx, spCC, spC4); - mtxf_scale2(mtx, gCharacterSize[player->characterId] * player->size); + mtxf_scale(mtx, gCharacterSize[player->characterId] * player->size); // convert_to_fixed_point_matrix(&gGfxPool->mtxShadow[playerId + (arg2 * 8)], mtx); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxShadow[playerId + (arg2 * 8)]), @@ -1604,6 +1599,19 @@ void render_player_shadow_credits(Player* player, s8 playerId, s8 arg2) { gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); } +Vtx player_vtx[] = { + { { { 9, 18, -6 }, 0, { 4032, 0 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, + { { { 9, 0, -6 }, 0, { 4032, 4032 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, + { { { -9, 18, -6 }, 0, { 0, 0 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, + { { { -9, 0, -6 }, 0, { 0, 4032 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, +}; +Vtx player_vtx_flip[] = { + { { { 9, 18, -6 }, 0, { 0, 0 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, + { { { 9, 0, -6 }, 0, { 0, 4032 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, + { { { -9, 18, -6 }, 0, { 4032, 0 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, + { { { -9, 0, -6 }, 0, { 4032, 4032 }, { 0xFF, 0xFF, 0xFF, 0xFF } } }, +}; + void render_kart(Player* player, s8 playerId, s8 screenId, s8 arg3) { UNUSED s32 pad; Mat4 mtx; @@ -1616,6 +1624,7 @@ void render_kart(Player* player, s8 playerId, s8 screenId, s8 arg3) { s16 temp_v1; s16 thing; + FrameInterpolation_RecordOpenChild("player_kart", playerId | screenId << 8); if (player->unk_044 & 0x2000) { sp14C[0] = 0; sp14C[1] = player->unk_048[screenId]; @@ -1668,9 +1677,11 @@ void render_kart(Player* player, s8 playerId, s8 screenId, s8 arg3) { #endif } mtxf_translate_rotate(mtx, sp154, sp14C); - mtxf_scale2(mtx, gCharacterSize[player->characterId] * player->size); + mtxf_scale(mtx, gCharacterSize[player->characterId] * player->size); // convert_to_fixed_point_matrix(&gGfxPool->mtxKart[playerId + (screenId * 8)], mtx); + // @port: Tag the transform. + if ((player->effects & BOO_EFFECT) == BOO_EFFECT) { if (screenId == playerId) { AddKartMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); @@ -1728,21 +1739,20 @@ void render_kart(Player* player, s8 playerId, s8 screenId, s8 arg3) { } // Render heads - gDPLoadTextureBlock(gDisplayListHead++, sKartUpperTexture, G_IM_FMT_CI, G_IM_SIZ_8b, 64, 32, 0, - G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOLOD); - gSPVertex(gDisplayListHead++, &D_800DDBB4[playerId][arg3], 4, 0); - gSPDisplayList(gDisplayListHead++, common_square_plain_render); - - // Render karts - u8* test = (u8*) LOAD_ASSET(sKartUpperTexture); - gDPLoadTextureBlock(gDisplayListHead++, test + 0x7C0, G_IM_FMT_CI, G_IM_SIZ_8b, 64, 32, 0, + gDPLoadTextureBlock(gDisplayListHead++, sKartUpperTexture, G_IM_FMT_CI, G_IM_SIZ_8b, 64, 64, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPVertex(gDisplayListHead++, &D_800DDBB4[playerId][arg3 + 4], 4, 0); - gSPDisplayList(gDisplayListHead++, common_square_plain_render); + if (arg3 == 0) { + gSPVertex(gDisplayListHead++, player_vtx, 4, 0); + } else { + gSPVertex(gDisplayListHead++, player_vtx_flip, 4, 0); + } + gSP2Triangles(gDisplayListHead++, 0, 1, 2, 0, 1, 3, 2, 0); gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); gDPSetAlphaCompare(gDisplayListHead++, G_AC_NONE); + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } void render_ghost(Player* player, s8 playerId, s8 screenId, s8 arg3) { @@ -1789,7 +1799,7 @@ void render_ghost(Player* player, s8 playerId, s8 screenId, s8 arg3) { } mtxf_translate_rotate(mtx, spDC, spD4); - mtxf_scale2(mtx, gCharacterSize[player->characterId] * player->size); + mtxf_scale(mtx, gCharacterSize[player->characterId] * player->size); // convert_to_fixed_point_matrix(&gGfxPool->mtxKart[playerId + (screenId * 8)], mtx); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxKart[playerId + (screenId * 8)]), @@ -1834,8 +1844,11 @@ void func_80025DE8(Player* player, s8 playerId, s8 screenId, s8 arg3) { sp94[1] = player->unk_048[screenId]; sp94[2] = player->unk_050[screenId]; + FrameInterpolation_RecordOpenChild("player_boost", playerId | screenId << 8); + + mtxf_translate_rotate(mtx, sp9C, sp94); - mtxf_scale2(mtx, gCharacterSize[player->characterId] * player->size); + mtxf_scale(mtx, gCharacterSize[player->characterId] * player->size); // convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], mtx); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]), @@ -1865,6 +1878,8 @@ void func_80025DE8(Player* player, s8 playerId, s8 screenId, s8 arg3) { gSPDisplayList(gDisplayListHead++, common_square_plain_render); gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); gMatrixEffectCount += 1; + + FrameInterpolation_RecordCloseChild(); } void render_player_ice_reflection(Player* player, s8 playerId, s8 screenId, s8 arg3) { @@ -1884,8 +1899,11 @@ void render_player_ice_reflection(Player* player, s8 playerId, s8 screenId, s8 a arg3 = 0; } + // @port: Tag the transform. + FrameInterpolation_RecordOpenChild("PlayerReflection", playerId | screenId << 8); + mtxf_translate_rotate(mtx, sp9C, sp94); - mtxf_scale2(mtx, gCharacterSize[player->characterId] * player->size); + mtxf_scale(mtx, gCharacterSize[player->characterId] * player->size); // convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], mtx); // gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]), @@ -1911,6 +1929,9 @@ void render_player_ice_reflection(Player* player, s8 playerId, s8 screenId, s8 a gSPDisplayList(gDisplayListHead++, common_square_plain_render); gSPTexture(gDisplayListHead++, 1, 1, 0, G_TX_RENDERTILE, G_OFF); gMatrixEffectCount += 1; + + // @port Pop the transform id. + FrameInterpolation_RecordCloseChild(); } void render_player(Player* player, s8 playerId, s8 screenId) { @@ -1951,7 +1972,7 @@ void render_player(Player* player, s8 playerId, s8 screenId) { func_80025DE8(player, playerId, screenId, var_v1); } // Allows wheels to spin - gSPInvalidateTexCache(gDisplayListHead++, sKartLowerTexture); + gSPInvalidateTexCache(gDisplayListHead++, sKartUpperTexture); } void func_80026A48(Player* player, s8 arg1) { diff --git a/src/render_player.h b/src/render_player.h index 212f8810b..3f9d06406 100644 --- a/src/render_player.h +++ b/src/render_player.h @@ -1,5 +1,5 @@ -#ifndef CODE_8001F980_H -#define CODE_8001F980_H +#ifndef RENDER_PLAYER_H +#define RENDER_PLAYER_H #include #include "buffers.h" @@ -29,7 +29,6 @@ void func_80021D40(void); void func_80021DA8(void); void mtxf_translate_rotate(Mat4, Vec3f, Vec3s); void func_80021F50(Mat4, Vec3f); -void mtxf_scale2(Mat4, f32); void failed_fixed_point_matrix_conversion(Mtx*, Mat4); void convert_to_fixed_point_matrix(Mtx*, Mat4); bool adjust_angle(s16*, s16, s16); @@ -279,4 +278,4 @@ extern s16 D_80165150[4][8]; extern s16 D_80165190[4][8]; extern s16 D_801651D0[4][8]; -#endif +#endif // RENDER_PLAYER_H diff --git a/src/spawn_players.c b/src/spawn_players.c index 5e623577b..f633f550d 100644 --- a/src/spawn_players.c +++ b/src/spawn_players.c @@ -729,7 +729,7 @@ void spawn_players_versus_two_player(f32* arg0, f32* arg1, f32 arg2) { } void spawn_players_2p_battle(f32* arg0, f32* arg1, f32 arg2) { - if (GetCourse() == GetBigDonut()) { + if (IsBigDonut()) { spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, -16384.0f, gCharacterSelections[0], PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN); spawn_player(gPlayerTwo, 1, arg0[1], arg1[1], arg2, 16384.0f, gCharacterSelections[1], @@ -778,7 +778,7 @@ void func_8003B318(f32* arg0, f32* arg1, f32 arg2) { } void spawn_players_3p_battle(f32* arg0, f32* arg1, f32 arg2) { - if (GetCourse() == GetBigDonut()) { + if (IsBigDonut()) { spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, -16384.0f, gCharacterSelections[0], PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN); spawn_player(gPlayerTwo, 1, arg0[1], arg1[1], arg2, 16384.0f, gCharacterSelections[1], @@ -830,7 +830,7 @@ void func_8003B870(f32* arg0, f32* arg1, f32 arg2) { } void spawn_players_4p_battle(f32* arg0, f32* arg1, f32 arg2) { - if (GetCourse() == GetBigDonut()) { + if (IsBigDonut()) { spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, -16384.0f, gCharacterSelections[0], PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN); spawn_player(gPlayerTwo, 1, arg0[1], arg1[1], arg2, 16384.0f, gCharacterSelections[1], @@ -888,17 +888,17 @@ void func_8003C0F0(void) { if (gModeSelection == BATTLE) { func_8000EEDC(); - } else if (GetCourse() != GetPodiumCeremony()) { + } else if (!IsPodiumCeremony()) { func_8000F2DC(); sp5E = (f32) D_80164550[0][0].posX; sp5C = (f32) D_80164550[0][0].posZ; sp5A = (f32) D_80164550[0][0].posY; - if (GetCourse() == GetToadsTurnpike()) { + if (IsToadsTurnpike()) { sp5E = 0; } } - if ((gModeSelection != BATTLE) && (GetCourse() != GetPodiumCeremony())) { + if ((gModeSelection != BATTLE) && (!IsPodiumCeremony())) { switch (gActiveScreenMode) { case SCREEN_MODE_1P: switch (gModeSelection) { @@ -993,7 +993,7 @@ void func_8003C0F0(void) { } break; } - } else if (GetCourse() == GetBlockFort()) { + } else if (IsBlockFort()) { switch (gActiveScreenMode) { case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL: @@ -1023,7 +1023,7 @@ void func_8003C0F0(void) { } break; } - } else if (GetCourse() == GetSkyscraper()) { + } else if (IsSkyscraper()) { switch (gActiveScreenMode) { case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL: @@ -1053,7 +1053,7 @@ void func_8003C0F0(void) { } break; } - } else if (GetCourse() == GetDoubleDeck()) { + } else if (IsDoubleDeck()) { switch (gActiveScreenMode) { case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL: @@ -1083,7 +1083,7 @@ void func_8003C0F0(void) { } break; } - } else if (GetCourse() == GetBigDonut()) { + } else if (IsBigDonut()) { switch (gActiveScreenMode) { case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL: case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL: @@ -1194,12 +1194,13 @@ void func_8003D080(void) { } else { func_8003C0F0(); } + if (!gDemoMode) { switch (gActiveScreenMode) { case SCREEN_MODE_1P: switch (gModeSelection) { case GRAND_PRIX: - if (GetCourse() == GetToadsTurnpike()) { + if (IsToadsTurnpike()) { camera_init(0.0f, player->pos[1], D_80165230[7], player->rotation[1], 8, 0); } else { camera_init((D_80165210[7] + D_80165210[6]) / 2, player->pos[1], D_80165230[7], @@ -1289,6 +1290,9 @@ void func_8003D080(void) { } } + // Init freecam + //freecam_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 4); + switch (gActiveScreenMode) { case SCREEN_MODE_1P: func_8003CD98(gPlayerOneCopy, camera1, 0, 0); // sic diff --git a/src/staff_ghosts.c b/src/staff_ghosts.c index 914809d38..c92892cdc 100644 --- a/src/staff_ghosts.c +++ b/src/staff_ghosts.c @@ -39,7 +39,7 @@ u32* D_80162DB4; s16 D_80162DB8; u32* D_80162DBC; -u16 D_80162DC0; +uintptr_t staff_ghost_track_ptr; StaffGhost* D_80162DC4; s32 D_80162DC8; s32 D_80162DCC; @@ -164,11 +164,11 @@ void func_80005310(void) { set_staff_ghost(); - if (D_80162DC0 != gCurrentCourseId) { + if (staff_ghost_track_ptr != (uintptr_t)GetCourse()) { D_80162DD4 = 1; } - D_80162DC0 = (u16) gCurrentCourseId; + staff_ghost_track_ptr = (uintptr_t)GetCourse(); D_80162DF0 = 0; D_80162DEC = 0; D_80162DF8 = 0; diff --git a/src/update_objects.c b/src/update_objects.c index 73d0dcfdc..15541a239 100644 --- a/src/update_objects.c +++ b/src/update_objects.c @@ -40,6 +40,8 @@ #include #include "port/Game.h" +float OTRGetAspectRatio(void); + //! @todo unused? f32 D_800E43B0[] = { 65536.0, 0.0, 1.0, 0.0, 0.0, 65536.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; @@ -2088,8 +2090,6 @@ void init_smoke_particles(s32 arg0) { } } - - void init_object_leaf_particle(s32 objectIndex, Vec3f arg1, s32 num) { UNUSED s32 stackPadding1; UNUSED u16 stackPadding0; @@ -2104,19 +2104,19 @@ void init_object_leaf_particle(s32 objectIndex, Vec3f arg1, s32 num) { gObjectList[objectIndex].sizeScaling = 0.1f; gObjectList[objectIndex].surfaceHeight = arg1[1]; - if (GetCourse() == GetMarioRaceway()) { + if (IsMarioRaceway()) { object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 25.0, arg1[2], 0x14, 0x1E, 0x14); gObjectList[objectIndex].unk_034 = 1.5f; gObjectList[objectIndex].velocity[1] = 1.5f; - } else if (GetCourse() == GetYoshiValley()) { + } else if (IsYoshiValley()) { object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 25.0, arg1[2], 0x14, 0x1E, 0x14); gObjectList[objectIndex].unk_034 = 2.0f; gObjectList[objectIndex].velocity[1] = 2.0f; - } else if (GetCourse() == GetRoyalRaceway()) { + } else if (IsRoyalRaceway()) { object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 30.0, arg1[2], 0x10, 0x28, 0x10); gObjectList[objectIndex].unk_034 = 2.0f; gObjectList[objectIndex].velocity[1] = 2.0f; - } else if (GetCourse() == GetLuigiRaceway()) { + } else if (IsLuigiRaceway()) { object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 25.0, arg1[2], 0x14, 0x1E, 0x14); gObjectList[objectIndex].unk_034 = 1.5f; gObjectList[objectIndex].velocity[1] = 1.0f; @@ -2454,21 +2454,30 @@ void update_snowflakes(void) { } } +// This function adjusted to place clouds in the sky correctly void func_800788F8(s32 objectIndex, u16 rot, Camera* camera) { - s16 temp_v0; + s16 cameraRot; + // Adjustable culling factor + const float cullingFactor = OTRGetAspectRatio(); - temp_v0 = camera->rot[1] + rot; - if ((temp_v0 >= D_8018D210) && (D_8018D208 >= temp_v0)) { - gObjectList[objectIndex].unk_09C = (D_8018D218 + (D_8018D1E8 * temp_v0)); - set_object_flag(objectIndex, 0x00000010); - return; - } - if (CVarGetInteger("gNoCulling", 0) == 1) { - gObjectList[objectIndex].unk_09C = (D_8018D218 + (D_8018D1E8 * temp_v0)); - set_object_flag(objectIndex, 0x00000010); - return; + // Calculate the cloud's rotation relative to the camera + cameraRot = camera->rot[1] + rot; + + // Adjust bounds based on the culling factor + s16 adjustedLowerBound = (s16) (D_8018D210 * cullingFactor); + s16 adjustedUpperBound = (s16) (D_8018D208 * cullingFactor); + + // Check if the object is within the adjusted bounds + if ((cameraRot >= adjustedLowerBound) && (adjustedUpperBound >= cameraRot)) { + // Calculate and update the object's position + gObjectList[objectIndex].unk_09C = (D_8018D218 + (D_8018D1E8 * cameraRot)); + + // Mark the object as visible + set_object_flag(objectIndex, 0x10); + } else { + // If outside the bounds, mark the object as not visible + set_object_flag(objectIndex, 0x10); } - clear_object_flag(objectIndex, 0x00000010); } void update_clouds(s32 arg0, Camera* arg1, CloudData* cloudList) { @@ -2601,7 +2610,6 @@ void func_80078C70(s32 arg0) { } } - void func_8007ABFC(s32 playerId, bool arg1) { s32 itemWindow; @@ -3448,7 +3456,7 @@ void func_8007BB9C(s32 arg0) { } void wrapper_update_boos(void) { - //update_boos(); + // update_boos(); } // Updates the display status on an object based on its relative direction to the camera @@ -3476,7 +3484,6 @@ void func_8007C420(s32 objectIndex, Player* player, Camera* camera) { func_8007C360(objectIndex, camera); } - void func_8007CE0C(s32 objectIndex) { Object* object; @@ -3873,8 +3880,6 @@ void func_800842C8(void) { } } - - void func_80085BB4(s32 objectIndex) { gObjectList[objectIndex].sizeScaling = 8.0f; set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f); diff --git a/torch b/torch index 8e56ea029..f75facb20 160000 --- a/torch +++ b/torch @@ -1 +1 @@ -Subproject commit 8e56ea0294973b7c9f8f077a131b40fce13b8489 +Subproject commit f75facb20883570ed091e8ae733ec0539f606e57 -- cgit v1.2.3