summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcoco875 <pereira.jannin@gmail.com>2025-05-25 19:51:35 +0200
committercoco875 <pereira.jannin@gmail.com>2025-05-25 19:51:35 +0200
commit5313309a0003c47f34eec2e840827a039952a712 (patch)
treef9b11c4260257a3cf5058f48f0c4f5d3e6fd5b40 /src
parenta67fbb6442d76016397c67f2cb7831687cdda91a (diff)
parent2a0c0939c780babc45c8c22dfd6f94563485bae5 (diff)
Merge branch 'transformfuncsforint' into particle-boat-and-train-
Diffstat (limited to 'src')
-rw-r--r--src/actors/cow/render.inc.c6
-rw-r--r--src/actors/fake_item_box/render.inc.c6
-rw-r--r--src/actors/falling_rock/render.inc.c21
-rw-r--r--src/actors/item_box/render.inc.c46
-rw-r--r--src/actors/mario_sign/render.inc.c13
-rw-r--r--src/actors/piranha_plant/render.inc.c2
-rw-r--r--src/actors/trees/render.inc.c2
-rw-r--r--src/actors/yoshi_egg/render.inc.c8
-rw-r--r--src/animation.c7
-rw-r--r--src/audio/external.c22
-rw-r--r--src/camera.c153
-rw-r--r--src/camera.h2
-rw-r--r--src/code_800029B0.c8
-rw-r--r--src/code_80005FD0.c93
-rw-r--r--src/code_80057C60.c177
-rw-r--r--src/code_8006E9C0.c8
-rw-r--r--src/code_8006E9C0.h2
-rw-r--r--src/code_80086E70.c4
-rw-r--r--src/code_800AF9B0.c8
-rw-r--r--src/effects.c16
-rw-r--r--src/ending/code_80281780.c2
-rw-r--r--src/ending/podium_ceremony_actors.c6
-rw-r--r--src/engine/Matrix.cpp13
-rw-r--r--src/engine/World.cpp19
-rw-r--r--src/engine/World.h18
-rw-r--r--src/engine/actors/Finishline.cpp8
-rw-r--r--src/engine/actors/Finishline.h1
-rw-r--r--src/engine/editor/Editor.cpp19
-rw-r--r--src/engine/editor/Editor.h1
-rw-r--r--src/engine/editor/EditorMath.cpp8
-rw-r--r--src/engine/objects/Bat.cpp48
-rw-r--r--src/engine/objects/BombKart.cpp8
-rw-r--r--src/engine/objects/Boos.cpp8
-rw-r--r--src/engine/objects/GrandPrixBalloons.cpp35
-rw-r--r--src/engine/objects/Hedgehog.cpp22
-rw-r--r--src/engine/objects/HotAirBalloon.cpp2
-rw-r--r--src/engine/objects/Lakitu.cpp10
-rw-r--r--src/engine/objects/Mole.cpp107
-rw-r--r--src/engine/objects/Snowman.cpp59
-rw-r--r--src/engine/objects/TrashBin.cpp10
-rw-r--r--src/engine/particles/StarEmitter.cpp5
-rw-r--r--src/enhancements/collision_viewer.c2
-rw-r--r--src/enhancements/freecam/freecam.cpp41
-rw-r--r--src/enhancements/freecam/freecam.h2
-rw-r--r--src/enhancements/freecam/freecam_engine.c4
-rw-r--r--src/gbiMacro.c2
-rw-r--r--src/main.c20
-rw-r--r--src/math_util_2.c99
-rw-r--r--src/math_util_2.h10
-rw-r--r--src/menu_items.c33
-rw-r--r--src/menus.c1
-rw-r--r--src/os/guLookAtF.c2
-rw-r--r--src/os/guPerspectiveF.c2
-rw-r--r--src/player_controller.c20
-rw-r--r--src/port/Engine.cpp82
-rw-r--r--src/port/Engine.h4
-rw-r--r--src/port/Game.cpp279
-rw-r--r--src/port/Game.h86
-rw-r--r--src/port/interpolation/FrameInterpolation.cpp806
-rw-r--r--src/port/interpolation/FrameInterpolation.h85
-rw-r--r--src/port/interpolation/matrix.c451
-rw-r--r--src/port/interpolation/matrix.h94
-rw-r--r--src/port/resource/importers/AudioBankFactory.cpp1
-rw-r--r--src/port/resource/type/AudioBank.cpp17
-rw-r--r--src/port/resource/type/AudioBank.h1
-rw-r--r--src/port/resource/type/AudioSample.cpp14
-rw-r--r--src/port/resource/type/AudioSample.h1
-rw-r--r--src/port/ui/ContentBrowser.cpp25
-rw-r--r--src/port/ui/PortMenu.cpp34
-rw-r--r--src/racing/actors.c55
-rw-r--r--src/racing/framebuffer_effects.c4
-rw-r--r--src/racing/math_util.c132
-rw-r--r--src/racing/math_util.h11
-rw-r--r--src/racing/race_logic.c10
-rw-r--r--src/racing/render_courses.c13
-rw-r--r--src/racing/skybox_and_splitscreen.c89
-rw-r--r--src/render_objects.c217
-rw-r--r--src/render_player.c91
-rw-r--r--src/render_player.h7
-rw-r--r--src/spawn_players.c26
-rw-r--r--src/staff_ghosts.c6
-rw-r--r--src/update_objects.c42
82 files changed, 3054 insertions, 880 deletions
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..3292b64e2 100644
--- a/src/actors/fake_item_box/render.inc.c
+++ b/src/actors/fake_item_box/render.inc.c
@@ -2,6 +2,7 @@
#include <code_800029B0.h>
#include <libultra/gbi.h>
#include <main.h>
+#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) {
@@ -163,4 +167,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..d0d5aa0dc 100644
--- a/src/actors/falling_rock/render.inc.c
+++ b/src/actors/falling_rock/render.inc.c
@@ -1,6 +1,7 @@
#include <actors.h>
#include <main.h>
#include <assets/choco_mountain_data.h>
+#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,26 @@ 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) {
+
+ mtxf_pos_rotation_xyz(mtx, sp8C, sp98);
+ if (render_set_position(mtx, 0) == 0) {
return;
}
gSPDisplayList(gDisplayListHead++, d_course_choco_mountain_dl_6F88);
}
}
- 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..12cc17497 100644
--- a/src/actors/item_box/render.inc.c
+++ b/src/actors/item_box/render.inc.c
@@ -1,6 +1,7 @@
#include <actors.h>
#include <main.h>
#include <macros.h>
+#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,25 +82,27 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIA, G_CC_MODULATEIA);
- 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)) {
- gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
- } else if ((item_box->rot[1] >= 0x38E1) && (item_box->rot[1] < 0x438A)) {
- gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
- } 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);
- }
+ // 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)) {
+ // gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
+ // } else if ((item_box->rot[1] >= 0x38E1) && (item_box->rot[1] < 0x438A)) {
+ // gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
+ // } 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);
+ // }
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 +126,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 +139,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 +152,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 +161,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 +169,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 +182,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 +194,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 <actors.h>
#include <main.h>
#include <assets/mario_raceway_data.h>
+#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 <actors.h>
#include <defines.h>
#include <main.h>
+#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 <libultra/gbi.h>
#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..6620c3ac0 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 {
@@ -992,7 +1134,8 @@ void func_8001EE98(Player* player, Camera* camera, s8 index) {
func_8001E8E8(camera, player, index);
break;
}
- freecam(camera, player, index); // Runs func_8001E45C when freecam is disabled
+ //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..2ce053cac 100644
--- a/src/code_80057C60.c
+++ b/src/code_80057C60.c
@@ -39,6 +39,7 @@
#include <assets/some_data.h>
#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,7 +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) &&
+ if ((IsLuigiRaceway()) && (D_80165898 == 0) &&
(gModeSelection != (s32) TIME_TRIALS)) {
D_80165898 = 1;
}
@@ -2610,7 +2618,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 +2935,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 +2959,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 +3201,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 +3402,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 +3638,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 +3658,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 +3674,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 +3712,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 +4058,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 +4628,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;
}
@@ -4966,16 +4974,18 @@ void func_800651F4(Player* player, UNUSED s8 arg1, UNUSED s8 arg2, s8 arg3) {
}
}
+s32 D_func_800652D4_counter = 0;
void func_800652D4(Vec3f arg0, Vec3s arg1, f32 arg2) {
Mat4 mtx;
-
+ FrameInterpolation_RecordOpenChild("some_thing", D_func_800652D4_counter++ << 8);
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);
AddEffectMatrix(mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ FrameInterpolation_RecordCloseChild();
}
void func_8006538C(Player* player, s8 arg1, s16 arg2, s8 arg3) {
@@ -5098,6 +5108,13 @@ void func_80065AB0(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
spAC[0] = 0;
spAC[1] = player->unk_048[arg3];
spAC[2] = 0;
+
+ // // @port: Tag the transform.
+ FrameInterpolation_RecordOpenChild("EEEEEEEEE", player->type << 8 | arg2 | var_s0 << 16);
+
+ // @port Skip interpolation
+ // FrameInterpolation_ShouldInterpolateFrame(false);
+
func_800652D4(spB4, spAC, player->unk_258[10 + arg2].unk_00C * player->size);
if (var_s0 == 0) {
gSPDisplayList(gDisplayListHead++, D_0D008DB8);
@@ -5117,6 +5134,11 @@ void func_80065AB0(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
gSPDisplayList(gDisplayListHead++, D_0D008E48);
}
gMatrixEffectCount += 1;
+
+ // @port Pop the transform id.
+ FrameInterpolation_RecordCloseChild();
+ // @port renable interpolation
+ // FrameInterpolation_ShouldInterpolateFrame(true);
}
}
#else
@@ -5667,6 +5689,10 @@ 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;
+
+ // @port: Tag the transform.
+ FrameInterpolation_RecordOpenChild("func_800691B8", TAG_OBJECT(arg2));
+
func_800652D4(sp5C, sp54, player->size * 0.5);
gSPDisplayList(gDisplayListHead++, D_0D008D58);
gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
@@ -5678,6 +5704,9 @@ void func_800691B8(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
gSPVertex(gDisplayListHead++, D_800E87C0, 4, 0);
gSPDisplayList(gDisplayListHead++, D_0D008DA0);
gMatrixEffectCount++;
+
+ // @port Pop the transform id.
+ FrameInterpolation_RecordCloseChild();
}
}
@@ -5737,6 +5766,10 @@ 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;
+
+ // @port: Tag the transform.
+ FrameInterpolation_RecordOpenChild("func_800696CC", TAG_OBJECT(arg2));
+
func_800652D4(sp5C, sp54, player->size * arg4);
gSPDisplayList(gDisplayListHead++, D_0D008D58);
gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
@@ -5748,6 +5781,9 @@ void func_800696CC(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3, f32 arg4)
gSPVertex(gDisplayListHead++, D_800E87C0, 4, 0);
gSPDisplayList(gDisplayListHead++, D_0D008DA0);
gMatrixEffectCount += 1;
+
+ // @port Pop the transform id.
+ FrameInterpolation_RecordCloseChild();
}
}
@@ -5764,6 +5800,10 @@ 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;
+
+ // @port: Tag the transform.
+ FrameInterpolation_RecordOpenChild("func_80069938", TAG_OBJECT(arg2));
+
func_800652D4(sp5C, sp54, player->unk_258[30 + arg2].unk_00C * player->size);
gSPDisplayList(gDisplayListHead++, D_0D008D58);
gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
@@ -5775,6 +5815,9 @@ void func_80069938(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
gSPVertex(gDisplayListHead++, D_800E87C0, 4, 0);
gSPDisplayList(gDisplayListHead++, D_0D008DA0);
gMatrixEffectCount += 1;
+
+ // @port Pop the transform id.
+ FrameInterpolation_RecordCloseChild();
}
}
@@ -6058,8 +6101,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 +6134,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 +6235,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 +6617,10 @@ 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(((u32) player->unk_258[var_s2].unk_012 << 8) + (playerId << 16) + var_s2));
+
switch (player->unk_258[var_s2].unk_012) {
case 1:
if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) {
@@ -6686,6 +6741,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)))) {
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 <string.h>
+#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..e01df8954 100644
--- a/src/engine/Matrix.cpp
+++ b/src/engine/Matrix.cpp
@@ -1,6 +1,7 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#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<Mtx>& 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
@@ -137,6 +136,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/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) {
+ 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<Mtx> Shadows;
std::vector<Mtx> Karts;
std::vector<Mtx> Effects;
+ std::vector<Mtx> Persp;
+ std::vector<Mtx> LookAt;
} Matrix;
public:
explicit World();
+ ~World();
- void AddCourse(Course* course);
+ Course* AddCourse(std::unique_ptr<Course> 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<typename T>
+ void SetCourseByType() {
+ for (const auto& course : Courses) {
+ if (dynamic_cast<T*>(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<std::shared_ptr<TrainCrossing>> Crossings;
// Holds all available courses
- std::vector<Course*> Courses;
+ std::vector<std::unique_ptr<Course>> 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<FVector> 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<GameObject*> 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..2bd58ef13 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"
@@ -34,6 +35,7 @@ OGrandPrixBalloons::OGrandPrixBalloons(const FVector& pos) {
find_unused_obj_index(&gObjectParticle3[i]);
init_object(gObjectParticle3[i], 0);
}
+ // printf("primAlfa %d\n", object->primAlpha);
}
void OGrandPrixBalloons::Tick() {
@@ -73,7 +75,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 +86,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 +107,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 +139,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 +147,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 +155,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 +198,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 +223,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);
}
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..988d3bc22 100644
--- a/src/engine/objects/Lakitu.cpp
+++ b/src/engine/objects/Lakitu.cpp
@@ -2,6 +2,7 @@
#include <libultra/gbi.h>
#include "Lakitu.h"
#include <vector>
+#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",(u32) 3939848893);
+
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/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 <port/interpolation/FrameInterpolation.h>
+#include <port/interpolation/matrix.h>
#include "collision_viewer.h"
#include "math_util.h"
diff --git a/src/enhancements/freecam/freecam.cpp b/src/enhancements/freecam/freecam.cpp
index 86dfef575..4efc5fcfb 100644
--- a/src/enhancements/freecam/freecam.cpp
+++ b/src/enhancements/freecam/freecam.cpp
@@ -4,6 +4,7 @@
#include "port/Game.h"
#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h>
#include <window/Window.h>
+#include "port/interpolation/FrameInterpolation.h"
extern "C" {
#include <macros.h>
@@ -85,7 +86,7 @@ void freecam(Camera* camera, Player* player, s8 index) {
if (enabled && (player == gPlayerOne)) {
freecam_loop(camera, player, index);
} else {
- func_8001E45C(camera, player, index);
+ func_8001EE98(gPlayerOneCopy, camera, index);
}
}
@@ -104,7 +105,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 +389,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 <camera.h>
#include "freecam_engine.h"
-FreeCam freeCam;
-
#include <math.h>
+FreeCam freeCam;
+
f32 gDampValue = 0.99f;
f32 gRotDampValue = 0.96f;
diff --git a/src/gbiMacro.c b/src/gbiMacro.c
index 5fa0ab171..007d7d281 100644
--- a/src/gbiMacro.c
+++ b/src/gbiMacro.c
@@ -18,5 +18,5 @@ UNUSED void gfx_func_80040D00(void) {
guOrtho(&gGfxPool->mtxScreen, 0.0f, SCREEN_WIDTH, 0.0f, SCREEN_HEIGHT, -1.0f, 1.0f, 1.0f);
gSPPerspNormalize(gDisplayListHead++, 0xFFFF);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gGfxPool), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
- gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gIdentityMatrix), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ //gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gIdentityMatrix), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
}
diff --git a/src/main.c b/src/main.c
index 7b7e05cda..c3f6f27d7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -44,6 +44,7 @@
#include "buffers/gfx_output_buffer.h"
#include <bridge/gfxdebuggerbridge.h>
#include "enhancements/freecam/freecam.h"
+#include "port/interpolation/FrameInterpolation.h"
#include "engine/wasm.h"
#include "port/Game.h"
#include "engine/Matrix.h"
@@ -647,7 +648,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 +687,7 @@ void calculate_updaterate(void) {
if (targetFPS < 60) {
gTickLogic = 2;
} else {
- gTickLogic = 1; // Perform logic update
+ gTickLogic = 2; // Perform logic update
}
}
@@ -694,8 +695,8 @@ 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 = 1; // Perform visual update
}
void display_debug_info(void) {
@@ -758,9 +759,15 @@ void process_game_tick(void) {
func_800382DC();
}
- // Editor requires this for camera movement.
- func_8001EE98(gPlayerOneCopy, camera1, 0);
+ // This looks like it should be in the switch.
+ // But it needs to be here for player 1 to work in all modes.
+ 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 +937,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 +975,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 <common_structs.h>
#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..3163b89b4 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) {
@@ -76,4 +77,5 @@ 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);
guMtxF2L(mf, m);
+ FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mf, m);
}
diff --git a/src/os/guPerspectiveF.c b/src/os/guPerspectiveF.c
index 062d42751..fc65c6e80 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;
@@ -37,4 +38,5 @@ void guPerspective(Mtx* m, u16* perspNorm, float fovy, float aspect, float near,
float mat[4][4];
guPerspectiveF(mat, perspNorm, fovy, aspect, near, far, scale);
guMtxF2L(mat, m);
+ FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mat, 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..70ea4054c 100644
--- a/src/port/Engine.cpp
+++ b/src/port/Engine.cpp
@@ -24,6 +24,7 @@
#include "window/gui/resource/FontFactory.h"
#include "SpaghettiGui.h"
+#include "port/interpolation/FrameInterpolation.h"
#include <graphic/Fast3D/Fast3dWindow.h>
#include <graphic/Fast3D/interpreter.h>
//#include <Fast3D/gfx_rendering_api.h>
@@ -225,6 +226,28 @@ bool GameEngine::GenAssetFile() {
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<uint32_t>(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 +298,9 @@ void GameEngine::Destroy() {
#ifdef __SWITCH__
Ship::Switch::Exit();
#endif
+ GameUI::Destroy();
+ delete GameEngine::Instance;
+ GameEngine::Instance = nullptr;
}
bool ShouldClearTextureCacheAtEndOfFrame = false;
@@ -301,16 +327,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<std::unordered_map<Mtx*, MtxF>>& mtx_replacements) {
auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(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 +355,46 @@ void GameEngine::RunCommands(Gfx* Commands) {
}
void GameEngine::ProcessGfxCommands(Gfx* commands) {
+ std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements;
+ int target_fps = GameEngine::Instance->GetInterpolationFPS();
+ 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<Fast::Fast3dWindow>(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 +512,9 @@ ImFont* GameEngine::CreateFontWithSize(float size, std::string fontPath) {
initData->Path = fontPath;
std::shared_ptr<Ship::Font> fontData = std::static_pointer_cast<Ship::Font>(
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;
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<std::unordered_map<Mtx*, MtxF>>& 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<PodiumCeremony> 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<Course*>{ gLuigiRaceway, gMooMooFarm, gKoopaTroopaBeach, gKalimariDesert });
- gFlowerCup = new Cup("mk:flower_cup", "flower cup",
- std::vector<Course*>{ gToadsTurnpike, gFrappeSnowland, gChocoMountain, gMarioRaceway });
- gStarCup = new Cup("mk:star_cup", "star cup",
- std::vector<Course*>{ gWarioStadium, gSherbetLand, gRoyalRaceway, gBowsersCastle });
- gSpecialCup = new Cup("mk:special_cup", "special cup",
- std::vector<Course*>{ gDkJungle, gYoshiValley, gBansheeBoardwalk, gRainbowRoad });
- gBattleCup =
- new Cup("mk:battle_cup", "battle", std::vector<Course*>{ gBigDonut, gBlockFort, gDoubleDeck, gSkyscraper });
+ Course* mario = gWorldInstance.AddCourse(std::make_unique<MarioRaceway>());
+ Course* choco = gWorldInstance.AddCourse(std::make_unique<ChocoMountain>());
+ Course* bowser = gWorldInstance.AddCourse(std::make_unique<BowsersCastle>());
+ Course* banshee = gWorldInstance.AddCourse(std::make_unique<BansheeBoardwalk>());
+ Course* yoshi = gWorldInstance.AddCourse(std::make_unique<YoshiValley>());
+ Course* frappe = gWorldInstance.AddCourse(std::make_unique<FrappeSnowland>());
+ Course* koopa = gWorldInstance.AddCourse(std::make_unique<KoopaTroopaBeach>());
+ Course* royal = gWorldInstance.AddCourse(std::make_unique<RoyalRaceway>());
+ Course* luigi = gWorldInstance.AddCourse(std::make_unique<LuigiRaceway>());
+ Course* mooMoo = gWorldInstance.AddCourse(std::make_unique<MooMooFarm>());
+ Course* toads = gWorldInstance.AddCourse(std::make_unique<ToadsTurnpike>());
+ Course* kalimari = gWorldInstance.AddCourse(std::make_unique<KalimariDesert>());
+ Course* sherbet = gWorldInstance.AddCourse(std::make_unique<SherbetLand>());
+ Course* rainbow = gWorldInstance.AddCourse(std::make_unique<RainbowRoad>());
+ Course* wario = gWorldInstance.AddCourse(std::make_unique<WarioStadium>());
+ Course* block = gWorldInstance.AddCourse(std::make_unique<BlockFort>());
+ Course* skyscraper = gWorldInstance.AddCourse(std::make_unique<Skyscraper>());
+ Course* doubleDeck = gWorldInstance.AddCourse(std::make_unique<DoubleDeck>());
+ Course* dkJungle = gWorldInstance.AddCourse(std::make_unique<DKJungle>());
+ Course* bigDonut = gWorldInstance.AddCourse(std::make_unique<BigDonut>());
+ Course* harbour = gWorldInstance.AddCourse(std::make_unique<Harbour>());
+ Course* testCourse = gWorldInstance.AddCourse(std::make_unique<TestCourse>());
+
+ gPodiumCeremony = std::make_unique<PodiumCeremony>();
+
+ // 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<MarioRaceway*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsLuigiRaceway() { return dynamic_cast<LuigiRaceway*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsChocoMountain() { return dynamic_cast<ChocoMountain*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsBowsersCastle() { return dynamic_cast<BowsersCastle*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsBansheeBoardwalk() { return dynamic_cast<BansheeBoardwalk*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsYoshiValley() { return dynamic_cast<YoshiValley*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsFrappeSnowland() { return dynamic_cast<FrappeSnowland*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsKoopaTroopaBeach() { return dynamic_cast<KoopaTroopaBeach*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsRoyalRaceway() { return dynamic_cast<RoyalRaceway*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsMooMooFarm() { return dynamic_cast<MooMooFarm*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsToadsTurnpike() { return dynamic_cast<ToadsTurnpike*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsKalimariDesert() { return dynamic_cast<KalimariDesert*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsSherbetLand() { return dynamic_cast<SherbetLand*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsRainbowRoad() { return dynamic_cast<RainbowRoad*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsWarioStadium() { return dynamic_cast<WarioStadium*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsBlockFort() { return dynamic_cast<BlockFort*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsSkyscraper() { return dynamic_cast<Skyscraper*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsDoubleDeck() { return dynamic_cast<DoubleDeck*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsDkJungle() { return dynamic_cast<DKJungle*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsBigDonut() { return dynamic_cast<BigDonut*>(gWorldInstance.CurrentCourse) != nullptr; }
+bool IsPodiumCeremony() { return dynamic_cast<PodiumCeremony*>(gWorldInstance.CurrentCourse) != nullptr; }
+
+void SelectMarioRaceway() { gWorldInstance.SetCourseByType<MarioRaceway>(); }
+void SelectLuigiRaceway() { gWorldInstance.SetCourseByType<LuigiRaceway>(); }
+void SelectChocoMountain() { gWorldInstance.SetCourseByType<ChocoMountain>(); }
+void SelectBowsersCastle() { gWorldInstance.SetCourseByType<BowsersCastle>(); }
+void SelectBansheeBoardwalk() { gWorldInstance.SetCourseByType<BansheeBoardwalk>(); }
+void SelectYoshiValley() { gWorldInstance.SetCourseByType<YoshiValley>(); }
+void SelectFrappeSnowland() { gWorldInstance.SetCourseByType<FrappeSnowland>(); }
+void SelectKoopaTroopaBeach() { gWorldInstance.SetCourseByType<KoopaTroopaBeach>(); }
+void SelectRoyalRaceway() { gWorldInstance.SetCourseByType<RoyalRaceway>(); }
+void SelectMooMooFarm() { gWorldInstance.SetCourseByType<MooMooFarm>(); }
+void SelectToadsTurnpike() { gWorldInstance.SetCourseByType<ToadsTurnpike>(); }
+void SelectKalimariDesert() { gWorldInstance.SetCourseByType<KalimariDesert>(); }
+void SelectSherbetLand() { gWorldInstance.SetCourseByType<SherbetLand>(); }
+void SelectRainbowRoad() { gWorldInstance.SetCourseByType<RainbowRoad>(); }
+void SelectWarioStadium() { gWorldInstance.SetCourseByType<WarioStadium>(); }
+void SelectBlockFort() { gWorldInstance.SetCourseByType<BlockFort>(); }
+void SelectSkyscraper() { gWorldInstance.SetCourseByType<Skyscraper>(); }
+void SelectDoubleDeck() { gWorldInstance.SetCourseByType<DoubleDeck>(); }
+void SelectDkJungle() { gWorldInstance.SetCourseByType<DKJungle>(); }
+void SelectBigDonut() { gWorldInstance.SetCourseByType<BigDonut>(); }
+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 <libultraship/bridge.h>
+
+#include <vector>
+#include <map>
+#include <unordered_map>
+#include <math.h>
+#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<const void*, uintptr_t> 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<label, vector<Path>> children;
+ map<Op, vector<Data>> ops;
+ vector<pair<Op, size_t>> items;
+};
+
+struct Recording {
+ Path root_path;
+};
+
+bool is_recording;
+vector<Path*> 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*, MtxF> 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<Mtx*, MtxF> FrameInterpolation_Interpolate(float step) {
+ InterpolateCtx ctx;
+ ctx.step = step;
+ ctx.w = 1.0f - step;
+ ctx.interpolate_branch(&previous_recording.root_path, &current_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(&current_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 <libultraship.h>
+#include <common_structs.h>
+
+#ifdef __cplusplus
+
+#include <unordered_map>
+
+
+
+std::unordered_map<Mtx*, MtxF> 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 <libultraship.h>
+#include <math.h>
+#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<Ship::File> 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<CtlEntry> {
using Resource::Resource;
AudioBank() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {}
+ ~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<AudioBankSample> {
using Resource::Resource;
AudioSample() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {}
+ ~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>();
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>();
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..cb709e16b 100644
--- a/src/port/ui/PortMenu.cpp
+++ b/src/port/ui/PortMenu.cpp
@@ -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<IntSliderOptions>(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<IntSliderOptions>(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();
}
@@ -368,6 +368,7 @@ void PortMenu::AddEnhancements() {
.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)
@@ -380,6 +381,7 @@ void PortMenu::AddEnhancements() {
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Properties")->ToggleVisibility();
})
.Options(UIWidgets::CheckboxOptions({{ .tooltip = "Edit the universe!"}}));
+ #endif
}
#ifdef __SWITCH__
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 <assets/wario_stadium_data.h>
#include <assets/frappe_snowland_data.h>
#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..a89df5b40 100644
--- a/src/racing/framebuffer_effects.c
+++ b/src/racing/framebuffer_effects.c
@@ -37,7 +37,7 @@ void FB_CreateFramebuffers(void) {
void FB_CopyToFramebuffer(Gfx** gfxP, s32 fb_src, s32 fb_dest, u8 oncePerFrame, u8* hasCopied) {
Gfx* gfx = *gfxP;
- gSPMatrix(gfx++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ // gSPMatrix(gfx++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetOtherMode(gfx++,
G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_NONE | G_TL_TILE |
@@ -110,7 +110,7 @@ void FB_WriteFramebufferSliceToCPU(Gfx** gfxP, void* buffer, u8 byteSwap) {
void FB_DrawFromFramebuffer(Gfx** gfxP, s32 fb, u8 alpha) {
Gfx* gfx = *gfxP;
- gSPMatrix(gfx++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ //gSPMatrix(gfx++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetEnvColor(gfx++, 255, 255, 255, alpha);
diff --git a/src/racing/math_util.c b/src/racing/math_util.c
index ac34ceda7..127961703 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 <port/interpolation/FrameInterpolation.h>
+#include <port/interpolation/matrix.h>
#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,19 +1144,28 @@ 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;
if (is_visible_between_angle(plus_fov_angle, minus_fov_angle, temp) == 1) {
- return distance;
+ return 0;
}
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..bf16380d3 100644
--- a/src/racing/render_courses.c
+++ b/src/racing/render_courses.c
@@ -7,6 +7,7 @@
#include <course.h>
#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,15 @@ 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);
+ //FrameInterpolation_RecordCloseChild();
+
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..62399dfea 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,15 +756,39 @@ 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;
+
+ 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();
+}
+
+extern s32 D_func_800652D4_counter;
+void render_screens(s32 mode, s32 cameraId, s32 playerId) {
Mat4 matrix;
s32 screenId = 0;
s32 screenMode = SCREEN_MODE_1P;
+D_func_800652D4_counter = 0;
switch (mode) {
case RENDER_SCREEN_MODE_1P_PLAYER_ONE:
@@ -817,7 +847,14 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
}
struct UnkStruct_800DC5EC* screen = &D_8015F480[screenId];
- Camera* camera = &cameras[cameraId];
+ Camera* 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 +865,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);
-
- gSPPerspNormalize(gDisplayListHead++, perspNorm);
- gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[cameraId]),
- G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
+ // Setup camera perspective and lookAt
+ setup_camera(camera, playerId, cameraId, screen);
+
+ // 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 +926,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 <assets/donkeykong_kart.h>
#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 <common_structs.h>
#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..96b6dcd2e 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 free cam
+ 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..0435a69d7 100644
--- a/src/update_objects.c
+++ b/src/update_objects.c
@@ -40,6 +40,8 @@
#include <assets/boo_frames.h>
#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 };
@@ -2104,19 +2106,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;
@@ -2455,20 +2457,28 @@ void update_snowflakes(void) {
}
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 object'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) {