Add Interpolation (#204)

* initial work

* more work

* progress

* Fixed slow fps

* Add Lywx changes

* Interp Works

* Test default tick/logic update

* Added missing include (#202)

* Added missing include

* More missing includes

---------

Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>

* test

* Revert "test"

This reverts commit 1a810d74cc.

* Interp Item box

* Actually interpolate item box

* fix clouds

* interp player?

* Test 2

* Fix mistake

* tag and fix item boxes

* tag fake item box and whatever func_800696CC is

* these aren't needed

* tag karts

* Slightly better falling rocks(still needs work)

* Tag Smoke and Dust

* Removed unneeded code from falling_rock

* tag whatever func_80051ABC is

* add missing rotate x coord

* GrandPrixBallon/kart shadow

* Green shells tag, and added comments I neglected to add before.

* doesn't compile on win

* Fixes

* Disabled camera interpolation

* Balloons fixes

* progress

* set_transform_matrix compiles

* Compile setTransformMatrix

* More transforms interp

* Add more interps

* matrix

* Matrix multi interp

* Fix interpolation camera bug

* Missing includes needed for Linux.

* Excluded access to HM64 Labs on Switch.

* interpolation tags for various objects

* Bowser castle statue flame interpolated.

* tag hedgehogs

* cloud interpolation

* Interpolated smoke particles from shells

* cloud interpolation refactor

* Interpolated snowflakes

* Interpolated penguins, also added comment tags to places I missed.

* tag Snowman interpolation

* Interpolated player reflection(sherbet land)

* Forgot to uncomment stuff while testing

* better tag

* tag leaves

* Set the default FPS to 30

* tag hud

* Fixed "Match Refresh Rate" option

* adjust draw distance

* remove innecessary rock tag

* rag rocks

* better tag

* Tagged player rank placement in HUD

* Tagged Bat, Boos, and TrashBin(Banshee Boardwalk objects)

* Refactor render_screens and fix editor raycast

* better object interpolation

* shift is not needed here

* fix tag

* fix tags

* mole comments

* comment

* Changed how shell flames are interpolated.

* interpolated ended scene fireworks.

* Tagged star particles in the ending scene

* Shell flames handled better.

* this isn't needed

* Fix multiplayer cameras

* Fixed loading battle maps.

* Tagged battle balloons

* Some fixes for battle mode

* No longer needed changes toAFinishline with the changes mega made.

* Tag finishline

* fix to make it compile with cmake 3.31

* changed mtxf_multiplication() to fix vert explosion in Desert & DK parkway.(provided by Coco.)

* fix memory leaks, avoid invalidate texture (#207)

* Fixed macos

* More stupid fixes

* update with main and update torch and lus and enable action on this branch

* Update FrameInterpolation.h

* Update FrameInterpolation.cpp

* fix some memory leak

* Update torch

* Update torch

* update torch and lus

* reduce texture import

* don't use fork of torch and lus

* Update torch

* Update torch

---------

Co-authored-by: Lywx <kiritodev01@gmail.com>

* Refactor World::Courses to unique_ptr (#211)

* wip course unique ptr

* Track unique_ptr : This probably compiles

* Finish impl Courses as unique_ptr

* Fix error

* Fixes

* More fixes

* Cleanup

* Remove old vars

---------

Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>

* particle boat and train

* fix player particle interpolation

* add modify interpolation target fps in menu

* fix windows

* Update libultraship

* Fix logo interp

* Interp SetTextMatrix

* Fix freecam camera

* Clarify comment

* Clarify func

* fix linux compilation

* Update Thwomp.cpp

* Update Thwomp.h

* Update render.inc.c

* Update render.inc.c

* Update gbiMacro.c

* interp falling rock shadow

* Revert change that has no explanation

* Update code_80057C60.c

* Update code_80057C60.c

* Update GrandPrixBalloons.cpp

* Update Lakitu.cpp

* Update framebuffer_effects.c

* Update render_courses.c

---------

Co-authored-by: Sonic Dreamcaster <alejandro.asenjo88@gmail.com>
Co-authored-by: KiritoDv <kiritodev01@gmail.com>
Co-authored-by: sitton76 <58642183+sitton76@users.noreply.github.com>
Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
Co-authored-by: coco875 <59367621+coco875@users.noreply.github.com>
Co-authored-by: coco875 <pereira.jannin@gmail.com>
This commit is contained in:
MegaMech 2025-06-07 21:38:12 -06:00 committed by GitHub
parent a67fbb6442
commit 44db9bab77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
92 changed files with 3234 additions and 1020 deletions

View File

@ -2,7 +2,7 @@ name: GenerateBuilds
on:
push:
branches: ["main"]
branches: ["*"]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

@ -1 +1 @@
Subproject commit 6a3f6cd327b99f617b623e5b9a3afeae460aac2b
Subproject commit 47b4d7f6ae47e4ac900d080f485d1a6145985144

View File

@ -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();
}

View File

@ -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) {
@ -61,6 +65,13 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox)
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIA, G_CC_MODULATEIA);
/*
* In the original game, the question mark texture would become corrupted. Thus, this code
* makes it disappear to hide the issue. Since the texture no longer becomes corrupted, this
* fix can be removed.
*/
#ifdef TARGET_N64
if ((fakeItemBox->rot[1] < 0xAA1) && (fakeItemBox->rot[1] > 0)) {
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
} else if ((fakeItemBox->rot[1] >= 0x6AA5) && (fakeItemBox->rot[1] < 0x754E)) {
@ -70,9 +81,12 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox)
} else if ((fakeItemBox->rot[1] >= 0xC711) && (fakeItemBox->rot[1] < 0xD1BA)) {
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
} else {
#endif
gDPSetBlendMask(gDisplayListHead++, 0xFF);
gDPSetRenderMode(gDisplayListHead++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2);
#ifdef TARGET_N64
}
#endif
gSPDisplayList(gDisplayListHead++, D_0D003090);
} else {
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
@ -163,4 +177,6 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox)
gSPDisplayList(gDisplayListHead++, D_0D0030F8);
gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK);
}
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
}

View File

@ -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,29 @@ void render_actor_falling_rock(Camera* camera, struct FallingRock* rock) {
sp98[1] = 0;
sp98[2] = 0;
sp8C[1] = height + 2.0f;
mtxf_pos_rotation_xyz(sp4C, sp8C, sp98);
if (render_set_position(sp4C, 0) == 0) {
FrameInterpolation_RecordOpenChild("rock_shadow", (uintptr_t) rock);
mtxf_pos_rotation_xyz(mtx, sp8C, sp98);
if (render_set_position(mtx, 0) == 0) {
FrameInterpolation_RecordCloseChild();
return;
}
gSPDisplayList(gDisplayListHead++, d_course_choco_mountain_dl_6F88);
FrameInterpolation_RecordCloseChild();
}
}
mtxf_pos_rotation_xyz(sp4C, rock->pos, rock->rot);
if (render_set_position(sp4C, 0) == 0) {
// @port: Tag the transform.
FrameInterpolation_RecordOpenChild("rock", (uintptr_t) rock);
mtxf_pos_rotation_xyz(mtx, rock->pos, rock->rot);
if (render_set_position(mtx, 0) == 0) {
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
return;
}
gSPDisplayList(gDisplayListHead++, d_course_choco_mountain_dl_falling_rock);
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
}

View File

@ -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,6 +82,13 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIA, G_CC_MODULATEIA);
/*
* In the original game, the question mark texture would become corrupted. Thus, this code
* makes it disappear to hide the issue. Since the texture no longer becomes corrupted, this
* fix can be removed.
*/
#ifdef TARGET_N64
if ((item_box->rot[1] < 0xAA1) && (item_box->rot[1] > 0)) {
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
} else if ((item_box->rot[1] >= 0x6AA5) && (item_box->rot[1] < 0x754E)) {
@ -83,16 +98,21 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
} else if ((item_box->rot[1] >= 0xC711) && (item_box->rot[1] < 0xD1BA)) {
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetBlendMask(gDisplayListHead++, 0xFF);
gDPSetRenderMode(gDisplayListHead++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2);
#endif
gDPSetBlendMask(gDisplayListHead++, 0xFF);
gDPSetRenderMode(gDisplayListHead++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2);
#ifdef TARGET_N64
}
#endif
gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
gSPDisplayList(gDisplayListHead++, D_0D003090);
} else {
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK);
gDPSetBlendMask(gDisplayListHead++, 0xFF);
thing = item_box->someTimer;
mtxf_pos_rotation_xyz(someMatrix1, item_box->pos, item_box->rot);
if (thing < 10.0f) {
someMultiplier = 1.0f;
@ -116,6 +136,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
}
gSPDisplayList(gDisplayListHead++, D_0D003158);
temp_f2_2 = 0.8f * thing;
temp_f12 = 0.5f * thing;
someVec1[0] = temp_f2_2;
@ -128,10 +149,12 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
}
gSPDisplayList(gDisplayListHead++, D_0D0031B8);
temp_f0_2 = -0.5f * thing;
someVec1[0] = temp_f2_2;
someVec1[1] = 1.2f * thing;
someVec1[2] = temp_f0_2;
add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1);
if (!render_set_position(someMatrix2, 0)) {
@ -139,6 +162,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
}
gSPDisplayList(gDisplayListHead++, D_0D003128);
if (!(item_box->someTimer & 1)) {
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
} else {
@ -147,6 +171,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
someVec1[0] = 0.0f;
someVec1[1] = 1.8f * thing;
someVec1[2] = -1.0f * thing;
add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1);
if (!render_set_position(someMatrix2, 0)) {
@ -154,10 +179,12 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
}
gSPDisplayList(gDisplayListHead++, D_0D0031E8);
temp_f0_3 = -0.8f * thing;
someVec1[0] = temp_f0_3;
someVec1[1] = 0.6f * thing;
someVec1[2] = temp_f0_2;
add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1);
if (!render_set_position(someMatrix2, 0)) {
@ -165,9 +192,11 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
}
gSPDisplayList(gDisplayListHead++, D_0D003188);
someVec1[0] = temp_f0_3;
someVec1[1] = temp_f2;
someVec1[2] = temp_f12;
add_translate_mat4_vec3f(someMatrix1, someMatrix2, someVec1);
if (!render_set_position(someMatrix2, 0)) {
@ -175,8 +204,11 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
}
gSPDisplayList(gDisplayListHead++, D_0D0030F8);
gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK);
}
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
}
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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:

View File

@ -18,17 +18,19 @@
#include "spawn_players.h"
#include "enhancements/freecam/freecam_engine.h"
#include "enhancements/freecam/freecam.h"
#include "port/interpolation/FrameInterpolation.h"
#include "engine/GameAPI.h"
#include "port/Game.h"
f32 D_800DDB30[] = { 0.4f, 0.6f, 0.275f, 0.3f };
Camera cameras[4];
Camera cameras[5];
Camera* camera1 = &cameras[0];
Camera* camera2 = &cameras[1];
Camera* camera3 = &cameras[2];
Camera* camera4 = &cameras[3];
Camera* gFreecamCamera = &cameras[4];
UNUSED s32 D_801649D0[2];
@ -193,6 +195,146 @@ void camera_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cam
func_802B7F7C(camera->pos, camera->lookAt, camera->rot);
}
// Many arrays are hard-coded to 4. Skip those.
void freecam_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cameraId) {
Player* player = gPlayerOne;
Camera* camera = &cameras[cameraId];
camera->cameraId = cameraId;
//D_80152300[cameraId] = arg4;
switch (arg4) {
case 0:
case 1:
case 3:
case 8:
case 9:
case 10:
D_80164A89 = 0;
camera->pos[0] = posX;
camera->pos[1] = posY;
camera->pos[2] = posZ;
camera->someBitFlags = 0;
camera->lookAt[0] = 0.0f;
camera->lookAt[2] = 150.0f;
camera->lookAt[1] = posY - 3.0;
camera->up[0] = 0.0f;
camera->up[1] = 1.0f;
camera->up[2] = 0.0f;
camera->playerId = (s16) 0;
camera->unk_B0 = 0;
camera->unk_A0 = 0.0f;
// D_801649D8[cameraId] = 20.0f;
// D_801649E8[cameraId] = 10.0f;
// D_801649F8[cameraId] = 7.0f;
// D_80164A2C = 0;
// D_80164A30 = 30.0f;
// D_80164A38[cameraId] = 0.0f;
// D_80164A48[cameraId] = 0.0f;
// D_80164A90[cameraId] = 0.0f;
// D_80164AA0[cameraId] = 0.0f;
// D_80164A78[cameraId] = D_800DDB30[gActiveScreenMode];
// D_80164A18[cameraId] = 0;
// D_80164A08[cameraId] = 0;
// D_80164498[cameraId] = 0.0f;
camera->unk_94.unk_8 = 0;
camera->unk_94.unk_0 = 0.0f;
player += cameraId;
camera->unk_2C = player->rotation[1];
camera->unk_AC = player->rotation[1];
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
if (gModeSelection == BATTLE) {
camera->unk_30[0] = 0.0f;
camera->unk_30[1] = 11.6f;
camera->unk_30[2] = -38.5f;
camera->unk_3C[0] = 0.0f;
camera->unk_3C[1] = 0.0f;
camera->unk_3C[2] = 19.2f;
D_80164A88 = 0;
} else {
camera->unk_30[0] = 0.0f;
camera->unk_30[1] = 9.5f;
camera->unk_30[2] = -50.0f;
camera->unk_3C[0] = 0.0f;
camera->unk_3C[1] = 0.0f;
camera->unk_3C[2] = 70.0f;
}
break;
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
if (gModeSelection == BATTLE) {
camera->unk_30[0] = 0.0f;
camera->unk_30[1] = 11.6f;
camera->unk_30[2] = -38.5f;
camera->unk_3C[0] = 0.0f;
camera->unk_3C[1] = 0.0f;
camera->unk_3C[2] = 19.2f;
} else {
camera->unk_30[0] = 0.0f;
camera->unk_30[1] = 9.6f;
camera->unk_30[2] = -35.0f;
camera->unk_3C[0] = 0.0f;
camera->unk_3C[1] = 0.0f;
camera->unk_3C[2] = 30.0f;
}
break;
case SCREEN_MODE_3P_4P_SPLITSCREEN:
if (gModeSelection == BATTLE) {
camera->unk_30[0] = 0.0f;
camera->unk_30[1] = 11.6f;
camera->unk_30[2] = -38.5f;
camera->unk_3C[0] = 0.0f;
camera->unk_3C[1] = 0.0f;
camera->unk_3C[2] = 19.2f;
} else {
camera->unk_30[0] = 0.0f;
camera->unk_30[1] = 9.0f;
camera->unk_30[2] = -40.0f;
camera->unk_3C[0] = 0.0f;
camera->unk_3C[1] = 0.0f;
camera->unk_3C[2] = 18.0f;
}
break;
}
//func_80014DE4(cameraId);
// if (D_80164678[cameraId] == 0) {
if (D_80164A28 == 1) {
// gCameraZoom[cameraId] = 80.0f;
} else {
// gCameraZoom[cameraId] = 40.0f;
}
camera->unk_B4 = gCameraZoom[0];
// }
// if (D_80164678[cameraId] == 1) {
// if (D_80164A28 == 1) {
// gCameraZoom[cameraId] = 100.0f;
// } else {
// gCameraZoom[cameraId] = 60.0f;
// }
// camera->unk_B4 = gCameraZoom[cameraId];
// // }
// if (D_80164678[cameraId] == 2) {
// if (D_80164A28 == 1) {
// gCameraZoom[cameraId] = 100.0f;
// } else {
// gCameraZoom[cameraId] = 60.0f;
// }
// camera->unk_B4 = gCameraZoom[cameraId];
// D_80164A38[cameraId] = 20.0f;
// D_80164A48[cameraId] = 1.5f;
// D_80164A78[cameraId] = 1.0f;
// }
break;
}
func_802B7F7C(camera->pos, camera->lookAt, camera->rot);
}
// Thwomp related
void func_8001CA10(Camera* camera) {
camera->unk_94.unk_8 = 0;
@ -241,7 +383,7 @@ void func_8001CA78(UNUSED Player* player, Camera* camera, Vec3f arg2, f32* arg3,
arg2[2] = camera->lookAt[2];
calculate_orientation_matrix(sp74, 0, 1, 0, -0x00008000);
mtxf_translate_vec3f_mat3(sp5C, sp74);
if (GetCourse() == GetToadsTurnpike()) {
if (IsToadsTurnpike()) {
var_f14 = sp5C[0];
} else {
var_f14 = sp5C[0] + temp_s2->posX;
@ -252,7 +394,7 @@ void func_8001CA78(UNUSED Player* player, Camera* camera, Vec3f arg2, f32* arg3,
arg2[1] += (temp_f18 - camera->lookAt[1]) * 1;
arg2[2] += (temp_f16 - camera->lookAt[2]) * 1;
mtxf_translate_vec3f_mat3(sp68, sp74);
if (GetCourse() == GetToadsTurnpike()) {
if (IsToadsTurnpike()) {
var_f14 = sp68[0];
} else {
var_f14 = sp68[0] + temp_s2->posX;
@ -345,7 +487,7 @@ void func_8001CCEC(Player* player, Camera* camera, Vec3f arg2, f32* arg3, f32* a
move_f32_towards(&D_80164AA0[index], 10, 0.02f);
break;
default:
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
move_f32_towards(&D_80164A90[index], 50, 0.04f);
move_f32_towards(&D_80164AA0[index], 35, 0.04f);
} else {
@ -993,6 +1135,7 @@ void func_8001EE98(Player* player, Camera* camera, s8 index) {
break;
}
freecam(camera, player, index); // Runs func_8001E45C when freecam is disabled
//func_8001E45C(camera, player, index);
break;
case 8:
func_8001E0C4(camera, player, index);

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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,8 +2596,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) {
case 1: /* switch 1 */
CM_ActivateSecondLapLakitu(playerId); // func_80079084(playerId);
func_800C9060(playerId, SOUND_ARG_LOAD(0x19, 0x00, 0xF0, 0x15));
if ((GetCourse() == GetLuigiRaceway()) && (D_80165898 == 0) &&
(gModeSelection != (s32) TIME_TRIALS)) {
if ((IsLuigiRaceway()) && (D_80165898 == 0) && (gModeSelection != (s32) TIME_TRIALS)) {
D_80165898 = 1;
}
break;
@ -2610,7 +2617,7 @@ void func_8005CB60(s32 playerId, s32 lapCount) {
if (D_8018D114 == 2) {
D_80165800[playerId] = 0;
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
playerHUD[playerId].unk_81 = 1;
}
playerHUD[playerId].lap1CompletionTimeX = 0x0140;
@ -2927,22 +2934,22 @@ void func_8005DAF4(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8
func_8005D794(player, &player->unk_258[10 + arg1], var_f2, var_f12, var_f14, (s8) surfaceType,
(s8) var_t3);
func_8005D7D8(&player->unk_258[10 + arg1], 2, 0.46f);
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[10 + arg1], 10, 0, 0x0080);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[10 + arg1], 11, 0, 0x0080);
}
player->unk_258[10 + arg1].unk_03A = random_int(0x0010U);
@ -2951,22 +2958,22 @@ void func_8005DAF4(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8
func_8005D794(player, &player->unk_258[10 + arg1], var_f2, var_f12, var_f14, (s8) surfaceType,
(s8) var_t3);
func_8005D7D8(&player->unk_258[10 + arg1], 2, 0.46f);
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[10 + arg1], 10, 0, 0x0080);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[10 + arg1], 11, 0, 0x0080);
}
player->unk_258[10 + arg1].unk_03A = random_int(0x0010U);
@ -3193,44 +3200,44 @@ void func_8005ED48(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8
((player->unk_258[10 + arg2].unk_01E > 0) || (player->unk_258[10 + arg2].unk_01C == 0))) {
func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t3);
func_8005D7D8(&player->unk_258[10 + arg1], 5, 0.46f);
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[10 + arg1], 10, 0, 0x0080);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[10 + arg1], 11, 0, 0x0080);
}
player->unk_258[10 + arg1].unk_03A = random_int(0x0010U);
} else if (player->unk_258[10 + arg2].unk_01E > 0) {
func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t3);
func_8005D7D8(&player->unk_258[10 + arg1], 5, 0.46f);
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[10 + arg1], 0x000A, 0, 0x0080);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[10 + arg1], 0x000B, 0, 0x0080);
}
player->unk_258[10 + arg1].unk_03A = random_int(0x0010U);
@ -3394,44 +3401,44 @@ void func_8005F90C(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8
((player->unk_258[10 + arg2].unk_01E > 0) || (player->unk_258[10 + arg2].unk_01C == 0))) {
func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t1);
func_8005D7D8(&player->unk_258[10 + arg1], 4, 0.46f);
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[10 + arg1], 0x000A, 0, 0x0080);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[10 + arg1], 0x000B, 0, 0x0080);
}
player->unk_258[10 + arg1].unk_03A = random_int(0x0010U);
} else if (player->unk_258[10 + arg2].unk_01E > 0) {
func_8005D794(player, &player->unk_258[10 + arg1], var_f0, var_f2, var_f12, surfaceType, var_t1);
func_8005D7D8(&player->unk_258[10 + arg1], 4, 0.46f);
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[10 + arg1], 1, 0, 0x0080);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[10 + arg1], 7, 0, 0x0080);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[10 + arg1], 8, 0, 0x0080);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[10 + arg1], 9, 0, 0x0080);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[10 + arg1], 0x000A, 0, 0x0080);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[10 + arg1], 0x000B, 0, 0x0080);
}
player->unk_258[10 + arg1].unk_03A = random_int(0x0010U);
@ -3630,13 +3637,13 @@ void func_800608E0(Player* player, s16 arg1, UNUSED s32 arg2, s8 arg3, UNUSED s8
var_f0 = 0.0f;
}
sp4C = (D_801652A0[arg3] - player->pos[1]) - 3.0f;
if ((player->unk_0DE & 1) && (GetCourse() != GetKoopaTroopaBeach())) {
if ((player->unk_0DE & 1) && (!IsKoopaTroopaBeach())) {
var_f0 = 2.5f;
sp4C = (f32) ((f64) (D_801652A0[arg3] - player->pos[1]) + 0.1);
}
func_8005D794(player, &player->unk_258[arg1], 0.0f, 0.0f, 0.0f, (s8) 0, (s8) 0);
func_8005D7D8(&player->unk_258[arg1], 3, var_f0);
if ((GetCourse() == GetBowsersCastle()) || (GetCourse() == GetBigDonut())) {
if ((IsBowsersCastle()) || (IsBigDonut())) {
func_8005D800(&player->unk_258[arg1], 0, 0x00AF);
} else {
func_8005D800(&player->unk_258[arg1], 0x00FFFFFF, 0x00CF);
@ -3650,7 +3657,7 @@ void func_800608E0(Player* player, s16 arg1, UNUSED s32 arg2, s8 arg3, UNUSED s8
}
void func_80060B14(Player* player, s16 arg1, s32 arg2, s8 arg3, s8 arg4) {
if ((GetCourse() != GetSkyscraper()) && (GetCourse() != GetRainbowRoad())) {
if ((!IsSkyscraper()) && (!IsRainbowRoad())) {
if ((arg1 == 0) && ((player->unk_258[arg2].unk_01E > 0) || (player->unk_258[arg2].unk_01C == 0))) {
func_800608E0(player, arg1, arg2, arg3, arg4);
} else if (player->unk_258[arg2].unk_01E > 0) {
@ -3666,10 +3673,10 @@ void func_80060BCC(Player* player, s16 arg1, s32 arg2, UNUSED s8 arg3, UNUSED s8
f32 sp48;
f32 sp44;
if (GetCourse() == GetSkyscraper()) {
if (IsSkyscraper()) {
return;
}
if (GetCourse() == GetRainbowRoad()) {
if (IsRainbowRoad()) {
return;
}
sp54 = random_int(0x0168U) - 0xB4;
@ -3704,7 +3711,7 @@ void func_80060F50(Player* player, s16 arg1, UNUSED s32 arg2, s8 arg3, UNUSED s8
func_8005D794(player, &player->unk_258[arg1], 0.0f, 0.0f, 0.0f, 0, 0);
func_8005D7D8(&player->unk_258[arg1], 5, 4.0f);
if ((GetCourse() == GetBowsersCastle()) || (GetCourse() == GetBigDonut())) {
if ((IsBowsersCastle()) || (IsBigDonut())) {
func_8005D800(&player->unk_258[arg1], 0xFF0000, 0xFF);
} else {
func_8005D800(&player->unk_258[arg1], 0xFFFFFF, 0xFF);
@ -4050,22 +4057,22 @@ void func_800624D8(Player* player, UNUSED s32 arg1, UNUSED s32 arg2, UNUSED s8 a
switch (player->surfaceType) {
case DIRT:
for (var_s1 = 0; var_s1 < 10; var_s1++) {
if ((GetCourse() == GetChocoMountain()) || (GetCourse() == GetRoyalRaceway())) {
if ((IsChocoMountain()) || (IsRoyalRaceway())) {
func_8005DAD8(&player->unk_258[0x1E + var_s1], 1, 0, 0x00A8);
}
if (GetCourse() == GetKalimariDesert()) {
if (IsKalimariDesert()) {
func_8005DAD8(&player->unk_258[0x1E + var_s1], 7, 0, 0x00A8);
}
if (GetCourse() == GetMooMooFarm()) {
if (IsMooMooFarm()) {
func_8005DAD8(&player->unk_258[0x1E + var_s1], 8, 0, 0x00A8);
}
if (GetCourse() == GetWarioStadium()) {
if (IsWarioStadium()) {
func_8005DAD8(&player->unk_258[0x1E + var_s1], 9, 0, 0x00A8);
}
if (GetCourse() == GetYoshiValley()) {
if (IsYoshiValley()) {
func_8005DAD8(&player->unk_258[0x1E + var_s1], 0x000A, 0, 0x00A8);
}
if (GetCourse() == GetDkJungle()) {
if (IsDkJungle()) {
func_8005DAD8(&player->unk_258[0x1E + var_s1], 0x000B, 0, 0x00A8);
}
func_80062484(player, &player->unk_258[0x1E + var_s1], var_s1);
@ -4620,7 +4627,7 @@ void func_80064184(Player* player, s16 arg1, s8 arg2, UNUSED s8 arg3) {
f32 sp3C;
sp40 = D_801652A0[arg2] - player->pos[1] - 3.0f;
if (((player->unk_0DE & 1) != 0) && (GetCourse() != GetKoopaTroopaBeach())) {
if (((player->unk_0DE & 1) != 0) && (!IsKoopaTroopaBeach())) {
sp40 = D_801652A0[arg2] - player->pos[1] + 0.1;
}
@ -4968,9 +4975,8 @@ void func_800651F4(Player* player, UNUSED s8 arg1, UNUSED s8 arg2, s8 arg3) {
void func_800652D4(Vec3f arg0, Vec3s arg1, f32 arg2) {
Mat4 mtx;
mtxf_translate_rotate(mtx, arg0, arg1);
mtxf_scale2(mtx, arg2);
mtxf_scale(mtx, arg2);
// convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], mtx);
// gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]),
// G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
@ -5098,6 +5104,7 @@ void func_80065AB0(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
spAC[0] = 0;
spAC[1] = player->unk_048[arg3];
spAC[2] = 0;
func_800652D4(spB4, spAC, player->unk_258[10 + arg2].unk_00C * player->size);
if (var_s0 == 0) {
gSPDisplayList(gDisplayListHead++, D_0D008DB8);
@ -5667,6 +5674,7 @@ void func_800691B8(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
sp54[1] = player->unk_048[arg3];
player->unk_258[30 + arg2].unk_03A += 0x1C71;
sp54[2] = player->unk_258[30 + arg2].unk_03A;
func_800652D4(sp5C, sp54, player->size * 0.5);
gSPDisplayList(gDisplayListHead++, D_0D008D58);
gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
@ -5737,6 +5745,7 @@ void func_800696CC(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3, f32 arg4)
sp54[0] = 0;
sp54[1] = player->unk_048[arg3];
sp54[2] = 0;
func_800652D4(sp5C, sp54, player->size * arg4);
gSPDisplayList(gDisplayListHead++, D_0D008D58);
gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
@ -5764,6 +5773,7 @@ void func_80069938(Player* player, UNUSED s8 arg1, s16 arg2, s8 arg3) {
sp54[0] = 0;
sp54[1] = player->unk_048[arg3];
sp54[2] = player->unk_258[30 + arg2].unk_038;
func_800652D4(sp5C, sp54, player->unk_258[30 + arg2].unk_00C * player->size);
gSPDisplayList(gDisplayListHead++, D_0D008D58);
gDPSetTextureLUT(gDisplayListHead++, G_TT_NONE);
@ -6058,8 +6068,12 @@ void render_battle_balloon(Player* player, s8 arg1, s16 arg2, s8 arg3) {
sp12C[1] = player->unk_048[arg3];
sp12C[2] = D_8018D7D0[arg1][arg2] - (D_8018D860[arg1][arg2] * coss(temp_t1)) -
((D_8018D890[arg1][arg2] * 8) * sins(temp_t1));
// @port: Tag the transform.
FrameInterpolation_RecordOpenChild((uintptr_t) player, arg1 | arg2 << 16);
mtxf_translate_rotate(mtx, sp134, sp12C);
mtxf_scale2(mtx, var_f20);
mtxf_scale(mtx, var_f20);
// convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], sp140);
// gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]),
@ -6087,6 +6101,10 @@ void render_battle_balloon(Player* player, s8 arg1, s16 arg2, s8 arg3) {
gSPVertex(gDisplayListHead++, gBalloonVertexPlane2, 4, 0);
gSPDisplayList(gDisplayListHead++, common_square_plain_render);
gSPTexture(gDisplayListHead++, 0x0001, 0x0001, 0, G_TX_RENDERTILE, G_OFF);
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
gMatrixEffectCount++;
}
@ -6184,7 +6202,7 @@ void render_balloon(Vec3f arg0, f32 arg1, s16 arg2, s16 arg3) {
spF4[1] = camera1->rot[1];
spF4[2] = arg2;
mtxf_translate_rotate(mtx, spFC, spF4);
mtxf_scale2(mtx, arg1);
mtxf_scale(mtx, arg1);
// convert_to_fixed_point_matrix(&gGfxPool->mtxEffect[gMatrixEffectCount], sp108);
// gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount]),
// G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
@ -6566,6 +6584,9 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) {
s16 var_s2;
if ((player->unk_002 & (8 << (screenId * 4))) == (8 << (screenId * 4))) {
for (var_s2 = 0; var_s2 < 10; var_s2++) {
// @port: Tag the transform.
FrameInterpolation_RecordOpenChild("SmokeDust", TAG_SMOKE_DUST((playerId << 8) + var_s2));
switch (player->unk_258[var_s2].unk_012) {
case 1:
if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) {
@ -6586,6 +6607,8 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) {
}
break;
}
FrameInterpolation_RecordCloseChild();
FrameInterpolation_RecordOpenChild("SmokeDust", TAG_SMOKE_DUST((playerId << 8) + var_s2 + 30));
switch (player->unk_258[var_s2 + 30].unk_012) {
case 1:
case 9:
@ -6645,6 +6668,8 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) {
}
break;
}
FrameInterpolation_RecordCloseChild();
FrameInterpolation_RecordOpenChild("SmokeDust", TAG_SMOKE_DUST((playerId << 8) + var_s2 + 10));
switch (player->unk_258[var_s2 + 10].unk_012) {
case 1:
if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) {
@ -6686,6 +6711,8 @@ void func_8006D474(Player* player, s8 playerId, s8 screenId) {
}
break;
}
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
}
}
if ((gModeSelection == BATTLE) && (player->unk_002 & (2 << (screenId * 4)))) {
@ -6707,48 +6734,50 @@ void func_8006DC54(Player* player, s8 arg1, s8 arg2) {
}
}
void func_8006DD3C(Player* arg0, s8 arg1, s8 arg2) {
void func_8006DD3C(Player* player, s8 playerId, s8 arg2) {
s16 temp_s0;
s32 temp_v0;
temp_v0 = 8 << (arg2 * 4);
if (temp_v0 == (arg0->unk_002 & temp_v0)) {
if (temp_v0 == (player->unk_002 & temp_v0)) {
for (temp_s0 = 0; temp_s0 < 10; ++temp_s0) {
temp_v0 = arg0->unk_258[temp_s0].unk_012;
temp_v0 = player->unk_258[temp_s0].unk_012;
if (temp_v0 != 3) {
if (temp_v0 == 5) {
func_8006A280(arg0, arg1, temp_s0, arg2);
func_8006A280(player, playerId, temp_s0, arg2);
}
} else if (gActiveScreenMode == SCREEN_MODE_3P_4P_SPLITSCREEN) {
if (arg2 == arg1) {
func_80066998(arg0, arg1, temp_s0, arg2);
if (arg2 == playerId) {
func_80066998(player, playerId, temp_s0, arg2);
}
} else {
func_80066998(arg0, arg1, temp_s0, arg2);
func_80066998(player, playerId, temp_s0, arg2);
}
}
if (((arg0->type & 0x4000) == 0x4000) && (arg2 == arg1)) {
switch (arg0->unk_258[20].unk_012) {
if (((player->type & 0x4000) == 0x4000) && (arg2 == playerId)) {
FrameInterpolation_RecordOpenChild("onomatopoeia", TAG_SMOKE_DUST((playerId << 8) + 20));
switch (player->unk_258[20].unk_012) {
case 2:
func_80068310(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0);
func_80068310(player, playerId, player->unk_258[20].unk_00C, arg2, 0);
break;
case 3:
func_80067964(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0);
func_80067964(player, playerId, player->unk_258[20].unk_00C, arg2, 0);
break;
case 4:
func_80068724(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0);
func_80068724(player, playerId, player->unk_258[20].unk_00C, arg2, 0);
break;
case 5:
func_80068AA4(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0);
func_80068AA4(player, playerId, player->unk_258[20].unk_00C, arg2, 0);
break;
case 6:
func_80068DA0(arg0, arg1, arg0->unk_258[20].unk_00C, arg2, 0);
func_80068DA0(player, playerId, player->unk_258[20].unk_00C, arg2, 0);
break;
}
if (arg0->unk_258[21].unk_012 == 5) {
func_80067D3C(arg0, arg2, D_8018D480, 1, 1.6f, 0xFFFFFF);
func_8006801C(arg0, arg2, D_8018D484, 1, 1.6f, 0xFF);
FrameInterpolation_RecordCloseChild();
if (player->unk_258[21].unk_012 == 5) {
func_80067D3C(player, arg2, D_8018D480, 1, 1.6f, 0xFFFFFF);
func_8006801C(player, arg2, D_8018D484, 1, 1.6f, 0xFF);
}
}
}

View File

@ -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 {

View File

@ -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);

View File

@ -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) {

View File

@ -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...

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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
@ -37,25 +36,26 @@ void AddMatrixFixed(std::vector<Mtx>& stack, s32 flags) {
// Used in func_80095BD0
Mtx* SetTextMatrix(f32 arg1, f32 arg2, f32 arg3, f32 arg4) {
Mat4 matrix;
matrix[0][0] = arg3;
matrix[0][1] = 0.0f;
matrix[0][2] = 0.0f;
matrix[0][3] = 0.0f;
matrix[1][0] = 0.0f;
matrix[1][1] = arg4;
matrix[1][2] = 0.0f;
matrix[1][3] = 0.0f;
matrix[2][0] = 0.0f;
matrix[2][1] = 0.0f;
matrix[2][2] = 1.0f;
matrix[2][3] = 0.0f;
matrix[3][0] = arg1;
matrix[3][1] = arg2;
matrix[3][2] = 0.0f;
matrix[3][3] = 1.0f;
Mat4 mf;
mf[0][0] = arg3;
mf[0][1] = 0.0f;
mf[0][2] = 0.0f;
mf[0][3] = 0.0f;
mf[1][0] = 0.0f;
mf[1][1] = arg4;
mf[1][2] = 0.0f;
mf[1][3] = 0.0f;
mf[2][0] = 0.0f;
mf[2][1] = 0.0f;
mf[2][2] = 1.0f;
mf[2][3] = 0.0f;
mf[3][0] = arg1;
mf[3][1] = arg2;
mf[3][2] = 0.0f;
mf[3][3] = 1.0f;
Mtx* mtx = GetMatrix(gWorldInstance.Mtx.Effects);
guMtxF2L(matrix, mtx);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mf, mtx);
guMtxF2L(mf, mtx);
return mtx;
}
@ -137,6 +137,14 @@ extern "C" {
AddMatrix(gWorldInstance.Mtx.Hud, mtx, flags);
}
void AddPerspMatrix(Mat4 mtx, s32 flags) {
AddMatrix(gWorldInstance.Mtx.Persp, mtx, flags);
}
void AddLookAtMatrix(Mat4 mtx, s32 flags) {
AddMatrix(gWorldInstance.Mtx.LookAt, mtx, flags);
}
void AddObjectMatrix(Mat4 mtx, s32 flags) {
AddMatrix(gWorldInstance.Mtx.Objects, mtx, flags);
}

View File

@ -5,6 +5,7 @@
#include "World.h"
#include "vehicles/Train.h"
#include "vehicles/Boat.h"
#include <port/interpolation/FrameInterpolation.h>
extern "C" {
#include "macros.h"
@ -69,7 +70,6 @@ void TrainSmokeTick() {
if (count != 0) {
boat->SmokeTimer = 100;
}
}
}
}
@ -80,28 +80,31 @@ void TrainSmokeDraw(s32 cameraId) {
for (auto& actor : gWorldInstance.Actors) {
if (auto train = dynamic_cast<ATrain*>(actor)) {
gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007AE0);
load_texture_block_i8_nomirror((uint8_t*)D_0D029458, 32, 32);
gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007AE0);
load_texture_block_i8_nomirror((uint8_t*) D_0D029458, 32, 32);
func_8004B72C(255, 255, 255, 255, 255, 255, 255);
D_80183E80[0] = 0;
D_80183E80[2] = 0x8000;
if ((train->SomeFlags != 0) &&
(is_particle_on_screen(train->Locomotive.position, camera, 0x4000U) != 0)) {
if ((train->SomeFlags != 0) && (is_particle_on_screen(train->Locomotive.position, camera, 0x4000U) != 0)) {
for (size_t i = 0; i < 128; i++) {
FrameInterpolation_RecordOpenChild("TrainSmokeParticle", train->SmokeParticles[i]);
render_object_train_smoke_particle(train->SmokeParticles[i], cameraId);
FrameInterpolation_RecordCloseChild();
}
}
} else if (auto boat = dynamic_cast<ABoat*>(actor)) {
gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007AE0);
gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007AE0);
load_texture_block_i8_nomirror((uint8_t*)D_0D029458, 32, 32);
load_texture_block_i8_nomirror((uint8_t*) D_0D029458, 32, 32);
func_8004B72C(255, 255, 255, 255, 255, 255, 255);
D_80183E80[0] = 0;
D_80183E80[2] = 0x8000;
if ((boat->SomeFlags != 0) && (is_particle_on_screen(boat->Position, camera, 0x4000U) != 0)) {
for (size_t i = 0; i < gObjectParticle2_SIZE; i++) {
FrameInterpolation_RecordOpenChild("BoatSmokeParticle", boat->SmokeParticles[i]);
render_object_paddle_boat_smoke_particle(boat->SmokeParticles[i], cameraId);
FrameInterpolation_RecordCloseChild();
}
}
}

View File

@ -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) {

View File

@ -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:

View File

@ -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) {}

View File

@ -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;

View File

@ -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)

View File

@ -14,6 +14,7 @@ namespace Editor {
class Editor {
public:
Editor();
~Editor();
ObjectPicker eObjectPicker;
std::vector<GameObject*> eGameObjects;

View File

@ -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();

View File

@ -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);
}

View File

@ -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 {

View File

@ -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();
}
}
}

View File

@ -3,6 +3,7 @@
#include "port/Game.h"
#include "assets/other_textures.h"
#include "assets/common_data.h"
#include "port/interpolation/FrameInterpolation.h"
extern "C" {
#include "update_objects.h"
@ -73,7 +74,7 @@ void OGrandPrixBalloons::Draw(s32 cameraId) {
return;
}
gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D007E98);
gSPDisplayList(gDisplayListHead++, (Gfx*) D_0D007E98);
gDPLoadTLUT_pal256(gDisplayListHead++, gTLUTOnomatopoeia);
func_8004B614(0, 0, 0, 0, 0, 0, 0);
gDPSetAlphaCompare(gDisplayListHead++, G_AC_THRESHOLD);
@ -84,14 +85,14 @@ void OGrandPrixBalloons::Draw(s32 cameraId) {
GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA));
D_80183E80[0] = 0;
D_80183E80[1] = 0x8000;
rsp_load_texture((uint8_t*)gTextureBalloon1, 64, 32);
rsp_load_texture((uint8_t*) gTextureBalloon1, 64, 32);
for (var_s1 = 0; var_s1 < _numBalloons; var_s1++) {
objectIndex = gObjectParticle3[var_s1];
if ((objectIndex != NULL_OBJECT_ID) && (gObjectList[objectIndex].state >= 2)) {
OGrandPrixBalloons::func_80053D74(objectIndex, cameraId, 0);
}
}
rsp_load_texture((uint8_t*)gTextureBalloon2, 64, 32);
rsp_load_texture((uint8_t*) gTextureBalloon2, 64, 32);
for (var_s1 = 0; var_s1 < _numBalloons; var_s1++) {
objectIndex = gObjectParticle3[var_s1];
if ((objectIndex != NULL_OBJECT_ID) && (gObjectList[objectIndex].state >= 2)) {
@ -105,15 +106,24 @@ void OGrandPrixBalloons::func_80053D74(s32 objectIndex, UNUSED s32 arg1, s32 ver
Vtx* vtx = (Vtx*) LOAD_ASSET_RAW(common_vtx_hedgehog);
size_t i = 0;
if (gMatrixHudCount <= MTX_HUD_POOL_SIZE_MAX) {
object = &gObjectList[objectIndex];
// @port: Tag the transform.
FrameInterpolation_RecordOpenChild("Balloon",
TAG_ITEM_ADDR((objectIndex << 32) + i++)); // Not working properly just yet
D_80183E80[2] = (s16) (object->unk_084[6] + 0x8000);
rsp_set_matrix_transformation(object->pos, (u16*) D_80183E80, object->sizeScaling);
set_color_render((s32) object->unk_084[0], (s32) object->unk_084[1], (s32) object->unk_084[2],
(s32) object->unk_084[3], (s32) object->unk_084[4], (s32) object->unk_084[5],
(s32) object->primAlpha);
gSPVertex(gDisplayListHead++, (uintptr_t)&vtx[vertexIndex], 4, 0);
gSPDisplayList(gDisplayListHead++, (Gfx*)common_rectangle_display);
gSPVertex(gDisplayListHead++, (uintptr_t) &vtx[vertexIndex], 4, 0);
gSPDisplayList(gDisplayListHead++, (Gfx*) common_rectangle_display);
// @port Pop the transform id.
FrameInterpolation_RecordCloseChild();
}
}
@ -128,7 +138,7 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) {
object = &gObjectList[objectIndex];
object->sizeScaling = 0.15f;
if (GetCourse() == GetMarioRaceway()) {
if (IsMarioRaceway()) {
sp2C = random_int(0x00C8U);
sp28 = random_int(_numBalloons3);
sp24 = random_int(0x0096U);
@ -136,7 +146,7 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) {
object->origin_pos[0] = (f32) ((((f64) Pos.x + 100.0) - (f64) sp2C) * (f64) xOrientation);
object->origin_pos[1] = (f32) (Pos.y + sp28);
object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24);
} else if (GetCourse() == GetRoyalRaceway()) {
} else if (IsRoyalRaceway()) {
sp2C = random_int(0x0168U);
sp28 = random_int(_numBalloons3);
sp24 = random_int(0x00B4U);
@ -144,7 +154,7 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) {
object->origin_pos[0] = (f32) ((((f64) Pos.x + 180.0) - (f64) sp2C) * (f64) xOrientation);
object->origin_pos[1] = (f32) (Pos.y + sp28);
object->origin_pos[2] = (f32) (((f64) Pos.z + 200.0) - (f64) sp24);
} else if (GetCourse() == GetLuigiRaceway()) {
} else if (IsLuigiRaceway()) {
sp2C = random_int(0x012CU);
sp28 = random_int(_numBalloons3);
sp24 = random_int(0x0096U);
@ -187,7 +197,10 @@ void OGrandPrixBalloons::func_80074924(s32 objectIndex) {
void OGrandPrixBalloons::func_80074D94(s32 objectIndex) {
if (gObjectList[objectIndex].unk_0AE == 1) {
if ((_numBalloons2 <= gObjectList[objectIndex].offset[1]) &&
//! @warning this fades out the balloons. Original game uses _numBalloons3 here but they disappear before
//! off-screen.
// So _numBalloons replaces it for now.
if ((_numBalloons <= gObjectList[objectIndex].offset[1]) &&
(s16_step_down_towards(&gObjectList[objectIndex].primAlpha, 0, 8) != 0)) {
func_80086F60(objectIndex);
}
@ -209,7 +222,8 @@ void OGrandPrixBalloons::func_80074E28(s32 objectIndex) {
case 0:
break;
case 3:
OGrandPrixBalloons::func_80041480(&gObjectList[objectIndex].unk_084[6], -0x1000, 0x1000, &gObjectList[objectIndex].unk_084[7]);
OGrandPrixBalloons::func_80041480(&gObjectList[objectIndex].unk_084[6], -0x1000, 0x1000,
&gObjectList[objectIndex].unk_084[7]);
if (gObjectList[objectIndex].unk_0AE == 0) {
func_80072428(objectIndex);
}
@ -228,4 +242,4 @@ void OGrandPrixBalloons::func_80041480(s16* arg0, s16 arg1, s16 arg2, s16* arg3)
*arg0 = arg1;
*arg3 = -*arg3;
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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",(uintptr_t) this);
objectIndex = gIndexLakituList[cameraId];
camera = &camera1[cameraId];
if (is_obj_flag_status_active(objectIndex, 0x00000010) != 0) {
@ -126,6 +129,7 @@ void OLakitu::Draw(s32 cameraId) {
}
}
}
FrameInterpolation_RecordCloseChild();
}
void OLakitu::func_80079114(s32 objectIndex, s32 playerId, s32 arg2) {
@ -293,7 +297,7 @@ void OLakitu::func_800729EC(s32 objectIndex) {
D_8018D2BC = 1;
D_8018D2A4 = 1;
if (GetCourse() != GetYoshiValley()) {
if (!IsYoshiValley()) {
for (i = 0; i < gPlayerCount; i++) {
playerHUD[i].unk_81 = temp_v1;
}
@ -362,7 +366,7 @@ void OLakitu::func_800797AC(s32 playerId) {
objectIndex = gIndexLakituList[playerId];
player = &gPlayerOne[playerId];
//if ((GetCourse() == GetSherbetLand()) && (player->unk_0CA & 1)) {
//if ((IsSherbetLand()) && (player->unk_0CA & 1)) {
if ((CM_GetProps()->LakituTowType == LakituTowType::ICE) && (player->unk_0CA & 1)) {
init_object(objectIndex, 7);
player->unk_0CA |= 0x10;

View File

@ -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);
}

View File

@ -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);

View File

@ -45,6 +45,7 @@ f32 D_800E594C[][2] = {
s16 D_800E597C[] = { 0x0000, 0x0000, 0x4000, 0x8000, 0x8000, 0xc000 };
size_t OThwomp::_count = 0;
size_t OThwomp::_rand = 0;
OThwomp::OThwomp(s16 x, s16 z, s16 direction, f32 scale, s16 behaviour, s16 primAlpha, u16 boundingBoxSize) {
Name = "Thwomp";
@ -88,6 +89,7 @@ void OThwomp::Tick60fps() { // func_80081210
if (_idx == 0) {
D_80165834[0] += 0x100;
D_80165834[1] += 0x200;
_rand += 1;
}
if (gObjectList[_objectIndex].state != 0) {
@ -131,26 +133,26 @@ void OThwomp::Tick60fps() { // func_80081210
}
OThwomp::func_8007542C(3);
if (func_80072320(_objectIndex, 0x00000020) == 0) {
return;
if (func_80072320(_objectIndex, 0x00000020)) {
func_800722CC(_objectIndex, 0x00000020);
OThwomp::AddParticles(_objectIndex);
}
func_800722CC(_objectIndex, 0x00000020);
OThwomp::AddParticles(_objectIndex);
for (var_s4 = 0; var_s4 < gObjectParticle2_SIZE; var_s4++) {
objectIndex = gObjectParticle2[var_s4];
if (objectIndex == DELETED_OBJECT_ID) {
return;
if (_idx == 0) {
for (var_s4 = 0; var_s4 < gObjectParticle2_SIZE; var_s4++) {
objectIndex = gObjectParticle2[var_s4];
if (objectIndex == DELETED_OBJECT_ID) {
continue;
}
if (gObjectList[objectIndex].state == 0) {
continue;
}
OThwomp::func_800810F4(objectIndex);
if (gObjectList[objectIndex].state != 0) {
continue;
}
delete_object_wrapper(&gObjectParticle2[var_s4]);
}
if (gObjectList[objectIndex].state == 0) {
return;
}
OThwomp::func_800810F4(objectIndex);
if (gObjectList[objectIndex].state != 0) {
return;
}
delete_object_wrapper(&gObjectParticle2[var_s4]);
}
}
@ -361,14 +363,16 @@ void OThwomp::func_8007F8D8() {
s32 OThwomp::func_8007F75C(s32 playerId) {
s32 someIndex;
s32 temp_s7;
static s32 temp_s7 = 0; // Must be static to sync far travelling thwomp instances
s32 var_s6;
s32 waypoint;
waypoint = gNearestWaypointByPlayerId[playerId];
var_s6 = 0;
if ((waypoint >= 0xAA) && (waypoint < 0xB5)) {
temp_s7 = random_int(0x0032U) + 0x32;
if (_idx == 0) {
temp_s7 = random_int(0x0032U) + 0x32;
}
if (gObjectList[_objectIndex].unk_0D5 == 3) {
var_s6 = 1;
OThwomp::func_8007F660(_objectIndex, playerId, temp_s7);
@ -928,9 +932,9 @@ void OThwomp::func_8007FA08(s32 objectIndex) {
set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f);
set_obj_direction_angle(objectIndex, 0U, 0U, 0U);
if (gIsMirrorMode != 0) {
set_obj_orientation(objectIndex, 0U, 0xC000U, 0U);
set_obj_orientation(objectIndex, 0U, _faceDirection, 0U);
} else {
set_obj_orientation(objectIndex, 0U, 0x4000U, 0U);
set_obj_orientation(objectIndex, 0U, -_faceDirection, 0U);
}
object->velocity[0] = 0.0f;
object->direction_angle[1] = object->orientation[1];
@ -970,7 +974,7 @@ void OThwomp::func_8007FB48(s32 objectIndex) {
gObjectList[objectIndex].velocity[0] = player->unk_094 * xOrientation * 1.25;
if (gObjectList[objectIndex].unk_048 >= gObjectList[objectIndex].unk_0B0) {
if (gObjectList[objectIndex].unk_0B0 == gObjectList[objectIndex].unk_048) {
if (D_8018D400 & 1) {
if (_rand & 1) { // D_8018D400 & 1
gObjectList[objectIndex].velocity[2] = 1.5f;
} else {
gObjectList[objectIndex].velocity[2] = -1.5f;
@ -1169,9 +1173,9 @@ void OThwomp::func_800802C0(s32 objectIndex) {
object->offset[1] = 10.0f;
object->unk_01C[1] = 10.0f;
if (gIsMirrorMode != 0) {
set_obj_orientation(objectIndex, 0U, 0x4000U, 0U);
set_obj_orientation(objectIndex, 0U, -_faceDirection, 0U);
} else {
set_obj_orientation(objectIndex, 0U, 0xC000U, 0U);
set_obj_orientation(objectIndex, 0U, _faceDirection, 0U);
}
object->offset[0] = 0.0f;
object->offset[2] = 0.0f;
@ -1195,7 +1199,7 @@ void OThwomp::SlidingBehaviour(s32 objectIndex) { // func_800808CC
OThwomp::func_8008085C(objectIndex);
func_80073514(objectIndex);
if (gGamestate != 9) {
if ((D_8018D40C == 0) && (gObjectList[objectIndex].state == 2)) {
if (((_rand & 0x3F) == 0) && (gObjectList[objectIndex].state == 2)) { // D_8018D40C == 0 &&
func_800C98B8(gObjectList[objectIndex].pos, gObjectList[objectIndex].velocity,
SOUND_ARG_LOAD(0x19, 0x03, 0x60, 0x45));
}

View File

@ -112,6 +112,7 @@ public:
void func_8007E63C(s32 objectIndex);
private:
static size_t _count;
static size_t _rand;
s32 _idx;
s16 _faceDirection;
//! @todo Write this better. This effects the squish size and the bounding box size.

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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"

View File

@ -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>
@ -86,6 +87,8 @@ void freecam(Camera* camera, Player* player, s8 index) {
freecam_loop(camera, player, index);
} else {
func_8001E45C(camera, player, index);
// Required if freecam were to use its own camera instead of borrowing the player camera
//func_8001EE98(gPlayerOneCopy, camera, index);
}
}
@ -104,7 +107,6 @@ void freecam_loop(Camera* camera, Player* player, s8 index) {
// Toggle freecam
CVarSetInteger("gFreecam", !CVarGetInteger("gFreecam", 0));
}
// Calculate forward direction
freecam_calculate_forward_vector_allow_rotation(camera, freeCam.forwardVector);
@ -389,24 +391,33 @@ void freecam_update_controller(void) {
// Note that D Pad as stick code has been removed. So if it's needed, it needs to be put back in.
}
void freecam_render_setup(void) {
Mtx fPersp;
Mtx fLookAt;
void freecam_render_setup(Camera* camera) {
u16 perspNorm;
Mat4 matrix;
init_rdp();
func_802A53A4();
init_rdp();
func_80057FC4(0);
Mat4 persp;
Mat4 lookAt;
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH);
gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK | G_CULL_BOTH | G_CULL_FRONT);
guPerspective(&gGfxPool->mtxPersp[0], &perspNorm, gCameraZoom[0], gScreenAspect,
// Perspective (camera movement)
FrameInterpolation_RecordOpenChild("freecam_persp", FrameInterpolation_GetCameraEpoch());
guPerspective(&fPersp, &perspNorm, gCameraZoom[0], gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, (&gGfxPool->mtxPersp[0]), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
guLookAt(&gGfxPool->mtxLookAt[0], camera1->pos[0], camera1->pos[1], camera1->pos[2], camera1->lookAt[0],
camera1->lookAt[1], camera1->lookAt[2], camera1->up[0], camera1->up[1], camera1->up[2]);
gSPMatrix(gDisplayListHead++, (&gGfxPool->mtxLookAt[0]), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
mtxf_identity(matrix);
gSPSetGeometryMode(gDisplayListHead++, G_CULL_BACK);
render_set_position(matrix, 0);
init_rdp();
gSPMatrix(gDisplayListHead++, (&fPersp), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
// LookAt (camera rotation)
FrameInterpolation_RecordOpenChild("freecam_lookAt", FrameInterpolation_GetCameraEpoch());
guLookAt(&fLookAt, camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0],
camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]);
gSPMatrix(gDisplayListHead++, (&fLookAt), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
gDPPipeSync(gDisplayListHead++);
}

View File

@ -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);

View File

@ -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;

View File

@ -3,6 +3,7 @@
#include "main.h"
#include <mk64.h>
#include <assets/common_data.h>
#include "src/port/interpolation/matrix.h"
#include "math_util.h"

View File

@ -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"
@ -636,6 +637,12 @@ void game_init_clear_framebuffer(void) {
clear_framebuffer(0);
}
//! @deprecated
// This function was made to tick the game logic at native 60 fps.
// However, many game objects are not in that special tick loop and run at native 30fps.
// Thus adding `if (gTickVisuals) { // stuff here }` would prevent double speed and allow ticking visuals once every 30 fps.
// This does not however, create extra interpolated frames. Whereas a possible solution, it is not the best solution.
// This function should be cleaned up and removed, since frame interpolation now exists.
void calculate_updaterate(void) {
static u32 prevtime = 0;
static u32 remainder = 0;
@ -647,7 +654,7 @@ void calculate_updaterate(void) {
s32 total;
// Get target FPS from configuration variable
s32 targetFPS = CVarGetInteger("gInterpolationFPS", 30);
s32 targetFPS = 30;
if (targetFPS < 60) {
targetFPS = 30;
@ -686,7 +693,7 @@ void calculate_updaterate(void) {
if (targetFPS < 60) {
gTickLogic = 2;
} else {
gTickLogic = 1; // Perform logic update
gTickLogic = 2; // Perform logic update
}
}
@ -694,8 +701,9 @@ void calculate_updaterate(void) {
visualsAccumulator += total; // Increment for each frame
if (visualsAccumulator >= visualsUpdateInterval) { // Check if it's time to update visuals
visualsAccumulator -= visualsUpdateInterval;
gTickVisuals = 1; // Perform visual update
// gTickVisuals <-- Goes here to use the native 60fps system
}
gTickVisuals = 1; // Perform visual update
}
void display_debug_info(void) {
@ -758,9 +766,20 @@ void process_game_tick(void) {
func_800382DC();
}
// Editor requires this for camera movement.
func_8001EE98(gPlayerOneCopy, camera1, 0);
// tick camera
// This looks like it should be in the switch.
// But it needs to be here for player 1 to work in all modes.
func_8001EE98(gPlayerOneCopy, camera1, 0);
// Required if freecam was to have a new camera
//if (CVarGetInteger("gFreecam", 0) == true) {
// freecam(gFreecamCamera, gPlayerOneCopy, 0);
//} else {
//func_8001EE98(gPlayerOneCopy, camera1, 0);
//}
// Editor requires this so the camera keeps moving while the game is paused.
if (gIsEditorPaused == true) {
return;
}
@ -930,6 +949,8 @@ void race_logic_loop(void) {
*/
void game_state_handler(void) {
FrameInterpolation_StartRecord();
#if DVDL
if ((gControllerOne->button & L_TRIG) && (gControllerOne->button & R_TRIG) && (gControllerOne->button & Z_TRIG) &&
(gControllerOne->button & A_BUTTON)) {
@ -966,6 +987,7 @@ void game_state_handler(void) {
credits_loop();
break;
}
FrameInterpolation_StopRecord();
}
void interrupt_gfx_sptask(void) {

View File

@ -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]);
void mtxf_set_matrix_transformation(Mat4 transformMatrix, Vec3f location, Vec3su rotation, f32 scale) {
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];
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++]),

View File

@ -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

View File

@ -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);
}
}

View File

@ -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()) {

View File

@ -11,6 +11,7 @@
**************************************************************************/
#include "libultra_internal.h"
#include "port/interpolation/FrameInterpolation.h"
void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp,
float yUp, float zUp) {
@ -75,5 +76,6 @@ void guLookAt(Mtx* m, float xEye, float yEye, float zEye, float xAt, float yAt,
guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mf, m);
guMtxF2L(mf, m);
}

View File

@ -1,4 +1,5 @@
#include "libultra_internal.h"
#include "port/interpolation/FrameInterpolation.h"
void guOrthoF(float m[4][4], float left, float right, float bottom, float top, float near, float far, float scale) {
int row;
@ -19,7 +20,8 @@ void guOrthoF(float m[4][4], float left, float right, float bottom, float top, f
}
void guOrtho(Mtx* m, float left, float right, float bottom, float top, float near, float far, float scale) {
float sp28[4][4];
guOrthoF(sp28, left, right, bottom, top, near, far, scale);
guMtxF2L(sp28, m);
float mf[4][4];
guOrthoF(mf, left, right, bottom, top, near, far, scale);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m);
guMtxF2L(mf, m);
}

View File

@ -1,4 +1,5 @@
#include "libultra_internal.h"
#include "port/interpolation/FrameInterpolation.h"
void guPerspectiveF(float mf[4][4], u16* perspNorm, float fovy, float aspect, float near, float far, float scale) {
float yscale;
@ -36,5 +37,6 @@ void guPerspectiveF(float mf[4][4], u16* perspNorm, float fovy, float aspect, fl
void guPerspective(Mtx* m, u16* perspNorm, float fovy, float aspect, float near, float far, float scale) {
float mat[4][4];
guPerspectiveF(mat, perspNorm, fovy, aspect, near, far, scale);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*)mat, m);
guMtxF2L(mat, m);
}

View File

@ -1,4 +1,5 @@
#include "libultra_internal.h"
#include "port/interpolation/FrameInterpolation.h"
void guRotateF(float m[4][4], float a, float x, float y, float z) {
float sin_a;
@ -38,5 +39,6 @@ void guRotateF(float m[4][4], float a, float x, float y, float z) {
void guRotate(Mtx* m, float a, float x, float y, float z) {
float mf[4][4];
guRotateF(mf, a, x, y, z);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m);
guMtxF2L(mf, m);
}

View File

@ -1,4 +1,5 @@
#include "libultra_internal.h"
#include "port/interpolation/FrameInterpolation.h"
void guScaleF(float mf[4][4], float x, float y, float z) {
guMtxIdentF(mf);
@ -11,5 +12,6 @@ void guScaleF(float mf[4][4], float x, float y, float z) {
void guScale(Mtx* m, float x, float y, float z) {
float mf[4][4];
guScaleF(mf, x, y, z);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m);
guMtxF2L(mf, m);
}

View File

@ -1,4 +1,5 @@
#include "libultra_internal.h"
#include "port/interpolation/FrameInterpolation.h"
void guTranslateF(float m[4][4], float x, float y, float z) {
guMtxIdentF(m);
@ -10,5 +11,6 @@ void guTranslateF(float m[4][4], float x, float y, float z) {
void guTranslate(Mtx* m, float x, float y, float z) {
float mf[4][4];
guTranslateF(mf, x, y, z);
FrameInterpolation_RecordMatrixMtxFToMtx((MtxF*) mf, m);
guMtxF2L(mf, m);
}

View File

@ -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);

View File

@ -24,9 +24,10 @@
#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>
// #include <Fast3D/gfx_rendering_api.h>
#include <SDL2/SDL.h>
#include <utility>
@ -51,9 +52,9 @@ float gInterpolationStep = 0.0f;
Fast::Interpreter* GetInterpreter() {
return static_pointer_cast<Fast::Fast3dWindow>(Ship::Context::GetInstance()->GetWindow())
->GetInterpreterWeak()
.lock()
.get();
->GetInterpreterWeak()
.lock()
.get();
}
GameEngine* GameEngine::Instance;
@ -62,7 +63,7 @@ GameEngine::GameEngine() {
const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory("mk64.o2r");
const std::string assets_path = Ship::Context::LocateFileAcrossAppDirs("spaghetti.o2r");
std::vector<std::string> archiveFiles;
#ifdef __SWITCH__
@ -70,7 +71,6 @@ GameEngine::GameEngine() {
Ship::Switch::Init(Ship::PostInitPhase);
#endif
#ifdef _WIN32
AllocConsole();
#endif
@ -79,7 +79,7 @@ GameEngine::GameEngine() {
archiveFiles.push_back(main_path);
} else {
if (ShowYesNoBox("No O2R Files", "No O2R files found. Generate one now?") == IDYES) {
if(!GenAssetFile()){
if (!GenAssetFile()) {
ShowMessage("Error", "An error occured, no O2R file was generated.\n\nExiting...");
exit(1);
} else {
@ -106,11 +106,11 @@ GameEngine::GameEngine() {
}
}
this->context =
Ship::Context::CreateUninitializedInstance("Spaghetti Kart", "spaghettify", "spaghettify.cfg.json");
this->context = Ship::Context::CreateUninitializedInstance("Spaghetti Kart", "spaghettify", "spaghettify.cfg.json");
this->context->InitConfiguration(); // without this line InitConsoleVariables fails at Config::Reload()
this->context->InitConsoleVariables(); // without this line the controldeck constructor failes in ShipDeviceIndexMappingManager::UpdateControllerNamesFromConfig()
this->context->InitConfiguration(); // without this line InitConsoleVariables fails at Config::Reload()
this->context->InitConsoleVariables(); // without this line the controldeck constructor failes in
// ShipDeviceIndexMappingManager::UpdateControllerNamesFromConfig()
auto controlDeck = std::make_shared<LUS::ControlDeck>();
@ -120,8 +120,8 @@ GameEngine::GameEngine() {
auto gui = std::make_shared<Ship::SpaghettiGui>(std::vector<std::shared_ptr<Ship::GuiWindow>>({}));
auto wnd = std::make_shared<Fast::Fast3dWindow>(gui);
//auto wnd = std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({}));
//auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(Ship::Context::GetInstance()->GetWindow());
// auto wnd = std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({}));
// auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(Ship::Context::GetInstance()->GetWindow());
this->context->Init(archiveFiles, {}, 3, { 26800, 512, 1100 }, wnd, controlDeck);
@ -158,8 +158,9 @@ GameEngine::GameEngine() {
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryXMLVertexV0>(), RESOURCE_FORMAT_XML, "Vertex",
static_cast<uint32_t>(Fast::ResourceType::Vertex), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryDisplayListV0>(), RESOURCE_FORMAT_BINARY,
"DisplayList", static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryDisplayListV0>(),
RESOURCE_FORMAT_BINARY, "DisplayList",
static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryXMLDisplayListV0>(), RESOURCE_FORMAT_XML,
"DisplayList", static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
@ -178,24 +179,21 @@ GameEngine::GameEngine() {
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryBinaryTrackSectionsV0>(),
RESOURCE_FORMAT_BINARY, "TrackSections",
static_cast<uint32_t>(MK64::ResourceType::TrackSection), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryXMLTrackSectionsV0>(),
RESOURCE_FORMAT_XML, "TrackSections",
static_cast<uint32_t>(MK64::ResourceType::TrackSection), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryXMLTrackSectionsV0>(), RESOURCE_FORMAT_XML,
"TrackSections", static_cast<uint32_t>(MK64::ResourceType::TrackSection), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryBinaryTrackWaypointsV0>(),
RESOURCE_FORMAT_BINARY, "Waypoints",
static_cast<uint32_t>(MK64::ResourceType::Waypoints), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryXMLTrackWaypointsV0>(),
RESOURCE_FORMAT_XML, "Paths",
static_cast<uint32_t>(MK64::ResourceType::Waypoints), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryXMLTrackWaypointsV0>(), RESOURCE_FORMAT_XML,
"Paths", static_cast<uint32_t>(MK64::ResourceType::Waypoints), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryBinaryActorSpawnDataV0>(),
RESOURCE_FORMAT_BINARY, "SpawnData",
static_cast<uint32_t>(MK64::ResourceType::SpawnData), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryBinaryUnkActorSpawnDataV0>(),
RESOURCE_FORMAT_BINARY, "UnkSpawnData",
static_cast<uint32_t>(MK64::ResourceType::UnkSpawnData), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryBinaryMinimapV0>(),
RESOURCE_FORMAT_BINARY, "Minimap",
static_cast<uint32_t>(MK64::ResourceType::Minimap), 0);
loader->RegisterResourceFactory(std::make_shared<MK64::ResourceFactoryBinaryMinimapV0>(), RESOURCE_FORMAT_BINARY,
"Minimap", static_cast<uint32_t>(MK64::ResourceType::Minimap), 0);
fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf");
fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf");
@ -216,15 +214,38 @@ bool GameEngine::GenAssetFile() {
auto game = extractor->ValidateChecksum();
if (!game.has_value()) {
ShowMessage("Unsupported ROM", "The provided ROM is not supported.\n\nCheck the readme for a list of supported versions.");
ShowMessage("Unsupported ROM",
"The provided ROM is not supported.\n\nCheck the readme for a list of supported versions.");
exit(1);
}
ShowMessage(("Found " + game.value()).c_str(), "The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION);
ShowMessage(("Found " + game.value()).c_str(),
"The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION);
return extractor->GenerateOTR();
}
uint32_t GameEngine::GetInterpolationFPS() {
if (CVarGetInteger("gMatchRefreshRate", 0)) {
return Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
} else if (CVarGetInteger("gVsyncEnabled", 1) ||
!Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) {
return std::min<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 +296,9 @@ void GameEngine::Destroy() {
#ifdef __SWITCH__
Ship::Switch::Exit();
#endif
GameUI::Destroy();
delete GameEngine::Instance;
GameEngine::Instance = nullptr;
}
bool ShouldClearTextureCacheAtEndOfFrame = false;
@ -301,16 +325,24 @@ void GameEngine::StartFrame() const {
// Instance->context->GetWindow()->MainLoop(run_one_game_iter);
// }
void GameEngine::RunCommands(Gfx* Commands) {
void GameEngine::RunCommands(Gfx* Commands, const std::vector<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 +353,49 @@ 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();
if (CVarGetInteger("gModifyInterpolationTargetFPS", 0)) {
target_fps = CVarGetInteger("gInterpolationTargetFPS", 60);
}
static int last_fps;
static int last_update_rate;
static int time;
int fps = target_fps;
int original_fps = 60 / 2 /*gVIsPerFrame*/;
if (target_fps == 30 || original_fps > target_fps) {
fps = original_fps;
}
if (last_fps != fps || last_update_rate != 2 /*gVIsPerFrame*/) {
time = 0;
}
// time_base = fps * original_fps (one second)
int next_original_frame = fps;
while (time + original_fps <= next_original_frame) {
time += original_fps;
if (time != next_original_frame) {
mtx_replacements.push_back(FrameInterpolation_Interpolate((float) time / next_original_frame));
} else {
mtx_replacements.emplace_back();
}
}
// printf("mtxf size: %d\n", mtx_replacements.size());
time -= fps;
auto wnd = std::dynamic_pointer_cast<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 +513,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;
@ -635,14 +706,14 @@ extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) {
/**
* Centers an item in a given area.
*
*
* Adds the number of extended screen pixels to the location to center.
* This allows stretching the game window really wide, and the item will stay in-place.
*
*
* This is not for centering in the direct center of the screen.
*
*
* How to use:
*
*
* s32 center = OTRCalculateCenterOfAreaFromRightEdge((SCREEN_WIDTH / 4) + (SCREEN_WIDTH / 2));
* x = center - (texWidth / 2)
* x2 = center + (texWidth / 2)

View File

@ -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);

View File

@ -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);
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>());
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 });
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;
}
// 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* 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;
}
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;

View File

@ -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);
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* 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);
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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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;
}
}
}

View File

@ -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();

View File

@ -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());
}

View File

@ -15,10 +15,10 @@
#endif
extern "C" {
extern s32 gGamestateNext;
extern s32 gMenuSelection;
#include "audio/external.h"
#include "defines.h"
extern s32 gGamestateNext;
extern s32 gMenuSelection;
#include "audio/external.h"
#include "defines.h"
}
namespace GameUI {
@ -158,9 +158,8 @@ void PortMenu::AddSettings() {
.IsPercentage());
AddWidget(path, "Main Music Volume: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT)
.CVar("gMainMusicVolume")
.Callback([](WidgetInfo& info) {
audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f));
})
.Callback(
[](WidgetInfo& info) { audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f)); })
.Options(FloatSliderOptions()
.Tooltip("Adjust the background music volume.")
.ShowButtons(false)
@ -168,16 +167,17 @@ void PortMenu::AddSettings() {
.IsPercentage());
AddWidget(path, "Sound Effects Volume: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT)
.CVar("gSFXMusicVolume")
.Callback([](WidgetInfo& info) {
audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f));
})
.Options(
FloatSliderOptions().Tooltip("Adjust the sound effects volume.").ShowButtons(false).Format("").IsPercentage());
.Callback(
[](WidgetInfo& info) { audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); })
.Options(FloatSliderOptions()
.Tooltip("Adjust the sound effects volume.")
.ShowButtons(false)
.Format("")
.IsPercentage());
AddWidget(path, "Sound Effects Volume: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT)
.CVar("gEnvironmentVolume")
.Callback([](WidgetInfo& info) {
audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f));
})
.Callback(
[](WidgetInfo& info) { audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f)); })
.Options(FloatSliderOptions()
.Tooltip("Adjust the environment volume.")
.ShowButtons(false)
@ -244,25 +244,25 @@ void PortMenu::AddSettings() {
.DefaultValue(1));
#endif
// AddWidget(path, "Current FPS: %d", WIDGET_CVAR_SLIDER_INT)
// .CVar("gInterpolationFPS")
// .Callback([](WidgetInfo& info) {
// int32_t defaultValue = std::static_pointer_cast<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();
}
@ -332,31 +332,36 @@ void PortMenu::AddEnhancements() {
AddMenuEntry("Enhancements", "gSettings.Menu.EnhancementsSidebarSection");
WidgetPath path = { "Enhancements", "General", SECTION_COLUMN_1 };
AddSidebarEntry("Enhancements", "General", 3);
//UIWidgets::WindowButton("Multiplayer", "gMultiplayerWindowEnabled", GameUI::mMultiplayerWindow,
// { .tooltip = "Shows the multiplayer window" });
// UIWidgets::WindowButton("Freecam", "gFreecam", GameUI::mFreecamWindow,
// { .tooltip = "Allows you to fly around the course" });
// UIWidgets::WindowButton("Multiplayer", "gMultiplayerWindowEnabled", GameUI::mMultiplayerWindow,
// { .tooltip = "Shows the multiplayer window" });
// UIWidgets::WindowButton("Freecam", "gFreecam", GameUI::mFreecamWindow,
// { .tooltip = "Allows you to fly around the course" });
AddWidget(path, "No multiplayer feature cuts", WIDGET_CVAR_CHECKBOX)
.CVar("gMultiplayerNoFeatureCuts")
.Options(CheckboxOptions().Tooltip("Allows full train and jumbotron in multiplayer, etc."));
AddWidget(path, "General Improvements", WIDGET_CVAR_CHECKBOX)
.CVar("gImprovements").Options(CheckboxOptions().Tooltip("General improvements to the game experience."));
.CVar("gImprovements")
.Options(CheckboxOptions().Tooltip("General improvements to the game experience."));
AddWidget(path, "No Level of Detail (LOD)", WIDGET_CVAR_CHECKBOX)
.CVar("gDisableLod")
.Options(CheckboxOptions().Tooltip("Disable Level of Detail (LOD) to avoid models using lower poly versions at a distance"));
.Options(CheckboxOptions().Tooltip(
"Disable Level of Detail (LOD) to avoid models using lower poly versions at a distance"));
AddWidget(path, "Disable Culling", WIDGET_CVAR_CHECKBOX)
.CVar("gNoCulling").Options(CheckboxOptions().Tooltip("Disable original culling of mk64"));
.CVar("gNoCulling")
.Options(CheckboxOptions().Tooltip("Disable original culling of mk64"));
AddWidget(path, "Far Frustrum", WIDGET_CVAR_SLIDER_FLOAT)
.CVar("gFarFrustrum")
.Options(FloatSliderOptions().Min(0.0f).Max(10000.0f).DefaultValue(10000.0f)
.Tooltip("Say how Far the Frustrum are when 'Disable Culling' are enable").Step(10.0f));
.Options(FloatSliderOptions()
.Min(0.0f)
.Max(10000.0f)
.DefaultValue(10000.0f)
.Tooltip("Say how Far the Frustrum are when 'Disable Culling' are enable")
.Step(10.0f));
path = { "Enhancements", "Cheats", SECTION_COLUMN_1 };
AddSidebarEntry("Enhancements", "Cheats", 3);
AddWidget(path, "Moon Jump", WIDGET_CVAR_CHECKBOX)
.CVar("gEnableMoonJump");
AddWidget(path, "Enable Custom CC", WIDGET_CVAR_CHECKBOX)
.CVar("gEnableCustomCC");
AddWidget(path, "Moon Jump", WIDGET_CVAR_CHECKBOX).CVar("gEnableMoonJump");
AddWidget(path, "Enable Custom CC", WIDGET_CVAR_CHECKBOX).CVar("gEnableCustomCC");
AddWidget(path, "Custom CC", WIDGET_CVAR_SLIDER_FLOAT)
.CVar("gCustomCC")
.Options(FloatSliderOptions().Min(0.0f).Max(1000.0f).DefaultValue(150.0f).Step(10.0f));
@ -365,21 +370,23 @@ void PortMenu::AddEnhancements() {
.Options(CheckboxOptions().Tooltip("Disable wall collision."));
AddWidget(path, "Min Height", WIDGET_CVAR_SLIDER_FLOAT)
.CVar("gMinHeight")
.Options(FloatSliderOptions().Min(-50.0f).Max(50.0f).DefaultValue(0.0f)
.Tooltip("When Disable Wall Collision are enable what is the minimal height you can get."));
.Options(FloatSliderOptions().Min(-50.0f).Max(50.0f).DefaultValue(0.0f).Tooltip(
"When Disable Wall Collision are enable what is the minimal height you can get."));
#if not defined(__SWITCH__) and not defined(__WIIU__)
path = { "Enhancements", "HM64 Lab", SECTION_COLUMN_1 };
AddSidebarEntry("Enhancements", "HM64 Lab", 4);
AddWidget(path, "Enable HM64 Labs", WIDGET_CVAR_CHECKBOX)
.CVar("gEditorEnabled")
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Tools")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Scene Explorer")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Content Browser")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Track Properties")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Properties")->ToggleVisibility();
})
.Options(UIWidgets::CheckboxOptions({{ .tooltip = "Edit the universe!"}}));
.CVar("gEditorEnabled")
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Tools")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Scene Explorer")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Content Browser")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Track Properties")->ToggleVisibility();
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Properties")->ToggleVisibility();
})
.Options(UIWidgets::CheckboxOptions({ { .tooltip = "Edit the universe!" } }));
#endif
}
#ifdef __SWITCH__
@ -400,11 +407,11 @@ void PortMenu::AddDevTools() {
WidgetPath path = { "Developer", "General", SECTION_COLUMN_1 };
#ifdef __SWITCH__
AddWidget(path, "Switch CPU Profile", WIDGET_CVAR_COMBOBOX)
.CVar("gSwitchPerfMode")
.Options(ComboboxOptions()
.Tooltip("Switches the CPU profile to a different one")
.ComboMap(switchCPUProfiles)
.DefaultIndex(Ship::SwitchProfiles::STOCK))
.CVar("gSwitchPerfMode")
.Options(ComboboxOptions()
.Tooltip("Switches the CPU profile to a different one")
.ComboMap(switchCPUProfiles)
.DefaultIndex(Ship::SwitchProfiles::STOCK))
.Callback([](WidgetInfo& info) { Ship::Switch::ApplyOverclock(); });
#endif
AddWidget(path, "Popout Menu", WIDGET_CVAR_CHECKBOX)
@ -413,6 +420,17 @@ void PortMenu::AddDevTools() {
AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX)
.CVar("gEnableDebugMode")
.Options(CheckboxOptions().Tooltip("Enables Debug Mode."));
AddWidget(path, "Modify Interpolation Target FPS", WIDGET_CVAR_CHECKBOX)
.CVar("gModifyInterpolationTargetFPS")
.Options(CheckboxOptions().Tooltip("Enables Debug Mode."));
AddWidget(path, "Interpolation Target FPS", WIDGET_CVAR_SLIDER_INT)
.CVar("gInterpolationTargetFPS")
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger("gModifyInterpolationTargetFPS", 0); })
.Options(IntSliderOptions()
.Tooltip("Sets the target FPS for interpolation. When Modify Interpolation Target FPS are enable")
.Min(15)
.Max(360)
.DefaultValue(60));
AddWidget(path, "Render Collision", WIDGET_CVAR_CHECKBOX)
.CVar("gRenderCollisionMesh")
.Options(CheckboxOptions().Tooltip("Renders the collision mesh instead of the course mesh"));
@ -429,7 +447,8 @@ void PortMenu::AddDevTools() {
AddSidebarEntry("Developer", "Stats", 1);
AddWidget(path, "Popout Stats", WIDGET_WINDOW_BUTTON)
.CVar("gStatsEnabled")
.Options(ButtonOptions().Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on"))
.Options(ButtonOptions().Tooltip(
"Shows the stats window, with your FPS and frametimes, and the OS you're playing on"))
.WindowName("Stats");
path = { "Developer", "Console", SECTION_COLUMN_1 };
@ -445,9 +464,9 @@ PortMenu::PortMenu(const std::string& consoleVariable, const std::string& name)
: Menu(consoleVariable, name, 0, UIWidgets::Colors::LightBlue) {
}
//bool CheckNetworkConnected(disabledInfo& info) {
// return gNetwork.isConnected;
//}
// bool CheckNetworkConnected(disabledInfo& info) {
// return gNetwork.isConnected;
// }
void PortMenu::InitElement() {
Ship::Menu::InitElement();
@ -531,4 +550,4 @@ void PortMenu::Draw() {
void PortMenu::DrawElement() {
Ship::Menu::DrawElement();
}
} // namespace BenGui
} // namespace GameUI

View File

@ -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:

View File

@ -3,6 +3,7 @@
#include "mk64.h"
#include <assets/common_data.h>
#include "port/Engine.h"
#include "port/interpolation/matrix.h"
#include "math_util.h"
#include <stdio.h>

View File

@ -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,14 +1144,23 @@ f32 is_within_render_distance(Vec3f cameraPos, Vec3f objectPos, u16 orientationY
if (minDistance == 0.0f) {
if (is_visible_between_angle((orientationY + extended_fov), (orientationY - extended_fov), angleObject) == 1) {
return distance;
if (IsKalimariDesert()) {
return distance / 6.5f; // set for better DD settings in Desert
} else {
return distance / 10.0f; // Items
}
}
return -1.0f;
}
if (is_visible_between_angle((u16) plus_fov_angle, (u16) minus_fov_angle, angleObject) == 1) {
return distance;
if (IsKalimariDesert()) {
return distance / 2.0f;
} else {
return distance / 10.0f; // DD Vhicles
}
}
temp_v0 = func_802B7CA8(minDistance / distance);
temp = angleObject + temp_v0;

View File

@ -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

View File

@ -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))) {

View File

@ -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,14 @@ void func_8029122C(struct UnkStruct_800DC5EC* arg0, s32 playerId) {
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
break;
}
FrameInterpolation_RecordOpenChild("track_water", playerId);
mtxf_identity(matrix);
render_set_position(matrix, 0);
CM_DrawWater(arg0, pathCounter, cameraRot, playerDirection);
FrameInterpolation_RecordCloseChild();
// switch (gCurrentCourseId) {
// case COURSE_BOWSER_CASTLE:
// if (gActiveScreenMode != SCREEN_MODE_1P) {

View File

@ -21,6 +21,8 @@
#include "engine/courses/Course.h"
#include "port/Game.h"
#include "math_util.h"
#include "src/enhancements/freecam/freecam.h"
#include "port/interpolation/FrameInterpolation.h"
Vp D_802B8880[] = {
{ { { 640, 480, 511, 0 }, { 640, 480, 511, 0 } } },
@ -397,11 +399,15 @@ void func_802A450C(Vtx* skybox) {
skybox[7].v.cn[2] = prop->FloorTopLeft.b;
}
Mtx gIdentityMatrix2 = {
toFixedPointMatrix(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
};
void func_802A487C(Vtx* arg0, UNUSED struct UnkStruct_800DC5EC* arg1, UNUSED s32 arg2, UNUSED s32 arg3,
UNUSED f32* arg4) {
init_rdp();
if (GetCourse() != GetRainbowRoad()) {
if (!IsRainbowRoad()) {
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER | G_LIGHTING);
@ -409,7 +415,7 @@ void func_802A487C(Vtx* arg0, UNUSED struct UnkStruct_800DC5EC* arg1, UNUSED s32
gSPPerspNormalize(gDisplayListHead++, 0xFFFF);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxScreen),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPMatrix(gDisplayListHead++, &gIdentityMatrix2, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPVertex(gDisplayListHead++, &arg0[4], 4, 0);
gSP2Triangles(gDisplayListHead++, 0, 3, 1, 0, 1, 3, 2, 0);
}
@ -476,10 +482,10 @@ void func_802A4A0C(Vtx* vtx, struct UnkStruct_800DC5EC* arg1, UNUSED s32 arg2, U
gSPPerspNormalize(gDisplayListHead++, 0xFFFF);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxScreen),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, &gIdentityMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPMatrix(gDisplayListHead++, &gIdentityMatrix2, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPVertex(gDisplayListHead++, &vtx[0], 4, 0);
gSP2Triangles(gDisplayListHead++, 0, 3, 1, 0, 1, 3, 2, 0);
if (GetCourse() == GetRainbowRoad()) {
if (IsRainbowRoad()) {
gSPVertex(gDisplayListHead++, &vtx[4], 4, 0);
gSP2Triangles(gDisplayListHead++, 0, 3, 1, 0, 1, 3, 2, 0);
}
@ -750,11 +756,35 @@ void func_802A5760(void) {
}
}
void render_screens(s32 mode, s32 cameraId, s32 playerId) {
UNUSED s32 pad[4];
// Setup the cameras perspective and lookAt (movement/rotation)
void setup_camera(Camera* camera, s32 playerId, s32 cameraId, struct UnkStruct_800DC5EC* screen) {
Mat4 matrix;
u16 perspNorm;
UNUSED s32 pad2[2];
UNUSED s32 pad3;
// This allows freecam to create a new separate camera
// if (CVarGetInteger("gFreecam", 0) == true) {
// freecam_render_setup(gFreecamCamera);
// return;
// }
// Setup perspective (camera movement)
FrameInterpolation_RecordOpenChild("camera",
(FrameInterpolation_GetCameraEpoch() | (((playerId | cameraId) << 8))));
guPerspective(&gGfxPool->mtxPersp[cameraId], &perspNorm, gCameraZoom[cameraId], gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[cameraId]),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
// Setup lookAt (camera rotation)
guLookAt(&gGfxPool->mtxLookAt[cameraId], camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0],
camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
}
void render_screens(s32 mode, s32 cameraId, s32 playerId) {
Mat4 matrix;
s32 screenId = 0;
@ -817,8 +847,16 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
}
struct UnkStruct_800DC5EC* screen = &D_8015F480[screenId];
Camera* camera = &cameras[cameraId];
Camera* camera;
// Required for freecam to have its own camera
//if (CVarGetInteger("gFreecam", 0) == true) {
// camera = &gFreecamCamera;
// cameraId = 4;
//} else {
camera = &cameras[cameraId];
//}
if (screenMode == SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL) {
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH);
}
@ -828,34 +866,21 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH);
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
guPerspective(&gGfxPool->mtxPersp[cameraId], &perspNorm, gCameraZoom[cameraId], gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
// Setup camera perspective and lookAt
setup_camera(camera, playerId, cameraId, screen);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxPersp[cameraId]),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
// Create a matrix for the track and game objects
FrameInterpolation_RecordOpenChild("track", (playerId | cameraId) << 8);
Mat4 trackMatrix;
mtxf_identity(trackMatrix);
render_set_position(trackMatrix, 0);
guLookAt(&gGfxPool->mtxLookAt[cameraId], camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0],
camera->lookAt[1], camera->lookAt[2], camera->up[0], camera->up[1], camera->up[2]);
if (D_800DC5C8 == 0) {
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
mtxf_identity(matrix);
render_set_position(matrix, 0);
} else {
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
}
// Draw course and game objects
render_course(screen);
if (D_800DC5C8 == 1) {
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxLookAt[cameraId]),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
mtxf_identity(matrix);
render_set_position(matrix, 0);
}
render_course_actors(screen);
CM_DrawStaticMeshActors();
render_object(mode);
switch (screenId) {
case 0:
render_players_on_screen_one();
@ -902,6 +927,7 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
if (mode != RENDER_SCREEN_MODE_1P_PLAYER_ONE) {
gNumScreens += 1;
}
FrameInterpolation_RecordCloseChild();
}
void func_802A74BC(void) {

View File

@ -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);
}

View File

@ -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,
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, 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,
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) {

View File

@ -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

View File

@ -729,7 +729,7 @@ void spawn_players_versus_two_player(f32* arg0, f32* arg1, f32 arg2) {
}
void spawn_players_2p_battle(f32* arg0, f32* arg1, f32 arg2) {
if (GetCourse() == GetBigDonut()) {
if (IsBigDonut()) {
spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, -16384.0f, gCharacterSelections[0],
PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN);
spawn_player(gPlayerTwo, 1, arg0[1], arg1[1], arg2, 16384.0f, gCharacterSelections[1],
@ -778,7 +778,7 @@ void func_8003B318(f32* arg0, f32* arg1, f32 arg2) {
}
void spawn_players_3p_battle(f32* arg0, f32* arg1, f32 arg2) {
if (GetCourse() == GetBigDonut()) {
if (IsBigDonut()) {
spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, -16384.0f, gCharacterSelections[0],
PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN);
spawn_player(gPlayerTwo, 1, arg0[1], arg1[1], arg2, 16384.0f, gCharacterSelections[1],
@ -830,7 +830,7 @@ void func_8003B870(f32* arg0, f32* arg1, f32 arg2) {
}
void spawn_players_4p_battle(f32* arg0, f32* arg1, f32 arg2) {
if (GetCourse() == GetBigDonut()) {
if (IsBigDonut()) {
spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, -16384.0f, gCharacterSelections[0],
PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN);
spawn_player(gPlayerTwo, 1, arg0[1], arg1[1], arg2, 16384.0f, gCharacterSelections[1],
@ -888,17 +888,17 @@ void func_8003C0F0(void) {
if (gModeSelection == BATTLE) {
func_8000EEDC();
} else if (GetCourse() != GetPodiumCeremony()) {
} else if (!IsPodiumCeremony()) {
func_8000F2DC();
sp5E = (f32) D_80164550[0][0].posX;
sp5C = (f32) D_80164550[0][0].posZ;
sp5A = (f32) D_80164550[0][0].posY;
if (GetCourse() == GetToadsTurnpike()) {
if (IsToadsTurnpike()) {
sp5E = 0;
}
}
if ((gModeSelection != BATTLE) && (GetCourse() != GetPodiumCeremony())) {
if ((gModeSelection != BATTLE) && (!IsPodiumCeremony())) {
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
switch (gModeSelection) {
@ -993,7 +993,7 @@ void func_8003C0F0(void) {
}
break;
}
} else if (GetCourse() == GetBlockFort()) {
} else if (IsBlockFort()) {
switch (gActiveScreenMode) {
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
@ -1023,7 +1023,7 @@ void func_8003C0F0(void) {
}
break;
}
} else if (GetCourse() == GetSkyscraper()) {
} else if (IsSkyscraper()) {
switch (gActiveScreenMode) {
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
@ -1053,7 +1053,7 @@ void func_8003C0F0(void) {
}
break;
}
} else if (GetCourse() == GetDoubleDeck()) {
} else if (IsDoubleDeck()) {
switch (gActiveScreenMode) {
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
@ -1083,7 +1083,7 @@ void func_8003C0F0(void) {
}
break;
}
} else if (GetCourse() == GetBigDonut()) {
} else if (IsBigDonut()) {
switch (gActiveScreenMode) {
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
@ -1194,12 +1194,13 @@ void func_8003D080(void) {
} else {
func_8003C0F0();
}
if (!gDemoMode) {
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
switch (gModeSelection) {
case GRAND_PRIX:
if (GetCourse() == GetToadsTurnpike()) {
if (IsToadsTurnpike()) {
camera_init(0.0f, player->pos[1], D_80165230[7], player->rotation[1], 8, 0);
} else {
camera_init((D_80165210[7] + D_80165210[6]) / 2, player->pos[1], D_80165230[7],
@ -1289,6 +1290,9 @@ void func_8003D080(void) {
}
}
// Init freecam
//freecam_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 4);
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
func_8003CD98(gPlayerOneCopy, camera1, 0, 0); // sic

View File

@ -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;

View File

@ -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 };
@ -2088,8 +2090,6 @@ void init_smoke_particles(s32 arg0) {
}
}
void init_object_leaf_particle(s32 objectIndex, Vec3f arg1, s32 num) {
UNUSED s32 stackPadding1;
UNUSED u16 stackPadding0;
@ -2104,19 +2104,19 @@ void init_object_leaf_particle(s32 objectIndex, Vec3f arg1, s32 num) {
gObjectList[objectIndex].sizeScaling = 0.1f;
gObjectList[objectIndex].surfaceHeight = arg1[1];
if (GetCourse() == GetMarioRaceway()) {
if (IsMarioRaceway()) {
object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 25.0, arg1[2], 0x14, 0x1E, 0x14);
gObjectList[objectIndex].unk_034 = 1.5f;
gObjectList[objectIndex].velocity[1] = 1.5f;
} else if (GetCourse() == GetYoshiValley()) {
} else if (IsYoshiValley()) {
object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 25.0, arg1[2], 0x14, 0x1E, 0x14);
gObjectList[objectIndex].unk_034 = 2.0f;
gObjectList[objectIndex].velocity[1] = 2.0f;
} else if (GetCourse() == GetRoyalRaceway()) {
} else if (IsRoyalRaceway()) {
object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 30.0, arg1[2], 0x10, 0x28, 0x10);
gObjectList[objectIndex].unk_034 = 2.0f;
gObjectList[objectIndex].velocity[1] = 2.0f;
} else if (GetCourse() == GetLuigiRaceway()) {
} else if (IsLuigiRaceway()) {
object_origin_pos_randomize_around_xyz(objectIndex, arg1[0], arg1[1] + 25.0, arg1[2], 0x14, 0x1E, 0x14);
gObjectList[objectIndex].unk_034 = 1.5f;
gObjectList[objectIndex].velocity[1] = 1.0f;
@ -2454,21 +2454,30 @@ void update_snowflakes(void) {
}
}
// This function adjusted to place clouds in the sky correctly
void func_800788F8(s32 objectIndex, u16 rot, Camera* camera) {
s16 temp_v0;
s16 cameraRot;
// Adjustable culling factor
const float cullingFactor = OTRGetAspectRatio();
temp_v0 = camera->rot[1] + rot;
if ((temp_v0 >= D_8018D210) && (D_8018D208 >= temp_v0)) {
gObjectList[objectIndex].unk_09C = (D_8018D218 + (D_8018D1E8 * temp_v0));
set_object_flag(objectIndex, 0x00000010);
return;
// Calculate the cloud's rotation relative to the camera
cameraRot = camera->rot[1] + rot;
// Adjust bounds based on the culling factor
s16 adjustedLowerBound = (s16) (D_8018D210 * cullingFactor);
s16 adjustedUpperBound = (s16) (D_8018D208 * cullingFactor);
// Check if the object is within the adjusted bounds
if ((cameraRot >= adjustedLowerBound) && (adjustedUpperBound >= cameraRot)) {
// Calculate and update the object's position
gObjectList[objectIndex].unk_09C = (D_8018D218 + (D_8018D1E8 * cameraRot));
// Mark the object as visible
set_object_flag(objectIndex, 0x10);
} else {
// If outside the bounds, mark the object as not visible
set_object_flag(objectIndex, 0x10);
}
if (CVarGetInteger("gNoCulling", 0) == 1) {
gObjectList[objectIndex].unk_09C = (D_8018D218 + (D_8018D1E8 * temp_v0));
set_object_flag(objectIndex, 0x00000010);
return;
}
clear_object_flag(objectIndex, 0x00000010);
}
void update_clouds(s32 arg0, Camera* arg1, CloudData* cloudList) {
@ -2601,7 +2610,6 @@ void func_80078C70(s32 arg0) {
}
}
void func_8007ABFC(s32 playerId, bool arg1) {
s32 itemWindow;
@ -3448,7 +3456,7 @@ void func_8007BB9C(s32 arg0) {
}
void wrapper_update_boos(void) {
//update_boos();
// update_boos();
}
// Updates the display status on an object based on its relative direction to the camera
@ -3476,7 +3484,6 @@ void func_8007C420(s32 objectIndex, Player* player, Camera* camera) {
func_8007C360(objectIndex, camera);
}
void func_8007CE0C(s32 objectIndex) {
Object* object;
@ -3873,8 +3880,6 @@ void func_800842C8(void) {
}
}
void func_80085BB4(s32 objectIndex) {
gObjectList[objectIndex].sizeScaling = 8.0f;
set_obj_origin_offset(objectIndex, 0.0f, 0.0f, 0.0f);

2
torch

@ -1 +1 @@
Subproject commit 8e56ea0294973b7c9f8f077a131b40fce13b8489
Subproject commit f75facb20883570ed091e8ae733ec0539f606e57