Camera Refactor --> Adds Track Tour Camera (#568)

* Impl SpawnParams

* Added json submodule

* Update json

* Update

* Works

* Remove comment

* Works refactor

* Snowman and thwomp working

* Impl hot air balloon

* More progress

* All OObjects are done

* cleanup

* Refactor 2Dpath to normal path

* Update nlohmann json & fix compile

* Rest of actors

* MORE CHANGES

* Finish actors

* Done PR, some fix to collision viewer

* Impl falling rocks

* Add const

* wip editor refactor

* Property work

* continue

* Overridable editor properties

* Actor saving/loading works now

* Fix light alignment

* Clarification

* Impl penguin

* params impl signs

* properties impl falling rock

* More property impls

* impl air balloon

* Add spawnParams to OObject Translate

* Snowman translate better

* impl hedgehog properly

* properties impl trophy

* thwomp progress

* Finish impl properties

* Fix compile

* Fix cursor collisions

* Move registered actors

* Rename pathPoint XYZ to xyz

* Fix editor pause bug

* Clean up

* Review comments

* Remove SpawnParams struct from actor classes

* Rename

* Player Label First Iteration

* Work now

* Working 3d text

* Fix boo bug

* Finish AText actor

* Fix spawnparams compile

* Register AText

* Finish Text Actor

* Fix thwomp interpolation

* Fix compile

* Fix crab and hedgehog

* Fix loading flagpole

* Fix Hot Air Balloon

* Turn zbuffer on for AText

* Update

* Camera Refactor

* Camera Refactor Complete

* Place Lookbehind behind a CVar

* Make Tour CVar

* Fix Tour Camera Billboarding

* micro optimization

* Impl tour cam in imgui editor and add to scenefile

* As per review

* Revert cleanWorld change as per review

* Cleanup SceneManager

* Func rename

* Proper enabling of freecam and wip zoom fix

* Couple fix

* Fix credits

* Fix podium ceremony

* Stop music on reset & label new play sequence func

* Rename func_800C8EF8 to play_sequence2

* Rename func_800CA414 to play_sequences

* Fix compile

* Label play_sequences

* Clean up

* Verify lakitu access

* Renames

* Fix tour enable logic

* Add Audio

* tour camera impl ending transition

* As per review

* Fix linux compile, probably

* Update TourCamera.cpp

* Update TourCamera.cpp

* Update TrackProperties.cpp

* Update TrackProperties.cpp

* Update Game.cpp

* Update SceneManager.cpp

* Update camera.c

* Update render_objects.h

* Update render_objects.h

* Update code_80057C60.h

* fixing compile

* addition

---------

Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
This commit is contained in:
MegaMech 2025-12-07 13:14:45 -07:00 committed by GitHub
parent 02ad54ca72
commit 6585333092
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
93 changed files with 2032 additions and 1555 deletions

2
.gitignore vendored
View File

@ -42,6 +42,8 @@
*.swp
.vscode/*
vcpkg_installed/*
# General project-specific ignores
__pycache__/*
doxygen/doxygen/*

View File

@ -139,7 +139,7 @@ enum MusicSeq {
MUSIC_SEQ_DK_JUNGLE,
MUSIC_SEQ_GAME_OVER,
MUSIC_SEQ_TOADS_TURNPIKE,
MUSIC_SEQ_START_GIRD_TIME_ATTACK,
MUSIC_SEQ_START_GRID_TIME_ATTACK,
MUSIC_SEQ_VS_BATTLE_RESULTS,
MUSIC_SEQ_LOSING_RESULTS,
MUSIC_SEQ_BATTLE_ARENAS,

View File

@ -15,7 +15,7 @@ void render_actor_banana(Camera* camera, UNUSED Mat4 arg1, struct BananaActor* b
Vec3s sp7C;
Mat4 sp3C;
f32 temp = is_within_render_distance(camera->pos, banana->pos, camera->rot[1], 0, gCameraZoom[camera - camera1],
f32 temp = is_within_render_distance(camera->pos, banana->pos, camera->rot[1], 0, gCameraFOV[camera - camera1],
490000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp = MAX(temp, 0.0f);

View File

@ -18,7 +18,7 @@ void render_actor_box_truck(Camera* arg0, struct Actor* arg1) {
Mat4 spD8;
UNUSED s32 pad2[32];
f32 temp_f0 =
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 2500.0f, gCameraZoom[arg0 - camera1], 9000000.0f);
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 2500.0f, gCameraFOV[arg0 - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
}

View File

@ -16,7 +16,7 @@ void render_actor_car(Camera* arg0, struct Actor* arg1) {
Mat4 spC8;
UNUSED s32 pad2[32];
f32 temp_f0 =
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 2500.0f, gCameraZoom[arg0 - camera1], 9000000.0f);
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 2500.0f, gCameraFOV[arg0 - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
}

View File

@ -13,7 +13,7 @@
* @param arg2
*/
void render_actor_cow(Camera* camera, Mat4 arg1, struct Actor* arg2) {
if (is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1],
if (is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1],
4000000.0f) < 0 &&
CVarGetInteger("gNoCulling", 0) == 0) {
return;

View File

@ -28,7 +28,7 @@ void render_actor_fake_item_box(Camera* camera, struct FakeItemBox* fakeItemBox)
// @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],
if (is_within_render_distance(camera->pos, fakeItemBox->pos, camera->rot[1], 2500.0f, gCameraFOV[camera - camera1],
1000000.0f) < 0 &&
CVarGetInteger("gNoCulling", 0) == 0) {
actor_not_rendered(camera, (struct Actor*) fakeItemBox);

View File

@ -21,7 +21,7 @@ void render_actor_falling_rock(Camera* camera, struct FallingRock* rock) {
return;
}
height = is_within_render_distance(camera->pos, rock->pos, camera->rot[1], 400.0f, gCameraZoom[camera - camera1],
height = is_within_render_distance(camera->pos, rock->pos, camera->rot[1], 400.0f, gCameraFOV[camera - camera1],
4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {

View File

@ -30,7 +30,7 @@ void render_actor_item_box(Camera* camera, struct ItemBox* item_box) {
// @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],
temp_f0 = is_within_render_distance(camera->pos, item_box->pos, camera->rot[1], 0.0f, gCameraFOV[camera - camera1],
4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = CLAMP(temp_f0, 0.0f, 600000.0f);

View File

@ -19,7 +19,7 @@ void render_actor_mario_sign(Camera* arg0, UNUSED Mat4 arg1, struct Actor* arg2)
return;
}
unk = is_within_render_distance(arg0->pos, arg2->pos, arg0->rot[1], 0, gCameraZoom[arg0 - camera1], 16000000.0f);
unk = is_within_render_distance(arg0->pos, arg2->pos, arg0->rot[1], 0, gCameraFOV[arg0 - camera1], 16000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
unk = MAX(unk, 0.0f);
}

View File

@ -29,7 +29,7 @@ void render_actor_paddle_boat(Camera* arg0, struct PaddleWheelBoat* boat, UNUSED
return;
}
temp = is_within_render_distance(arg0->pos, boat->pos, arg0->rot[1], 90000.0f, gCameraZoom[arg0 - camera1],
temp = is_within_render_distance(arg0->pos, boat->pos, arg0->rot[1], 90000.0f, gCameraFOV[arg0 - camera1],
9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {

View File

@ -21,7 +21,7 @@ void render_actor_palm_tree(Camera* arg0, UNUSED Mat4 arg1, struct PalmTree* arg
}
temp_f0 =
is_within_render_distance(arg0->pos, arg2->pos, arg0->rot[1], 0.0f, gCameraZoom[arg0 - camera1], 4000000.0f);
is_within_render_distance(arg0->pos, arg2->pos, arg0->rot[1], 0.0f, gCameraFOV[arg0 - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);

View File

@ -37,7 +37,7 @@ void render_actor_piranha_plant(Camera* arg0, Mat4 arg1, struct PiranhaPlant* ar
return;
}
temp_f0 = is_within_render_distance(arg0->pos, arg2->pos, arg0->rot[1], 0, gCameraZoom[arg0 - camera1], 1000000.0f);
temp_f0 = is_within_render_distance(arg0->pos, arg2->pos, arg0->rot[1], 0, gCameraFOV[arg0 - camera1], 1000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);

View File

@ -13,7 +13,7 @@
void render_actor_railroad_crossing(Camera* arg0, struct RailroadCrossing* rr_crossing) {
UNUSED Vec3s sp80 = { 0, 0, 0 };
Mat4 sp40;
f32 unk = is_within_render_distance(arg0->pos, rr_crossing->pos, arg0->rot[1], 0.0f, gCameraZoom[arg0 - camera1],
f32 unk = is_within_render_distance(arg0->pos, rr_crossing->pos, arg0->rot[1], 0.0f, gCameraFOV[arg0 - camera1],
4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {

View File

@ -18,7 +18,7 @@ void render_actor_school_bus(Camera* arg0, struct Actor* arg1) {
f32 temp_f0;
temp_f0 =
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 2500.0f, gCameraZoom[arg0 - camera1], 9000000.0f);
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 2500.0f, gCameraFOV[arg0 - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);

View File

@ -15,7 +15,7 @@ void render_actor_tanker_truck(Camera* camera, struct Actor* arg1) {
Mat4 spC8;
UNUSED s32 pad2[32];
f32 temp_f0 = is_within_render_distance(camera->pos, arg1->pos, camera->rot[1], 2500.0f,
gCameraZoom[camera - camera1], 9000000.0f);
gCameraFOV[camera - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);

View File

@ -20,7 +20,7 @@ void render_actor_train_engine(Camera* camera, struct TrainCar* actor) {
Mat4 resultMtx;
f32 distance = is_within_render_distance(camera->pos, actor->pos, camera->rot[1], 2500.0f,
gCameraZoom[camera - camera1], 9000000.0f);
gCameraFOV[camera - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
distance = MAX(distance, 0.0f);
@ -175,7 +175,7 @@ void render_actor_train_tender(Camera* camera, struct TrainCar* actor) {
Mat4 spA0;
f32 temp_f0 = is_within_render_distance(camera->pos, actor->pos, camera->rot[1], 625.0f,
gCameraZoom[camera - camera1], 9000000.0f);
gCameraFOV[camera - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -268,7 +268,7 @@ void render_actor_train_passenger_car(Camera* camera, struct TrainCar* actor) {
Mat4 spA0;
f32 temp_f0 = is_within_render_distance(camera->pos, actor->pos, camera->rot[1], 2025.0f,
gCameraZoom[camera - camera1], 9000000.0f);
gCameraFOV[camera - camera1], 9000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);

View File

@ -22,7 +22,7 @@ void render_actor_tree_mario_raceway(Camera* camera, Mat4 arg1, struct Actor* ar
return;
}
temp_f0 = is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1],
temp_f0 = is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1],
16000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
@ -62,7 +62,7 @@ void render_actor_tree_yoshi_valley(Camera* camera, Mat4 arg1, struct Actor* arg
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -101,7 +101,7 @@ void render_actor_tree_royal_raceway(Camera* camera, Mat4 arg1, struct Actor* ar
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -140,7 +140,7 @@ void render_actor_tree_moo_moo_farm(Camera* camera, Mat4 arg1, struct Actor* arg
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 6250000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 6250000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -172,7 +172,7 @@ void render_actor_tree_luigi_raceway(Camera* camera, Mat4 arg1, struct Actor* ar
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -215,7 +215,7 @@ void render_actor_tree_peach_castle(Camera* camera, Mat4 arg1, struct Actor* arg
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -254,7 +254,7 @@ void render_actor_bush_bowser_castle(Camera* camera, Mat4 arg1, struct Actor* ar
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 640000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 640000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -293,7 +293,7 @@ void render_actor_tree_frappe_snowland(Camera* camera, Mat4 arg1, struct Actor*
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -331,7 +331,7 @@ void render_actor_tree_cactus1_kalimari_desert(Camera* camera, Mat4 arg1, struct
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -369,7 +369,7 @@ void render_actor_tree_cactus2_kalimari_desert(Camera* camera, Mat4 arg1, struct
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);
@ -407,7 +407,7 @@ void render_actor_tree_cactus3_kalimari_desert(Camera* camera, Mat4 arg1, struct
}
temp_f0 =
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 4000000.0f);
is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = MAX(temp_f0, 0.0f);

View File

@ -13,7 +13,7 @@
void render_actor_wario_sign(Camera* arg0, struct Actor* arg1) {
Mat4 sp38;
f32 unk =
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 0, gCameraZoom[arg0 - camera1], 16000000.0f);
is_within_render_distance(arg0->pos, arg1->pos, arg0->rot[1], 0, gCameraFOV[arg0 - camera1], 16000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
unk = MAX(unk, 0.0f);

View File

@ -20,7 +20,7 @@ void render_actor_yoshi_egg(Camera* arg0, Mat4 arg1, struct YoshiValleyEgg* egg,
f32 temp_f0;
if (gGamestate != CREDITS_SEQUENCE) {
temp_f0 = is_within_render_distance(arg0->pos, egg->pos, arg0->rot[1], 200.0f, gCameraZoom[arg0 - camera1],
temp_f0 = is_within_render_distance(arg0->pos, egg->pos, arg0->rot[1], 200.0f, gCameraFOV[arg0 - camera1],
16000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {

View File

@ -626,38 +626,33 @@ void func_800C2474(void) {
D_8018EFD8[var_v0].next = 0xFF;
}
#ifdef NON_MATCHING
// https://decomp.me/scratch/B9kUf
// No idea what's up with this function. `arg1_copy` is a huge improvement but feels very silly
// Presumably there's some macro being used to do all the or'ing (creating soundbits), that might
// matter for match purposes
void func_800C284C(u8 arg0, u8 arg1, u8 arg2, u16 arg3) {
u8 var_v1;
u8* arg1_copy = &arg1;
UNUSED s32 pad;
if ((D_800EA1EC == 0) || (arg0 == 2)) {
if (1) {}
func_800CBBB8(0x82000000 | (arg0 << 0x10) | (*arg1_copy << 8), arg3);
D_801930D0[arg0].unk_248 = *arg1_copy | (arg2 << 8);
if (D_801930D0[arg0].unk_000 != 1.0f) {
func_800CBB88(0x41000000 | (arg0 << 0x10), D_801930D0[arg0].unk_000);
}
D_801930D0[arg0].unk_028 = 0;
D_801930D0[arg0].unk_018 = 0;
D_801930D0[arg0].unk_014 = 0;
for (var_v1 = 0; var_v1 < 16; var_v1++) {
D_801930D0[arg0].unk_044[var_v1].unk_00 = 1.0f;
D_801930D0[arg0].unk_044[var_v1].unk_0C = 0;
D_801930D0[arg0].unk_044[var_v1].unk_10 = 1.0f;
D_801930D0[arg0].unk_044[var_v1].unk_1C = 0;
}
D_801930D0[arg0].unk_244 = 0;
D_801930D0[arg0].unk_246 = 0;
if ((D_800EA1EC != 0) && (arg0 != 2)) {
return;
}
func_800CBBB8(0x82000000 | (((u32) arg0 & 0xFF) << 0x10) | (((u32) arg1 & 0xFF) << 8), arg3);
D_801930D0[arg0].unk_248 = arg1 | (arg2 << 8);
if (D_801930D0[arg0].unk_000 != 1.0f) {
func_800CBB88(0x41000000 | (((u32) arg0 & 0xFF) << 0x10), D_801930D0[arg0].unk_000);
}
D_801930D0[arg0].unk_028 = 0;
D_801930D0[arg0].unk_018 = 0;
D_801930D0[arg0].unk_014 = 0;
for (var_v1 = 0; var_v1 < 16; var_v1++) {
D_801930D0[arg0].unk_044[var_v1].unk_00 = 1.0f;
D_801930D0[arg0].unk_044[var_v1].unk_0C = 0;
D_801930D0[arg0].unk_044[var_v1].unk_10 = 1.0f;
D_801930D0[arg0].unk_044[var_v1].unk_1C = 0;
}
D_801930D0[arg0].unk_244 = 0;
D_801930D0[arg0].unk_246 = 0;
}
#else
GLOBAL_ASM("asm/non_matchings/audio/external/func_800C284C.s")
#endif
void func_800C29B4(u8 arg0, u16 arg1) {
func_800CBBB8(((arg0 & 0xFF) << 0x10) | 0x83000000, arg1);
@ -2432,15 +2427,15 @@ void func_800C76C0(u8 playerId) {
func_800C97C4(playerId);
D_800EA0F0 = 2;
func_800C9A88(playerId);
func_800CA414(0x000DU, 0x0010U);
play_sequences(MUSIC_SEQ_FINISH_1ST_PLACE, MUSIC_SEQ_WINNING_RESULTS);
} else if (gPlayers[playerId].currentRank < 4) {
func_800C97C4(playerId);
D_800EA0F0 = 2;
func_800C9A88(playerId);
func_800CA414(0x000EU, 0x0010U);
play_sequences(MUSIC_SEQ_FINISH_2ND_4TH_PLACE, MUSIC_SEQ_WINNING_RESULTS);
} else {
func_800C3448(-0x3E9F9C00);
func_800CA414(0x000FU, 0x0018U);
play_sequences(MUSIC_SEQ_FINISH_5TH_8TH_PLACE, MUSIC_SEQ_LOSING_RESULTS);
}
} else {
D_800EA0EC[playerId] = 2;
@ -2451,7 +2446,7 @@ void func_800C76C0(u8 playerId) {
func_800C97C4(playerId);
D_800EA0F0 = 2;
func_800C9A88(playerId);
func_800CA414(0x000DU, 0x0010U);
play_sequences(MUSIC_SEQ_FINISH_1ST_PLACE, MUSIC_SEQ_WINNING_RESULTS);
} else if (gPlayers[playerId].currentRank < 4) {
if (D_800EA104 == 0) {
func_800C3448(0x100100FF);
@ -2460,12 +2455,12 @@ void func_800C76C0(u8 playerId) {
func_800C97C4(playerId);
D_800EA0F0 = 2;
func_800C9A88(playerId);
func_800CA414(0x000EU, 0x0010U);
play_sequences(MUSIC_SEQ_FINISH_2ND_4TH_PLACE, MUSIC_SEQ_WINNING_RESULTS);
} else if (D_800EA104 == 0) {
func_800C3448(0x100100FF);
func_800C3448(0x110100FF);
func_800C3448(-0x3E9F9C00);
func_800CA414(0x000FU, 0x0018U);
play_sequences(MUSIC_SEQ_FINISH_5TH_8TH_PLACE, MUSIC_SEQ_LOSING_RESULTS);
}
if ((D_800EA104 != 0) || (D_800EA0EC[playerId] != 1)) {
func_800C5278(5U);
@ -2481,9 +2476,9 @@ void func_800C76C0(u8 playerId) {
D_800EA0EC[playerId] = 2;
func_800C9060(playerId, 0x1900F103U);
if (D_801657E5 == 1) {
func_800CA414(0x000DU, 0x0010U);
play_sequences(MUSIC_SEQ_FINISH_1ST_PLACE, MUSIC_SEQ_WINNING_RESULTS);
} else if (D_8018ED90 == 1) {
func_800CA414(0x000EU, 0x0010U);
play_sequences(MUSIC_SEQ_FINISH_2ND_4TH_PLACE, MUSIC_SEQ_WINNING_RESULTS);
} else {
func_800C3448(0x01640010);
}
@ -2498,16 +2493,16 @@ void func_800C76C0(u8 playerId) {
func_800C97C4(playerId);
D_800EA0F0 = 2;
func_800C9A88(playerId);
func_800CA414(0x000DU, 0x0017U);
play_sequences(MUSIC_SEQ_FINISH_1ST_PLACE, MUSIC_SEQ_VS_BATTLE_RESULTS);
break;
case 2: /* switch 1 */
if ((D_800EA104 == 0) && (D_800EA0EC[playerId] == 1)) {
func_800C3448(0x100100FF);
func_800C3448(0x110100FF);
#ifdef VERSION_EU
func_800C8EF8(0x000DU);
play_sequence2(MUSIC_SEQ_FINISH_1ST_PLACE);
#else
func_800CA414(0x000DU, 0x0017U);
play_sequences(MUSIC_SEQ_FINISH_1ST_PLACE, MUSIC_SEQ_VS_BATTLE_RESULTS);
#endif
D_800EA104 = 1;
} else if ((D_800EA104 == 1) && (D_800EA0EC[playerId] == 1)) {
@ -2516,7 +2511,7 @@ void func_800C76C0(u8 playerId) {
if (func_800C3508(1) != 0x000D) {
#endif
D_800EA104 = 0;
func_800CA414(0x000EU, 0x0017U);
play_sequences(MUSIC_SEQ_FINISH_2ND_4TH_PLACE, MUSIC_SEQ_VS_BATTLE_RESULTS);
}
D_800EA104 = 2;
}
@ -2525,12 +2520,12 @@ void func_800C76C0(u8 playerId) {
if ((D_800EA104 == 0) && (D_800EA0EC[playerId] == 1)) {
func_800C3448(0x100100FF);
func_800C3448(0x110100FF);
func_800C8EF8(0x000DU);
play_sequence2(MUSIC_SEQ_FINISH_1ST_PLACE);
D_800EA104 = 1;
} else if ((D_800EA104 == 1) && (D_800EA0EC[playerId] == 1)) {
if (func_800C3508(1) != 0x000D) {
D_800EA104 = 0;
func_800C8EF8(0x000EU);
play_sequence2(MUSIC_SEQ_FINISH_2ND_4TH_PLACE);
}
D_800EA104 = 2;
} else if ((D_800EA104 == 2) && (D_800EA0EC[playerId] == 1)) {
@ -2539,7 +2534,7 @@ void func_800C76C0(u8 playerId) {
if (func_800C3508(1) != 0x000E) {
#endif
D_800EA104 = 0;
func_800CA414(0x000EU, 0x0017U);
play_sequences(MUSIC_SEQ_FINISH_2ND_4TH_PLACE, MUSIC_SEQ_VS_BATTLE_RESULTS);
}
D_800EA104 = 3;
}
@ -2553,7 +2548,7 @@ void func_800C76C0(u8 playerId) {
func_800C3448(0x110100FF);
func_800C5278(5U);
func_800C9018(playerId, SOUND_ARG_LOAD(0x01, 0x00, 0xF9, 0x26));
func_800C8EF8(0x0017U);
play_sequence2(MUSIC_SEQ_VS_BATTLE_RESULTS);
D_800EA0EC[playerId] = 2;
func_800C90F4(playerId, (gPlayers[gPlayerWinningIndex].characterId * 0x10) +
SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x0D));
@ -2562,7 +2557,7 @@ void func_800C76C0(u8 playerId) {
if ((D_800EA0EC[0] == 1) && (D_800EA0EC[1] == 1) && (D_800EA0EC[2] == 1)) {
func_800C5278(5U);
func_800C9018(playerId, SOUND_ARG_LOAD(0x01, 0x00, 0x80, 0x26));
func_800C8EF8(0x0017U);
play_sequence2(MUSIC_SEQ_VS_BATTLE_RESULTS);
D_800EA0EC[playerId] = 2;
func_800C90F4(playerId, (gPlayers[gPlayerWinningIndex].characterId * 0x10) +
SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x0D));
@ -2573,7 +2568,7 @@ void func_800C76C0(u8 playerId) {
(D_800EA0EC[3] == 1)) {
func_800C5278(5U);
func_800C9018(playerId, SOUND_ARG_LOAD(0x01, 0x00, 0x80, 0x26));
func_800C8EF8(0x0017U);
play_sequence2(MUSIC_SEQ_VS_BATTLE_RESULTS);
D_800EA0EC[playerId] = 2;
func_800C90F4(playerId, (gPlayers[gPlayerWinningIndex].characterId * 0x10) +
SOUND_ARG_LOAD(0x29, 0x00, 0x80, 0x0D));
@ -2899,8 +2894,8 @@ void play_sequence(u16 arg0) {
}
}
void func_800C8EF8(u16 arg0) {
func_800C3448(arg0 | 0x1010000);
void play_sequence2(u16 arg0) {
func_800C3448(arg0 | 0x01010000);
D_800EA160 = arg0;
}
@ -3332,7 +3327,7 @@ void func_800CA388(u8 arg0) {
fade_channel_volume_scale(5, 0, arg0);
}
void func_800CA414(u16 arg0, u16 arg1) {
void play_sequences(u16 arg0, u16 arg1) {
if (D_800EA104 == 0) {
func_800C3448(func_800C3508(0) | 0x30000000);
func_800C35E8(0);
@ -3349,12 +3344,12 @@ void func_800CA49C(u8 arg0) {
} else if (D_800EA164 != 0) {
func_800C3448(0x100100FF); // 0x19000000
func_800C3448(0x110100FF);
func_800C8EF8(0xC);
play_sequence2(MUSIC_SEQ_FINAL_LAP_FANFARE);
func_800C3448(0xC1510011);
} else {
func_800C3448(0x100100FF); // 0x19000000
func_800C3448(0x110100FF);
func_800C8EF8(0xC);
play_sequence2(MUSIC_SEQ_FINAL_LAP_FANFARE);
func_800C3448(gCurrentMusicSeq | 0xC1500000);
func_800C3448(0xC130017D);
}
@ -3385,11 +3380,11 @@ void func_800CA59C(u8 playerId) {
func_800C3448(0xC1F00000);
func_800C3448(0xC1510011);
} else {
func_800C8EF8(0x0011U);
play_sequence2(MUSIC_SEQ_STAR_JINGLE);
}
} else {
if (1) {} // ?
func_800C8EF8(0x0011U);
play_sequence2(MUSIC_SEQ_STAR_JINGLE);
}
}
D_800EA10C[playerId] = 1;
@ -3600,7 +3595,7 @@ void func_800CB14C() {
if (D_800EA174 == 0x012C) {
play_sequence(MUSIC_SEQ_AWARD_CEREMONY_1ST_3RD);
func_800C3448(0x4000007F);
func_800C8EF8(0x001DU);
play_sequence2(MUSIC_SEQ_AWARD_CEREMONY_4TH_8TH);
func_800C3448(0x41000000);
}
if (D_800EA174 == 0x0230) {

View File

@ -272,7 +272,7 @@ void func_800C8C7C(u8);
void func_800C8CCC(void);
void play_sound2(s32);
void play_sequence(u16);
void func_800C8EF8(u16);
void play_sequence2(u16);
void func_800C8F44(u8);
void func_800C8F80(u8, u32);
@ -305,7 +305,7 @@ void func_800CA2E4(u8, s8);
void func_800CA30C(u8);
void func_800CA330(u8);
void func_800CA388(u8);
void func_800CA414(u16, u16);
void play_sequences(u16, u16);
void func_800CA49C(u8);
void func_800CA59C(u8);
void func_800CA984(u8);

View File

@ -1,4 +1,5 @@
#include <libultraship.h>
#include <stdio.h>
#include <macros.h>
#include <common_structs.h>
#include <defines.h>
@ -25,7 +26,7 @@
f32 D_800DDB30[] = { 0.4f, 0.6f, 0.275f, 0.3f };
Camera cameras[8]; // This size should be 5 but there is an overflow somewhere in Bowser's Castle, so we allocate 8 cameras to avoid it.
Camera cameras[NUM_CAMERAS]; // This size should be 5 but there is an overflow somewhere in Bowser's Castle, so we allocate 8 cameras to avoid it.
Camera* camera1 = &cameras[0];
Camera* camera2 = &cameras[1];
Camera* camera3 = &cameras[2];
@ -34,36 +35,34 @@ Camera* gFreecamCamera = &cameras[4];
UNUSED s32 D_801649D0[2];
f32 D_801649D8[4];
f32 D_801649E8[4];
f32 D_801649F8[4];
f32 D_801649D8[NUM_CAMERAS];
f32 D_801649E8[NUM_CAMERAS];
f32 D_801649F8[NUM_CAMERAS];
s32 D_80164A08[4];
s32 D_80164A18[4];
s32 D_80164A18[NUM_CAMERAS];
s32 D_80164A28;
s32 D_80164A2C;
static s32 sStagingTimer[NUM_CAMERAS];
f32 D_80164A30;
UNUSED f32 D_80164A34;
f32 D_80164A38[4];
f32 D_80164A48[4];
UNUSED s32 D_80164A58[8];
f32 D_80164A78[4];
f32 D_80164A38[NUM_CAMERAS];
f32 D_80164A48[NUM_CAMERAS];
f32 D_80164A78[NUM_CAMERAS];
s8 D_80164A88;
s8 D_80164A89;
// UNUSED s8 D_80164A8C[3];
f32 D_80164A90[4];
f32 D_80164AA0[4];
f32 D_80164A90[NUM_CAMERAS];
f32 D_80164AA0[NUM_CAMERAS];
extern f32 D_80164498[];
extern s16 D_80164678[];
void camera_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cameraId) {
Player* player = gPlayerOne;
void camera_init(Vec3f pos, s16 rot, u32 mode, s32 cameraId) {
Camera* camera = &cameras[cameraId];
camera->cameraId = cameraId;
if (cameraId >= NUM_CAMERAS) {
return;
}
D_80152300[cameraId] = arg4;
switch (arg4) {
camera->mode = mode;
sStagingTimer[cameraId] = 0;
switch (mode) {
case 0:
case 1:
case 3:
@ -71,17 +70,17 @@ void camera_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cam
case 9:
case 10:
D_80164A89 = 0;
camera->pos[0] = posX;
camera->pos[1] = posY;
camera->pos[2] = posZ;
camera->pos[0] = pos[0];
camera->pos[1] = pos[1];
camera->pos[2] = pos[2];
camera->someBitFlags = 0;
camera->lookAt[0] = 0.0f;
camera->lookAt[2] = 150.0f;
camera->lookAt[1] = posY - 3.0;
camera->lookAt[1] = pos[1] - 3.0;
camera->up[0] = 0.0f;
camera->up[1] = 1.0f;
camera->up[2] = 0.0f;
camera->playerId = (s16) cameraId;
camera->unk_B0 = 0;
camera->unk_A0 = 0.0f;
@ -97,14 +96,13 @@ void camera_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cam
D_80164AA0[cameraId] = 0.0f;
D_80164A78[cameraId] = D_800DDB30[gActiveScreenMode];
D_80164A18[cameraId] = 0;
D_80164A08[cameraId] = 0;
D_80164498[cameraId] = 0.0f;
//D_80164A08[cameraId] = 0; // Now reset in spawn_players_and_cameras
//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];
camera->unk_2C = rot;
camera->unk_AC = rot;
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
@ -165,45 +163,48 @@ void camera_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 cam
if (D_80164678[cameraId] == 0) {
if (D_80164A28 == 1) {
gCameraZoom[cameraId] = 80.0f;
gCameraFOV[cameraId] = 80.0f;
} else {
gCameraZoom[cameraId] = 40.0f;
gCameraFOV[cameraId] = 40.0f;
}
camera->unk_B4 = gCameraZoom[cameraId];
camera->unk_B4 = gCameraFOV[cameraId];
}
if (D_80164678[cameraId] == 1) {
if (D_80164A28 == 1) {
gCameraZoom[cameraId] = 100.0f;
gCameraFOV[cameraId] = 100.0f;
} else {
gCameraZoom[cameraId] = 60.0f;
gCameraFOV[cameraId] = 60.0f;
}
camera->unk_B4 = gCameraZoom[cameraId];
camera->unk_B4 = gCameraFOV[cameraId];
}
if (D_80164678[cameraId] == 2) {
if (D_80164A28 == 1) {
gCameraZoom[cameraId] = 100.0f;
gCameraFOV[cameraId] = 100.0f;
} else {
gCameraZoom[cameraId] = 60.0f;
gCameraFOV[cameraId] = 60.0f;
}
camera->unk_B4 = gCameraZoom[cameraId];
camera->unk_B4 = gCameraFOV[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);
}
// 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;
void freecam_init(Vec3f pos, s16 rot, u32 mode, s32 cameraId) {
Camera* camera = &cameras[cameraId];
camera->cameraId = cameraId;
if (cameraId >= NUM_CAMERAS) {
return;
}
//D_80152300[cameraId] = arg4;
switch (arg4) {
camera->mode = mode;
sStagingTimer[cameraId] = 0;
switch (mode) {
case 0:
case 1:
case 3:
@ -211,17 +212,17 @@ void freecam_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 ca
case 9:
case 10:
D_80164A89 = 0;
camera->pos[0] = posX;
camera->pos[1] = posY;
camera->pos[2] = posZ;
camera->pos[0] = pos[0];
camera->pos[1] = pos[1];
camera->pos[2] = pos[2];
camera->someBitFlags = 0;
camera->lookAt[0] = 0.0f;
camera->lookAt[2] = 150.0f;
camera->lookAt[1] = posY - 3.0;
camera->lookAt[1] = pos[1] - 3.0;
camera->up[0] = 0.0f;
camera->up[1] = 1.0f;
camera->up[2] = 0.0f;
camera->playerId = (s16) 0;
//camera->playerId = (s16) cameraId;
camera->unk_B0 = 0;
camera->unk_A0 = 0.0f;
@ -242,9 +243,8 @@ void freecam_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 ca
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];
camera->unk_2C = rot;
camera->unk_AC = rot;
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
@ -305,27 +305,27 @@ void freecam_init(f32 posX, f32 posY, f32 posZ, UNUSED s16 rot, u32 arg4, s32 ca
// if (D_80164678[cameraId] == 0) {
if (D_80164A28 == 1) {
// gCameraZoom[cameraId] = 80.0f;
// gCameraFOV[cameraId] = 80.0f;
} else {
// gCameraZoom[cameraId] = 40.0f;
// gCameraFOV[cameraId] = 40.0f;
}
camera->unk_B4 = gCameraZoom[0];
camera->unk_B4 = gCameraFOV[0];
// }
// if (D_80164678[cameraId] == 1) {
// if (D_80164A28 == 1) {
// gCameraZoom[cameraId] = 100.0f;
// gCameraFOV[cameraId] = 100.0f;
// } else {
// gCameraZoom[cameraId] = 60.0f;
// gCameraFOV[cameraId] = 60.0f;
// }
// camera->unk_B4 = gCameraZoom[cameraId];
// camera->unk_B4 = gCameraFOV[cameraId];
// // }
// if (D_80164678[cameraId] == 2) {
// if (D_80164A28 == 1) {
// gCameraZoom[cameraId] = 100.0f;
// gCameraFOV[cameraId] = 100.0f;
// } else {
// gCameraZoom[cameraId] = 60.0f;
// gCameraFOV[cameraId] = 60.0f;
// }
// camera->unk_B4 = gCameraZoom[cameraId];
// camera->unk_B4 = gCameraFOV[cameraId];
// D_80164A38[cameraId] = 20.0f;
// D_80164A48[cameraId] = 1.5f;
// D_80164A78[cameraId] = 1.0f;
@ -342,7 +342,12 @@ void func_8001CA10(Camera* camera) {
}
void func_8001CA24(Player* player, f32 arg1) {
Camera* camera = &cameras[player - gPlayerOne];
Camera* camera = CM_GetPlayerCamera(player - gPlayerOne);
if (NULL == camera) {
printf("[camera.c][func_8001CA24] Could not find a camera using GetPlayerCamera()\n");
return;
}
camera->unk_94.unk_8 = 0;
camera->unk_94.unk_0 = arg1;
@ -1045,13 +1050,13 @@ void func_8001EE98(Player* player, Camera* camera, s8 index) {
switch (gModeSelection) {
case GRAND_PRIX:
// clang-format off
if (((player->type & PLAYER_CINEMATIC_MODE) == PLAYER_CINEMATIC_MODE) || (gDemoMode == 1)) { D_80152300[cameraIndex] = 3;
if (((player->type & PLAYER_CINEMATIC_MODE) == PLAYER_CINEMATIC_MODE) || (gDemoMode == 1)) { camera->mode = 3;
// --> --> Scroll right --> bit more --> ^ Required for matching
// clang-format on
} else if (gIsGamePaused == 1) {
func_8001A0A4(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0A4(&camera->mode, camera, player, index, cameraIndex);
} else {
func_8001A0DC(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0DC(&camera->mode, camera, player, index, cameraIndex);
}
break;
case BATTLE:
@ -1060,53 +1065,47 @@ void func_8001EE98(Player* player, Camera* camera, s8 index) {
func_80019ED0();
}
D_80164A88 = 1;
D_80152300[0] = 3;
D_80152300[1] = 3;
D_80152300[2] = 3;
D_80152300[3] = 3;
camera->mode = 3;
} else {
D_80164A88 = 0;
if (gIsGamePaused == 1) {
func_8001A0A4(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0A4(&camera->mode, camera, player, index, cameraIndex);
} else {
func_8001A0DC(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0DC(&camera->mode, camera, player, index, cameraIndex);
}
D_80152300[cameraIndex] = 9;
camera->mode = 9;
}
break;
case TIME_TRIALS:
if (((gPlayerOne->type & PLAYER_CINEMATIC_MODE) == PLAYER_CINEMATIC_MODE) || (gDemoMode == 1)) {
D_80152300[0] = 3;
D_80152300[1] = 3;
D_80152300[2] = 3;
D_80152300[3] = 3;
camera->mode = 3;
} else {
if (gIsGamePaused == 1) {
func_8001A0A4(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0A4(&camera->mode, camera, player, index, cameraIndex);
} else {
func_8001A0DC(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0DC(&camera->mode, camera, player, index, cameraIndex);
}
D_80152300[cameraIndex] = 1;
camera->mode = 1;
}
break;
case VERSUS:
if (((player->type & PLAYER_CINEMATIC_MODE) == PLAYER_CINEMATIC_MODE) || (gDemoMode == 1) ||
(D_8015F894 == 2)) {
D_80152300[cameraIndex] = 3;
camera->mode = 3;
} else {
if (gIsGamePaused == 1) {
func_8001A0A4(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0A4(&camera->mode, camera, player, index, cameraIndex);
} else {
func_8001A0DC(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A0DC(&camera->mode, camera, player, index, cameraIndex);
}
D_80152300[cameraIndex] = 1;
camera->mode = 1;
}
break;
}
if (gIsGamePaused == 0) {
switch (D_80152300[cameraIndex]) {
switch (camera->mode) {
case 3: // end of race
func_8001A588(&D_80152300[cameraIndex], camera, player, index, cameraIndex);
func_8001A588(&camera->mode, camera, player, index, cameraIndex);
break;
case 1: // player camera
if (((player->unk_0CA & 1) == 1) || ((player->unk_0CA & 2) == 2)) {
@ -1135,7 +1134,13 @@ void func_8001F394(Player* player, f32* arg1) {
UNUSED s32 pad;
s32 playerIndex = player - gPlayerOne;
UNUSED s32 pad2;
Camera* camera = &cameras[playerIndex];
Camera* camera = CM_GetPlayerCamera(player - gPlayerOne);
if (NULL == camera) {
printf("[camera.c][func_8001F394] Could not find a camera using GetPlayerCamera()\n");
return;
}
if (player == gPlayerOne) {
playerIndex = 0;
@ -1260,25 +1265,20 @@ void func_8001F394(Player* player, f32* arg1) {
}
void func_8001F87C(s32 cameraId) {
s32 playerIndex;
// Why?
s32 id = cameraId;
if (gPlayerOne) {}
if (gActiveScreenMode == SCREEN_MODE_1P) {
if (gModeSelection == GRAND_PRIX) {
for (playerIndex = 0; playerIndex < NUM_PLAYERS; playerIndex++) {
if ((gPlayerOne[playerIndex].type & 0x200) || (gPlayerOne[playerIndex].type & 0x80)) {
for (size_t i = 0; i < NUM_PLAYERS; i++) {
if ((gPlayerOne[i].type & 0x200) || (gPlayerOne[i].type & 0x80)) {
break;
}
if (playerIndex == 7) {
D_80164A2C += 1;
if (i == PLAYER_EIGHT) {
sStagingTimer[cameraId] += 1;
}
if ((playerIndex == 7) && (D_80164A2C == 0x0000003C)) {
if ((i == PLAYER_EIGHT) && (sStagingTimer[cameraId] == 60)) {
D_80164A28 = 2;
D_80152300[id] = 1;
cameras[id].rot[1] = gPlayerOne[playerIndex].rotation[1];
cameras[id].unk_2C = gPlayerOne[playerIndex].rotation[1];
cameras[cameraId].mode = 1;
cameras[cameraId].rot[1] = gPlayerOne[i].rotation[1];
cameras[cameraId].unk_2C = gPlayerOne[i].rotation[1];
}
}
}

View File

@ -17,6 +17,14 @@
#define BAD_RETURN(cmd) cmd
#endif
#define NUM_CAMERAS 16
typedef enum RenderMode {
RENDER_TRACK_SECTIONS,
RENDER_FULL_SCENE,
RENDER_COLLISION_MESH
};
typedef struct {
f32 unk_0;
s16 unk_4;
@ -56,10 +64,15 @@ typedef struct {
/* 0xB2 */ s16 unk_B2;
/* 0xB4 */ f32 unk_B4;
size_t cameraId;
} Camera; /* size = 0xB8 */
int32_t mode;
/* 0xB8 */ enum RenderMode renderMode;
/* 0xBC */ Mtx* perspectiveMatrix;
/* 0xC0 */ Mtx* lookAtMatrix;
void camera_init(f32, f32, f32, s16, u32, s32);
void freecam_init(f32 posX, f32 posY, f32 posZ, s16 rot, u32 arg4, s32 cameraId);
} Camera; /* size = 0xBC */
void camera_init(Vec3f pos, s16 rot, u32, s32);
void freecam_init(Vec3f pos, s16 rot, u32 mode, s32 cameraId);
void func_8001CA10(Camera*);
void func_8001CA24(Player*, f32);
void func_8001CA78(Player*, Camera*, Vec3f, f32*, f32*, f32*, s32, s32);

View File

@ -229,7 +229,9 @@ void setup_race(void) {
D_8015F700 = 200;
func_80005310();
func_8003D080();
CM_CleanCameras();
spawn_players_and_cameras();
load_kart_textures();
init_hud();
gRaceState = RACE_INIT;
gNumSpawnedShells = 0;
@ -305,7 +307,9 @@ void setup_editor(void) {
D_8015F700 = 200;
func_80005310();
func_8003D080();
CM_CleanCameras();
spawn_players_and_cameras();
load_kart_textures();
init_hud();
gRaceState = RACE_INIT;
gNumSpawnedShells = 0;

View File

@ -8,7 +8,11 @@
struct UnkStruct_800DC5EC {
/* 0x00 */ struct Controller* controllers; // gControllers ptr 800F6910
/* 0x04 */ Camera* camera; // Player camera ptr
/* 0x04 */ Camera* camera; // The active camera
/* */ Camera* raceCamera;
/* */ Camera* lookBehindCamera; // The lookBehind camera
Camera* freeCamera;
/* */ Camera* pendingCamera; // The camera to switch too next frame
/* 0x08 */ Player* player; // Player ptr 800F6990
/* 0x0C */ s32* unkC; // unk struct?
/* 0x10 */ Vp viewport;
@ -24,7 +28,7 @@ struct UnkStruct_800DC5EC {
/* 0x38 */ s16 pathCounter;
/* 0x3A */ s16 unk42;
/* 0x3C */ s32 pad2;
}; // size = 0x40
};
/* Function Prototypes */

View File

@ -192,21 +192,21 @@ s16* gPathExpectedRotation[4];
s16* gTrackConsecutiveCurveCounts[4];
u16 gPathIndexByPlayerId[12]; // D_801645B0
u16 gPathCountByPathIndex[4]; // D_801645C8
s32 D_801645D0[4];
s32 D_801645D0[NUM_CAMERAS];
s16* gCurrentTrackConsecutiveCurveCountsPath;
s32 D_801645E8[4];
f32 D_801645F8[4];
s32 D_80164608[4];
f32 D_80164618[4];
s32 D_80164628[4];
f32 D_80164638[4];
f32 D_80164648[4];
f32 D_80164658[4];
s16 gNearestPathPointByCameraId[4];
s16 D_80164670[4];
s16 D_80164678[4];
s16 D_80164680[4];
f32 D_80164688[4];
s32 D_801645E8[NUM_CAMERAS];
f32 D_801645F8[NUM_CAMERAS];
s32 D_80164608[NUM_CAMERAS];
f32 D_80164618[NUM_CAMERAS];
s32 D_80164628[NUM_CAMERAS];
f32 D_80164638[NUM_CAMERAS];
f32 D_80164648[NUM_CAMERAS];
f32 D_80164658[NUM_CAMERAS];
s16 gNearestPathPointByCameraId[NUM_CAMERAS];
s16 D_80164670[NUM_CAMERAS];
s16 D_80164678[NUM_CAMERAS];
s16 D_80164680[NUM_CAMERAS];
f32 D_80164688[NUM_CAMERAS];
f32 D_80164698;
f32 D_8016469C;
f32 D_801646A0;
@ -219,10 +219,10 @@ s32 D_801646B4;
s32 D_801646B8;
s32 D_801646BC;
// end padding
s16 D_801646C0[4];
s16 D_801646C0[NUM_CAMERAS];
u32 D_801646C8;
u16 D_801646CC;
UnkStruct_46D0 D_801646D0[4];
UnkStruct_46D0 D_801646D0[NUM_CAMERAS];
// Strings, presented by google translate!
// Note that these are EUC-JP encoded, see:
@ -3413,7 +3413,7 @@ void generate_player_smoke(void) {
void func_8000F0E0(void) {
s32 i;
for (i = 0; i < 4; i++) {
for (i = 0; i < NUM_CAMERAS; i++) {
D_80164670[i] = 0;
D_80164678[i] = 0;
}
@ -5401,7 +5401,7 @@ void func_80014DE4(s32 cameraIndex) {
D_80164678[cameraIndex] = 0;
}
for (cameraId = 0; cameraId < 4; cameraId++) {
for (cameraId = 0; cameraId < NUM_CAMERAS; cameraId++) {
gNearestPathPointByCameraId[cameraId] = 0;
}
}
@ -6667,6 +6667,40 @@ void func_80019C50(s32 arg0) {
}
}
void look_behind_toggle(s32 cameraIdx) {
static bool lookBehindActive[NUM_CAMERAS] = {0};
bool pressed = gControllers[cameraIdx].button & L_CBUTTONS; // button held
Camera* camera = &cameras[cameraIdx];
struct UnkStruct_800DC5EC* screenCtx = NULL;
if (CVarGetInteger("gLookBehind", false) == false) {
return;
}
if (cameras[cameraIdx].playerId < 0 || cameras[cameraIdx].playerId >= 4) {
return;
}
// Get the screen context
screenCtx = &D_8015F480[cameras[cameraIdx].playerId];
if (gRaceState == RACE_IN_PROGRESS) {
// Flip the camera
if (pressed && !lookBehindActive[cameraIdx]) {
screenCtx->pendingCamera = screenCtx->lookBehindCamera;
lookBehindActive[cameraIdx] = true;
// Unflip the camera
} else if (!pressed && lookBehindActive[cameraIdx]) {
screenCtx->pendingCamera = screenCtx->raceCamera;
lookBehindActive[cameraIdx] = false;
}
} else if (lookBehindActive[cameraIdx]) {
// Restore the original camera
screenCtx->pendingCamera = screenCtx->raceCamera;
lookBehindActive[cameraIdx] = false;
}
}
void func_80019D2C(Camera* camera, Player* player, s32 arg2) {
s32 playerId;
s32 nearestWaypoint;
@ -6693,7 +6727,7 @@ void func_80019DF4(void) {
s32 playerId = gGPCurrentRacePlayerIdByRank[0];
// clang-format off
// Has to be on a single line to match. Because IDO hates you :)
for (i = 0; i < 4; i++) { D_80164670[i] = D_80164678[i]; }
for (i = 0; i < NUM_CAMERAS; i++) { D_80164670[i] = D_80164678[i]; }
// clang-format on
camera1->playerId = playerId;
D_80164678[0] = 1;
@ -6714,7 +6748,7 @@ void func_80019E58(void) {
void func_80019ED0(void) {
s32 i;
for (i = 0; i < 4; i++) {
for (i = 0; i < NUM_CAMERAS; i++) {
D_80164670[i] = D_80164678[i];
}
@ -6722,7 +6756,7 @@ void func_80019ED0(void) {
camera1->playerId = (s16) gPlayerWinningIndex;
for (i = 0; i < 4; i++) {
for (i = 0; i < NUM_CAMERAS; i++) {
D_80164680[i] = 0;
func_80015314(gPlayerWinningIndex, 0, i);
D_80164678[i] = 1;
@ -6758,6 +6792,7 @@ void func_80019FB4(s32 cameraId) {
void func_8001A0A4(UNUSED u16* arg0, UNUSED Camera* arg1, UNUSED Player* arg2, UNUSED s8 arg3, s32 arg4) {
func_80019FB4(arg4);
func_80019C50(arg4);
look_behind_toggle(arg4);
}
void func_8001A0DC(u16* arg0, Camera* arg1, Player* arg2, s8 arg3, s32 arg4) {
@ -6962,6 +6997,7 @@ void func_8001A588(UNUSED u16* localD_80152300, Camera* camera, Player* player,
break;
}
func_80019C50(cameraIndex);
look_behind_toggle(cameraIndex);
switch (D_80164680[cameraIndex]) {
case 0:
func_80015390(camera, player, index);

View File

@ -489,7 +489,7 @@ void func_80057FC4(u32 arg0) {
}
}
void render_object(u32 arg0) {
void render_object(struct UnkStruct_800DC5EC* screen) {
UNUSED Gfx* temp_v1;
if (gHUDDisable != 0) {
@ -502,106 +502,17 @@ void render_object(u32 arg0) {
return;
}
switch (arg0) {
case RENDER_SCREEN_MODE_1P_PLAYER_ONE:
render_object_p1();
break;
case RENDER_SCREEN_MODE_2P_HORIZONTAL_PLAYER_ONE:
render_object_p1();
break;
case RENDER_SCREEN_MODE_2P_HORIZONTAL_PLAYER_TWO:
render_object_p2();
break;
case RENDER_SCREEN_MODE_2P_VERTICAL_PLAYER_ONE:
render_object_p1();
break;
case RENDER_SCREEN_MODE_2P_VERTICAL_PLAYER_TWO:
render_object_p2();
break;
case 5:
render_object_p1();
break;
case 6:
render_object_p2();
break;
case 7:
render_object_p3();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_ONE:
render_object_p1();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_TWO:
render_object_p2();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_THREE:
render_object_p3();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_FOUR:
render_object_p4();
break;
}
}
void render_object_p1(void) {
size_t playerIdx = PLAYER_ONE;
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
if (CVarGetInteger("gFreecam", 0) == true) {
playerIdx = CAMERA_FREECAM;
}
gSPMatrix(gDisplayListHead++, GetPerspMatrix(playerIdx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(playerIdx),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
// if (gGamestate == ENDING) {
// //func_80055F48(PLAYER_ONE);
// //func_80056160(PLAYER_ONE);
// //func_8005217C(PLAYER_ONE);
// //func_80054BE8(PLAYER_ONE);
// return;
// }
render_object_for_player(PLAYER_ONE);
}
void render_object_p2(void) {
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_TWO),
gSPMatrix(gDisplayListHead++, screen->camera->perspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_TWO),
gSPMatrix(gDisplayListHead++, screen->camera->lookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
// render_bomb_karts_wrap(PLAYER_TWO);
render_object_for_player(PLAYER_TWO);
render_object_for_player(screen->camera->cameraId);
}
void render_object_p3(void) {
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_THREE),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_THREE),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
// render_bomb_karts_wrap(PLAYER_THREE);
render_object_for_player(PLAYER_THREE);
}
void render_object_p4(void) {
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_FOUR),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_FOUR),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
// render_bomb_karts_wrap(PLAYER_FOUR);
if ((!gDemoMode) && (gPlayerCountSelection1 == 4)) {
// render_lakitu(PLAYER_FOUR);
}
render_object_for_player(PLAYER_FOUR);
}
void render_player_snow_effect(u32 arg0) {
void render_player_snow_effect(Camera* camera) {
UNUSED Gfx* temp_v1;
if (gHUDDisable != 0) {
@ -613,172 +524,24 @@ void render_player_snow_effect(u32 arg0) {
if (D_8018D22C != 0) {
return;
}
switch (arg0) {
case RENDER_SCREEN_MODE_1P_PLAYER_ONE:
render_player_snow_effect_one();
break;
case RENDER_SCREEN_MODE_2P_HORIZONTAL_PLAYER_ONE:
render_player_snow_effect_one();
break;
case RENDER_SCREEN_MODE_2P_HORIZONTAL_PLAYER_TWO:
render_player_snow_effect_two();
break;
case RENDER_SCREEN_MODE_2P_VERTICAL_PLAYER_ONE:
render_player_snow_effect_one();
break;
case RENDER_SCREEN_MODE_2P_VERTICAL_PLAYER_TWO:
render_player_snow_effect_two();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_ONE:
render_player_snow_effect_one();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_TWO:
render_player_snow_effect_two();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_THREE:
render_player_snow_effect_three();
break;
case RENDER_SCREEN_MODE_3P_4P_PLAYER_FOUR:
render_player_snow_effect_four();
break;
}
}
void render_player_snow_effect_one(void) {
size_t playerIdx = PLAYER_ONE;
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
if (CVarGetInteger("gFreecam", 0) == true) {
playerIdx = CAMERA_FREECAM;
}
gSPMatrix(gDisplayListHead++, GetPerspMatrix(playerIdx),
gSPMatrix(gDisplayListHead++, camera->perspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(playerIdx),
gSPMatrix(gDisplayListHead++, camera->lookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
if (gGamestate != ENDING) {
render_snowing_effect(PLAYER_ONE);
render_snowing_effect(camera->cameraId);
}
}
void render_player_snow_effect_two(void) {
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_TWO),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_TWO),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
render_snowing_effect(PLAYER_TWO);
}
void render_player_snow_effect_three(void) {
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_THREE),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_THREE),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
render_snowing_effect(PLAYER_THREE);
}
void render_player_snow_effect_four(void) {
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_FOUR),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_FOUR),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
render_snowing_effect(PLAYER_FOUR);
}
void render_object_for_player(s32 cameraId) {
CM_DrawObjects(cameraId);
CM_DrawParticles(cameraId);
CM_RenderCourseObjects(cameraId);
CM_DrawEditor();
// switch (gCurrentCourseId) {
// case COURSE_MARIO_RACEWAY:
// break;
// case COURSE_CHOCO_MOUNTAIN:
// break;
// case COURSE_BOWSER_CASTLE:
// render_object_thwomps(cameraId);
// render_object_bowser_flame(cameraId);
// break;
// case COURSE_BANSHEE_BOARDWALK:
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_trash_bin(cameraId);
// render_object_bat(cameraId);
// func_8005217C(cameraId);
// render_object_boos(cameraId);
// }
// break;
// case COURSE_YOSHI_VALLEY:
// func_80055228(cameraId);
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_hedgehogs(cameraId);
// }
// break;
// case COURSE_FRAPPE_SNOWLAND:
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_snowmans(cameraId);
// }
// break;
// case COURSE_KOOPA_BEACH:
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_crabs(cameraId);
// }
// if (gGamestate != CREDITS_SEQUENCE) {
// if ((gPlayerCount == 1) || (gPlayerCount == 2)) {
// render_object_seagulls(cameraId);
// }
// } else {
// render_object_seagulls(cameraId);
// }
// break;
// case COURSE_ROYAL_RACEWAY:
// break;
// case COURSE_LUIGI_RACEWAY:
// if (D_80165898 != 0) {
// render_object_hot_air_balloon(cameraId);
// }
// break;
// case COURSE_MOO_MOO_FARM:
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_moles(cameraId);
// }
// break;
// case COURSE_TOADS_TURNPIKE:
// break;
// case COURSE_KALIMARI_DESERT:
// render_object_trains_smoke_particles(cameraId);
// break;
// case COURSE_SHERBET_LAND:
// if (gGamestate != CREDITS_SEQUENCE) {
// func_80052E30(cameraId);
// }
// render_object_train_penguins(cameraId);
// break;
// case COURSE_RAINBOW_ROAD:
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_neon(cameraId);
// render_object_chain_chomps(cameraId);
// }
// break;
// case COURSE_WARIO_STADIUM:
// break;
// case COURSE_BLOCK_FORT:
// break;
// case COURSE_SKYSCRAPER:
// break;
// case COURSE_DOUBLE_DECK:
// break;
// case COURSE_DK_JUNGLE:
// if (gGamestate != CREDITS_SEQUENCE) {
// render_object_paddle_boat_smoke_particles(cameraId);
// }
// break;
// }
render_object_smoke_particles(cameraId);
render_object_leaf_particle(cameraId);
@ -6908,7 +6671,7 @@ void func_8006E420(Player* player, s8 arg1, s8 arg2) {
}
}
void render_kart_particle_on_screen_one(Player* player, s8 playerId, s8 screenId) {
void render_kart_particles(Player* player, s8 playerId, s8 screenId) {
if ((player->type & PLAYER_EXISTS) == PLAYER_EXISTS) {
if ((player->effects & BOO_EFFECT) == BOO_EFFECT) {
if (playerId == screenId) {
@ -6921,45 +6684,6 @@ void render_kart_particle_on_screen_one(Player* player, s8 playerId, s8 screenId
}
}
void render_kart_particle_on_screen_two(Player* player, s8 arg1, s8 arg2) {
if ((player->type & PLAYER_EXISTS) == PLAYER_EXISTS) {
if ((player->effects & BOO_EFFECT) == BOO_EFFECT) {
if (arg1 == arg2) {
func_8006D474(player, arg1, arg2);
}
} else {
func_8006D474(player, arg1, arg2);
}
func_8006DC54(player, arg1, arg2);
}
}
void render_kart_particle_on_screen_three(Player* player, s8 arg1, s8 arg2) {
if ((player->type & PLAYER_EXISTS) == PLAYER_EXISTS) {
if ((player->effects & BOO_EFFECT) == BOO_EFFECT) {
if (arg1 == arg2) {
func_8006D474(player, arg1, arg2);
}
} else {
func_8006D474(player, arg1, arg2);
}
func_8006DC54(player, arg1, arg2);
}
}
void render_kart_particle_on_screen_four(Player* player, s8 arg1, s8 arg2) {
if ((player->type & PLAYER_EXISTS) == PLAYER_EXISTS) {
if ((player->effects & BOO_EFFECT) == BOO_EFFECT) {
if (arg1 == arg2) {
func_8006D474(player, arg1, arg2);
}
} else {
func_8006D474(player, arg1, arg2);
}
func_8006DC54(player, arg1, arg2);
}
}
void func_8006E7CC(Player* player, s8 arg1, s8 arg2) {
if ((player->type & PLAYER_EXISTS) == PLAYER_EXISTS) {
if ((player->effects & BOO_EFFECT) == BOO_EFFECT) {

View File

@ -8,6 +8,7 @@ extern "C" {
#include <common_structs.h>
#include "objects.h"
#include "camera.h"
#include "code_800029B0.h"
// code_80057C60
@ -37,16 +38,8 @@ void func_80057CE4(void);
void func_80057DD0(void);
void func_80057FC4(u32);
void render_object(u32);
void render_object_p1(void);
void render_object_p2(void);
void render_object_p3(void);
void render_object_p4(void);
void render_player_snow_effect(u32);
void render_player_snow_effect_one(void);
void render_player_snow_effect_two(void);
void render_player_snow_effect_three(void);
void render_player_snow_effect_four(void);
void render_object(struct UnkStruct_800DC5EC* screen);
void render_player_snow_effect(Camera* camera);
void render_object_for_player(s32);
void render_snowing_effect(s32);
void func_80058BF4(void);
@ -249,10 +242,7 @@ void func_8006DD3C(Player*, s8, s8);
void func_8006E058(void);
void func_8006E420(Player*, s8, s8);
void render_kart_particle_on_screen_one(Player*, s8, s8);
void render_kart_particle_on_screen_two(Player*, s8, s8);
void render_kart_particle_on_screen_three(Player*, s8, s8);
void render_kart_particle_on_screen_four(Player*, s8, s8);
void render_kart_particles(Player* player, s8 playerId, s8 screenId);
void func_8006E7CC(Player*, s8, s8);
void func_8006E848(Player*, s8, s8);
void func_8006E8C4(Player*, s8, s8);

View File

@ -36,7 +36,7 @@ void init_camera_podium_ceremony(void) {
cameras[0].up[0] = 0.0f;
cameras[0].up[1] = 1.0f;
cameras[0].up[2] = 0.0f;
gCameraZoom[0] = 40.0f;
gCameraFOV[0] = 40.0f;
gScreenAspect = 1.33333333f;
D_80150150 = 3.0f;
D_8015014C = 6800.0f;

View File

@ -547,7 +547,7 @@ void init_cinematic_camera(void) {
camera->unk68 = 0.0f;
camera->unk6C = 0;
camera->unk6E = 0;
camera->unk20 = gCameraZoom[0];
camera->unk20 = gCameraFOV[0];
sCutsceneShot = 0;
gCutsceneShotTimer = 0;
D_802876D4 = 0;
@ -633,7 +633,7 @@ s32 func_80283648(Camera* camera) {
}
func_80282F44(0, cinematicCamera, camera);
func_80282F44(1, cinematicCamera, camera);
func_80283100(cinematicCamera, gCameraZoom);
func_80283100(cinematicCamera, gCameraFOV);
vec3f_copy_return_dupe(cinematicCamera->unk30, camera->pos);
vec3f_copy_return_dupe(cinematicCamera->unk24, camera->lookAt);
vec3f_copy_return_dupe(cinematicCamera->unk3C, camera->up);
@ -724,12 +724,12 @@ void func_80283BA4(UNUSED CinematicCamera* camera) {
}
void func_80283BF0(UNUSED CinematicCamera* camera) {
func_800C8EF8(0x1A);
play_sequence2(MUSIC_SEQ_AWARD_CEREMONY_BUILDUP);
}
//
void func_80283C14(UNUSED CinematicCamera* camera) {
func_800C8EF8(0x1B);
play_sequence2(MUSIC_SEQ_AWARD_CEREMONY_1ST_3RD);
}
void wrap_func_800CB134(UNUSED CinematicCamera* camera) {
@ -742,7 +742,7 @@ void wrap_func_800CB14C(UNUSED CinematicCamera* camera) {
void func_80283C78(UNUSED CinematicCamera* arg0) {
if (D_800DC5E4 == 0) {
func_800C8EF8(0x1C);
play_sequence2(MUSIC_SEQ_STAFF_ROLL);
}
}

View File

@ -39,9 +39,8 @@ void func_80280000(void) {
func_8005A070();
}
void func_80280038(void) {
void func_80280038(Camera* camera) {
u16 perspNorm;
Camera* camera = &cameras[0];
UNUSED s32 pad;
Mat4 matrix;
@ -57,13 +56,13 @@ void func_80280038(void) {
func_80057FC4(0);
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_SHADING_SMOOTH);
guPerspective(GetPerspMatrix(0), &perspNorm, gCameraZoom[0], gScreenAspect, CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
guPerspective(camera->perspectiveMatrix , &perspNorm, gCameraFOV[0], gScreenAspect, CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(0),
gSPMatrix(gDisplayListHead++, camera->perspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
guLookAt(GetLookAtMatrix(0), camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0],
guLookAt(camera->lookAtMatrix, 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++, GetLookAtMatrix(0),
gSPMatrix(gDisplayListHead++, camera->lookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gCurrentCourseId = gCreditsCourseId;
SetCourseById(gCreditsCourseId);
@ -71,10 +70,10 @@ void func_80280038(void) {
render_set_position(matrix, 0);
render_course(D_800DC5EC);
render_course_actors(D_800DC5EC);
CM_DrawActors(D_800DC5EC->camera);
CM_DrawActors(camera);
CM_DrawStaticMeshActors();
render_object(PLAYER_ONE + SCREEN_MODE_1P);
render_player_snow_effect(PLAYER_ONE + SCREEN_MODE_1P);
render_object(D_800DC5EC);
render_player_snow_effect(camera);
ceremony_transition_sliding_borders();
func_80281C40();
init_rdp();
@ -93,7 +92,9 @@ void func_80280268(s32 courseId) {
}
void credits_loop(void) {
Camera* camera = &cameras[0];
Editor_ClearMatrix();
CM_TickEditor();
Camera* camera = D_800DC5EC->camera;
f32 temp_f12;
f32 temp;
@ -121,7 +122,7 @@ void credits_loop(void) {
D_800DC5E4++;
} else {
func_80280000();
func_80280038();
func_80280038(camera);
#if DVDL
display_dvdl();
#endif
@ -132,20 +133,29 @@ void credits_loop(void) {
}
void load_credits(void) {
Camera* camera = &cameras[0];
CM_CleanCameras();
Vec3f spawn = {0.0f, 0.0f, 0.0f};
Camera* camera = CM_AddCamera(spawn, 0, 0);
if (NULL == camera) {
return;
}
CM_AttachCamera(camera, PLAYER_ONE);
D_800DC5EC->camera = camera;
camera->renderMode = RENDER_FULL_SCENE;
camera->unk_B4 = 60.0f;
gCameraFOV[0] = 60.0f;
gCurrentCourseId = gCreditsCourseId;
SetCourseById(gCreditsCourseId);
D_800DC5B4 = 1;
creditsRenderMode = 1;
func_802A4D18();
set_screen();
camera->unk_B4 = 60.0f;
gCameraZoom[0] = 60.0f;
D_800DC5EC->screenWidth = SCREEN_WIDTH;
D_800DC5EC->screenHeight = SCREEN_HEIGHT;
D_800DC5EC->screenStartX = 160;
D_800DC5EC->screenStartY = 120;
D_800DC5EC->screenStartX = SCREEN_WIDTH / 2;
D_800DC5EC->screenStartY = SCREEN_HEIGHT / 2;
gScreenModeSelection = SCREEN_MODE_1P;
gActiveScreenMode = SCREEN_MODE_1P;
gNextFreeMemoryAddress = gFreeMemoryResetAnchor;

View File

@ -6,7 +6,7 @@
/* Function Prototypes */
void func_80280000(void);
void func_80280038(void);
void func_80280038(Camera* camera);
void func_80280268(s32 arg0);
void credits_loop(void);
void load_credits(void);

View File

@ -93,7 +93,7 @@ void func_802818BC(void) {
}
void setup_podium_ceremony(void) {
Camera* camera = &cameras[0];
Vec3f spawn = {0, 0, 0};
clear_D_802874D8_actors();
@ -105,12 +105,10 @@ void setup_podium_ceremony(void) {
D_80287554 = 0;
func_802A4D18();
set_screen();
camera->unk_B4 = 60.0f;
gCameraZoom[0] = 60.0f;
D_800DC5EC->screenWidth = SCREEN_WIDTH;
D_800DC5EC->screenHeight = SCREEN_HEIGHT;
D_800DC5EC->screenStartX = 160;
D_800DC5EC->screenStartY = 120;
D_800DC5EC->screenStartX = SCREEN_WIDTH / 2;
D_800DC5EC->screenStartY = SCREEN_HEIGHT / 2;
gScreenModeSelection = SCREEN_MODE_1P;
gNextFreeMemoryAddress = gFreeMemoryResetAnchor;
gActiveScreenMode = SCREEN_MODE_1P;
@ -156,7 +154,12 @@ void setup_podium_ceremony(void) {
func_80295C6C();
debug_switch_character_ceremony_cutscene();
func_802818BC();
func_8003D080();
CM_CleanCameras();
spawn_players_and_cameras();
D_800DC5EC->camera->renderMode = RENDER_FULL_SCENE;
D_800DC5EC->camera->unk_B4 = 60.0f;
gCameraFOV[0] = 60.0f;
load_kart_textures();
init_hud();
func_8001C05C();
balloons_and_fireworks_init();

View File

@ -55,7 +55,7 @@ extern Gfx D_80284F70[];
extern Gfx D_80284EE0[];
void func_80281D00(void) {
Camera* camera = &cameras[0];
Camera* camera = D_800DC5EC->camera;
UNUSED s32 pad[3];
u16 perspNorm;
Mat4 matrix;
@ -74,22 +74,23 @@ void func_80281D00(void) {
}
func_8028150C();
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_SHADING_SMOOTH);
guPerspective(GetPerspMatrix(0), &perspNorm, gCameraZoom[0], gScreenAspect, CM_GetProps()->NearPersp, CM_GetProps()->FarPersp,
guPerspective(camera->perspectiveMatrix, &perspNorm, gCameraFOV[0], gScreenAspect, CM_GetProps()->NearPersp, CM_GetProps()->FarPersp,
1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(0),
gSPMatrix(gDisplayListHead++, camera->perspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
guLookAt(GetLookAtMatrix(0), camera->pos[0], camera->pos[1], camera->pos[2], camera->lookAt[0],
guLookAt(camera->lookAtMatrix, 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++, GetLookAtMatrix(0),
gSPMatrix(gDisplayListHead++, camera->lookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
mtxf_identity(matrix);
render_set_position(matrix, 0);
gSPDisplayList(gDisplayListHead++, D_80284F70);
render_players_on_screen_one();
render_players(camera, PLAYER_ONE);
gSPDisplayList(gDisplayListHead++, VIRTUAL_TO_PHYSICAL2(&D_80284EE0));
update_actors_loop();
render_object(RENDER_SCREEN_MODE_1P_PLAYER_ONE);
render_object(D_800DC5EC);
func_80021B0C();
gSPDisplayList(gDisplayListHead++, VIRTUAL_TO_PHYSICAL2(&D_80284EE0));
func_80093F10();

View File

@ -464,6 +464,7 @@ void func_80281540(void) {
void podium_ceremony_loop(void) {
ClearMatrixPools();
Editor_ClearMatrix();
CM_TickEditor();
gMatrixObjectCount = 0;
D_802874FC = 0;
update_camera_podium_ceremony();

View File

@ -9,6 +9,7 @@ extern "C" {
#include "main.h"
#include "camera.h"
#include "common_structs.h"
}
class AActor {
public:
@ -52,7 +53,7 @@ public:
virtual void SetSpawnParams(SpawnParams& params);
virtual void BeginPlay();
virtual void Tick();
virtual void Draw(Camera*);
virtual void Draw(Camera* camera);
virtual void Collision(Player* player, AActor* actor);
virtual void VehicleCollision(s32 playerId, Player* player);
void SetLocation(FVector pos);
@ -69,5 +70,3 @@ public:
void SetScale(FVector scale);
virtual void DrawEditorProperties() { DrawDefaultEditorProperties(); };
};
}

View File

@ -169,15 +169,15 @@ void HarbourMastersIntro::Setup() {
u16 perspNorm;
gDPSetTexturePersp(gDisplayListHead++, G_TP_PERSP);
// Setup camera perspective
guPerspective(GetPerspMatrix(0), &perspNorm, 45.0f, 1.3333334f, 100.0f, 12800.0f, 1.0f);
guPerspective(&PerspectiveMatrix, &perspNorm, 45.0f, 1.3333334f, 100.0f, 12800.0f, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(0), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, &PerspectiveMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
// Setup camera lookAt
guLookAt(GetLookAtMatrix(0), _camera.Pos.x, _camera.Pos.y, _camera.Pos.z, _camera.LookAt.x, _camera.LookAt.y, _camera.LookAt.z, 0.0f, 1.0f, 0.0f);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(0), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
guLookAt(&LookAtMatrix, _camera.Pos.x, _camera.Pos.y, _camera.Pos.z, _camera.LookAt.x, _camera.LookAt.y, _camera.LookAt.z, 0.0f, 1.0f, 0.0f);
gSPMatrix(gDisplayListHead++, &LookAtMatrix, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);

View File

@ -33,6 +33,8 @@ private:
FVector LookAt;
};
Mtx PerspectiveMatrix;
Mtx LookAtMatrix;
HMCamera _camera;
f32 _cameraSpeed;

View File

@ -125,7 +125,7 @@ void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector sca
* Rotates on all three axis
*/
void ApplySphericalBillBoard(Mat4 mat, FVector pos, FVector scale, s32 cameraIndex) {
Mtx* lookAt = GetLookAtMatrix(cameraIndex);
Mtx* lookAt = cameras[cameraIndex].lookAtMatrix;
Mat4 lookAtF;
guMtxL2F((float(*)[4])&lookAtF, lookAt);

View File

@ -117,6 +117,3 @@ void RaceManager::PostInit() {
OTrophy::Spawn(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH);
}
}
void RaceManager::Clean() {
}

View File

@ -38,7 +38,6 @@ public:
virtual void PreInit();
virtual void BeginPlay();
virtual void PostInit();
virtual void Clean();
protected:
World& WorldContext;
};

View File

@ -8,7 +8,7 @@ extern "C" {
#include "math_util_2.h"
}
StaticMeshActor::StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision) : Name(name), Pos(pos), Rot(rot), Scale(scale), Model(""), Collision(collision) {
StaticMeshActor::StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision) : Name(name), Pos(pos), Rot(rot), Scale(scale), Model(""), CollisionMesh(collision) {
Name = "StaticMesh";
ResourceName = "hm:static_mesh";

View File

@ -14,7 +14,7 @@ public:
IRotator Rot;
FVector Scale;
std::string Model;
int32_t* Collision;
int32_t* CollisionMesh;
bool bPendingDestroy = false;
StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision);
@ -29,8 +29,8 @@ public:
j["Model"] = Model;
// If Collision is not null, serialize it
if (Collision != nullptr) {
j["Collision"] = *Collision; // Serialize the value that Collision points to
if (CollisionMesh != nullptr) {
j["Collision"] = *CollisionMesh; // Serialize the value that Collision points to
} else {
j["Collision"] = nullptr; // Handle the case where Collision is nullptr
}
@ -53,7 +53,7 @@ public:
// Collision = new int32_t(j.at("Collision").get<int32_t>());
//} else {
// If Collision is not present or is null, set it to nullptr
Collision = nullptr;
CollisionMesh = nullptr;
//}
}

View File

@ -17,10 +17,16 @@ extern "C" {
#include "defines.h"
#include "audio/external.h"
#include "menus.h"
#include "code_800029B0.h"
#include "assets/models/common_data.h"
#include "assets/models/tracks/mario_raceway/mario_raceway_data.h"
}
#include "engine/cameras/GameCamera.h"
#include "engine/cameras/FreeCamera.h"
#include "engine/cameras/TourCamera.h"
#include "engine/cameras/LookBehindCamera.h"
std::shared_ptr<Course> CurrentCourse;
Cup* CurrentCup;
@ -29,7 +35,7 @@ World::World() {
}
World::~World() {
ClearWorld();
CleanWorld();
}
std::shared_ptr<Course> World::AddCourse(std::shared_ptr<Course> course) {
@ -137,6 +143,24 @@ void World::PreviousCourse() {
gWorldInstance.SetCurrentCourse(Courses[CourseIndex]);
}
void World::TickCameras() {
for (size_t i = 0; i < 4; i++) {
struct UnkStruct_800DC5EC* screen = &D_8015F480[i];
if (NULL == screen->pendingCamera) { continue; }
if (screen->pendingCamera != screen->camera) {
screen->camera = screen->pendingCamera;
screen->pendingCamera = nullptr;
}
}
for (GameCamera* camera : Cameras) {
if (camera->IsActive()) {
camera->Tick();
}
}
}
AActor* World::AddActor(AActor* actor) {
Actors.push_back(actor);
actor->BeginPlay();
@ -196,7 +220,7 @@ StaticMeshActor* World::AddStaticMeshActor(std::string name, FVector pos, IRotat
}
void World::DrawStaticMeshActors() {
for (const auto& actor: StaticMeshActors) {
for (const auto& actor : StaticMeshActors) {
actor->Draw();
}
}
@ -266,7 +290,7 @@ Object* World::GetObjectByIndex(size_t index) {
}
// Deletes all objects from the world
void World::ClearWorld(void) {
void World::CleanWorld(void) {
printf("[Game.cpp] Clean World\n");
World* world = &gWorldInstance;
for (auto& actor : world->Actors) {
@ -297,7 +321,4 @@ void World::ClearWorld(void) {
gWorldInstance.Objects.clear();
gWorldInstance.Emitters.clear();
gWorldInstance.Lakitus.clear();
gWorldInstance.GetRaceManager().Clean();
}

View File

@ -1,8 +1,10 @@
#pragma once
#include <libultraship.h>
#include "CoreMath.h"
#include "engine/courses/Course.h"
#include "engine/cameras/GameCamera.h"
#include "objects/Object.h"
#include "Cup.h"
#include "PlayerBombKart.h"
@ -26,6 +28,7 @@ extern "C" {
class Cup; // <-- Forward declaration
class OObject;
class GameCamera;
class Course;
class StaticMeshActor;
class OBombKart;
@ -61,6 +64,8 @@ public:
std::shared_ptr<Course> AddCourse(std::shared_ptr<Course> course);
void TickCameras();
AActor* AddActor(AActor* actor);
struct Actor* AddBaseActor();
void ActorBeginPlay(Actor* actor);
@ -98,7 +103,7 @@ public:
void SetCourseFromCup();
World* GetWorld(void);
void ClearWorld(void);
void CleanWorld(void);
// getter/setter for current course
std::shared_ptr<Course> GetCurrentCourse() {
@ -127,6 +132,8 @@ public:
std::vector<Cup*> Cups;
size_t CupIndex = 1;
std::vector<GameCamera*> Cameras;
std::vector<StaticMeshActor*> StaticMeshActors;
std::vector<AActor*> Actors;
std::vector<OObject*> Objects;

View File

@ -157,7 +157,7 @@ void AFallingRock::Draw(Camera* camera) {
return;
}
height = is_within_render_distance(camera->pos, Pos, camera->rot[1], 400.0f, gCameraZoom[camera - camera1],
height = is_within_render_distance(camera->pos, Pos, camera->rot[1], 400.0f, gCameraFOV[camera - camera1],
4000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {

View File

@ -14,7 +14,6 @@ extern "C" {
}
AMarioSign::AMarioSign(const SpawnParams& params) : AActor(params) {
Type = ACTOR_MARIO_SIGN;
Name = "Mario Sign";
ResourceName = "mk:mario_sign";
Model = d_course_mario_raceway_dl_sign;
@ -68,7 +67,7 @@ void AMarioSign::Draw(Camera *camera) {
return;
}
unk = is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 16000000.0f);
unk = is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 16000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
unk = MAX(unk, 0.0f);
}

View File

@ -182,7 +182,7 @@ void AText::Draw(Camera* camera) {
}
f32 distance = is_within_render_distance(camera->pos, (float*)&Pos[0], camera->rot[1], Close,
gCameraZoom[camera - camera1], Far);
gCameraFOV[camera - camera1], Far);
if (distance == -1.0f) {
Dist = DistanceProps::TOO_FAR;
@ -372,6 +372,7 @@ void AText::DrawText3D(Camera* camera) { // Based on func_80095BD0
gSPDisplayList(gDisplayListHead++, (Gfx*)D_02007818);
break;
}
//printf("tex texture %p width %d height %d mode %d col %f\n", tex.Texture, tex.width, tex.height, tex.mode, tex.column);
gDPLoadTextureTile_4b(gDisplayListHead++, (Gfx*)tex.Texture, G_IM_FMT_I, tex.width, 0, 0, 0, tex.width, tex.height + 2, 0,
G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,

View File

@ -119,7 +119,6 @@ public:
void FollowPlayer();
void SetText(std::string text);
std::string ValidateString(const std::string_view& text);
void Refresh();
void Print3D(char* text, s32 tracking, s32 mode);

View File

@ -38,7 +38,7 @@ void ATree::Draw(Camera* camera) {
return;
}
dist = is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraZoom[camera - camera1],
dist = is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraFOV[camera - camera1],
DrawDistance);
if (CVarGetInteger("gNoCulling", 0) == 1) {

View File

@ -47,7 +47,7 @@ void AWarioSign::Tick() {
void AWarioSign::Draw(Camera *camera) {
Mat4 sp38;
f32 unk =
is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraZoom[camera - camera1], 16000000.0f);
is_within_render_distance(camera->pos, Pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 16000000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
unk = MAX(unk, 0.0f);

View File

@ -0,0 +1,76 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include "FreeCamera.h"
#include "port/interpolation/FrameInterpolation.h"
#include "engine/Matrix.h"
#include "port/Game.h"
#include "src/enhancements/freecam/freecam.h"
extern "C" {
#include "main.h"
#include "code_800029B0.h"
#include "camera.h"
#include "code_80057C60.h"
#include "defines.h"
}
FreeCamera::FreeCamera(FVector pos, s16 rot, u32 mode) : GameCamera() {
_camera->renderMode = RENDER_FULL_SCENE;
ProjMode = ProjectionMode::PERSPECTIVE;
Vec3f spawn = {pos.x, pos.y, pos.z};
freecam_init(spawn, rot, mode, _camera->cameraId);
bActive = false;
}
void FreeCamera::SetActive(bool state) {
bActive = state;
if (state) {
gIsHUDVisible = false;
// gPlayerOne->type |= PLAYER_CPU;
} else {
gIsHUDVisible = true;
gPlayerOne->type &= ~PLAYER_CPU;
}
}
void FreeCamera::Tick() {
if (!bActive) { return; }
if (nullptr == _camera) {
bActive = false;
return;
}
freecam_loop(_camera);
}
void FreeCamera::SetViewProjection() {
u16 perspNorm;
Mat4 matrix;
Mat4 persp;
Mat4 lookAt;
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH);
gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK | G_CULL_BOTH | G_CULL_FRONT);
// Perspective (camera movement)
FrameInterpolation_RecordOpenChild("freecam_persp", FrameInterpolation_GetCameraEpoch());
guPerspective(&PerspectiveMatrix, &perspNorm, 40, gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, &PerspectiveMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
// LookAt (camera rotation)
FrameInterpolation_RecordOpenChild("freecam_lookAt", FrameInterpolation_GetCameraEpoch());
guLookAt(&LookAtMatrix,
_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++, &LookAtMatrix, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
gDPPipeSync(gDisplayListHead++);
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <libultraship.h>
#include "GameCamera.h"
extern "C" {
#include "camera.h"
}
class FreeCamera : public GameCamera {
public:
FreeCamera(FVector pos, s16 rot, u32 mode);
virtual void Tick() override;
virtual void SetViewProjection() override;
virtual void SetActive(bool state) override;
};

View File

@ -0,0 +1,104 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include "GameCamera.h"
#include "port/interpolation/FrameInterpolation.h"
#include "engine/Matrix.h"
#include "port/Game.h"
extern "C" {
#include "main.h"
#include "code_800029B0.h"
#include "camera.h"
}
size_t GameCamera::_count = 0;
GameCamera::GameCamera() {
_camera = &cameras[_count];
_camera->cameraId = _count;
_camera->perspectiveMatrix = &PerspectiveMatrix;
_camera->lookAtMatrix = &LookAtMatrix;
_count += 1;
}
GameCamera::GameCamera(FVector pos, s16 rot, u32 mode) {
_camera = &cameras[_count];
_camera->cameraId = _count;
_camera->perspectiveMatrix = &PerspectiveMatrix;
_camera->lookAtMatrix = &LookAtMatrix;
switch(gGamestate) {
case RACING:
_camera->renderMode = RENDER_TRACK_SECTIONS;
break;
case ENDING:
case CREDITS_SEQUENCE:
_camera->renderMode = RENDER_FULL_SCENE;
break;
}
ProjMode = ProjectionMode::PERSPECTIVE;
bActive = true;
if (gGamestate != CREDITS_SEQUENCE) {
Vec3f spawn = {pos.x, pos.y, pos.z};
camera_init(spawn, rot, mode, _camera->cameraId);
}
_count += 1;
}
void GameCamera::Tick() {
if (!bActive) { return; }
if (nullptr == _camera) {
bActive = false;
return;
}
func_8001EE98(&gPlayers[_camera->playerId], _camera, _camera->cameraId);
}
void GameCamera::SetActive(bool state) {
bActive = state;
}
bool GameCamera::IsActive() {
return bActive;
}
Camera* GameCamera::Get() {
return _camera;
}
void GameCamera::SetProjectionMode(GameCamera::ProjectionMode mode) {
ProjMode = mode;
}
Mtx* GameCamera::GetPerspMatrix() {
return &PerspectiveMatrix;
}
Mtx* GameCamera::GetLookAtMatrix() {
return &LookAtMatrix;
}
void GameCamera::SetViewProjection() {
u16 perspNorm;
// Tag the camera for the interpolation engine
FrameInterpolation_RecordOpenChild("camera",
(FrameInterpolation_GetCameraEpoch() | ((_camera->cameraId << 8))));
// Calculate camera perspective (camera movement/location)
guPerspective(&PerspectiveMatrix, &perspNorm, gCameraFOV[_camera->cameraId], gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, &PerspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
// Calculate the camera lookAt (camera rotation)
guLookAt(&LookAtMatrix, _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++, &LookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <libultraship.h>
#include "CoreMath.h"
extern "C" {
#include "camera.h"
}
class GameCamera {
public:
GameCamera();
GameCamera(FVector spawn, s16 rot, u32 mode);
~GameCamera() {
_count--;
}
enum class ProjectionMode {
PERSPECTIVE,
ORTHOGRAPHIC
};
ProjectionMode ProjMode;
virtual void Tick();
virtual void SetViewProjection();
virtual void SetActive(bool state);
void SetProjectionMode(GameCamera::ProjectionMode mode);
bool IsActive();
Camera* Get();
Mtx* GetPerspMatrix();
Mtx* GetLookAtMatrix();
protected:
Mtx PerspectiveMatrix;
Mtx LookAtMatrix;
bool bActive;
Camera* _camera;
static size_t _count;
};

View File

@ -0,0 +1,41 @@
#include <libultraship.h>
#include <libultra/gbi.h>
#include "LookBehindCamera.h"
#include "port/interpolation/FrameInterpolation.h"
#include "engine/Matrix.h"
#include "port/Game.h"
#include "src/enhancements/freecam/freecam.h"
extern "C" {
#include "main.h"
#include "code_800029B0.h"
#include "camera.h"
#include "code_80057C60.h"
#include "defines.h"
}
LookBehindCamera::LookBehindCamera(FVector pos, s16 rot, u32 mode) : GameCamera() {
_camera->renderMode = RENDER_TRACK_SECTIONS;
ProjMode = ProjectionMode::PERSPECTIVE;
bActive = true;
// Look behind
Vec3f spawn = {pos.x, pos.y, pos.z};
camera_init(spawn, rot, mode, _camera->cameraId);
// Flip camera to look backwards
_camera->unk_30[2] = -_camera->unk_30[2];
_camera->unk_3C[2] = -_camera->unk_3C[2];
}
void LookBehindCamera::Tick() {
if (!bActive) { return; }
if (nullptr == _camera) {
bActive = false;
return;
}
func_8001EE98(&gPlayers[_camera->playerId], _camera, _camera->cameraId);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <libultraship.h>
#include "GameCamera.h"
extern "C" {
#include "camera.h"
}
class LookBehindCamera : public GameCamera {
public:
LookBehindCamera(FVector pos, s16 rot, u32 mode);
virtual void Tick() override;
};

View File

@ -0,0 +1,222 @@
#include <libultraship/libultraship.h>
#include "TourCamera.h"
#include "port/Engine.h"
#include "port/Game.h"
#include "port/interpolation/FrameInterpolation.h"
#include "engine/Matrix.h"
#include "engine/World.h"
#include "port/audio/HMAS.h"
extern "C" {
#include "main.h"
#include "camera.h"
#include "code_800029B0.h"
#include "ceremony_and_credits.h"
#include "common_structs.h"
#include "spawn_players.h"
#include "math_util.h"
#include "external.h"
}
TourCamera::TourCamera(FVector pos, s16 rot, u32 mode) : GameCamera() {
_camera->renderMode = RENDER_FULL_SCENE;
ProjMode = ProjectionMode::PERSPECTIVE;
Vec3f spawn = {pos.x, pos.y, pos.z};
freecam_init(spawn, rot, mode, _camera->cameraId);
Type = TOUR_TYPE::SEQUENTIAL;
ShotIndex = 0;
KeyFrameIndex = 0;
KeyFrameProgress = 0;
bShotComplete = false;
bTourComplete = false;
bActive = false;
bActivateAudio = true;
Alpha = 0;
}
void TourCamera::Reset() {
Type = TOUR_TYPE::SEQUENTIAL;
KeyFrameIndex = 0;
KeyFrameProgress = 0.0f;
bShotComplete = false;
}
void TourCamera::NextShot() {
TourCamera::Reset();
bShotComplete = false;
_camera->pos[0] = gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].Pos.x;
_camera->pos[1] = gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].Pos.y;
_camera->pos[2] = gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].Pos.z;
_camera->lookAt[0] = gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].LookAt.x;
_camera->lookAt[1] = gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].LookAt.y;
_camera->lookAt[2] = gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].LookAt.z;
}
void TourCamera::Stop() {
printf("[TourCamera] End of Track Tour\n");
gTourComplete = true;
CM_ResetAudio();
D_8015F480[0].pendingCamera = &cameras[0];
bActive = false;
bTourComplete = true;
CM_CameraSetActive(0, true);
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = RACING;
if(HMAS_IsPlaying(HMAS_MUSIC)) {
HMAS_Stop(HMAS_MUSIC);
}
}
void TourCamera::Tick() {
if (!bActive) { return; }
if (
(nullptr == _camera) ||
(bTourComplete) ||
(ShotIndex >= gWorldInstance.GetCurrentCourse()->TourShots.size())
) {
Alpha += 5;
if (Alpha == 255) {
TourCamera::Stop();
}
return;
}
f32 extraArg; // Calculates camera up. Likely for preventing some camera flip related issues
if (bShotComplete) {
switch(Type) {
case TOUR_TYPE::SEQUENTIAL:
TourCamera::NextShot();
break;
case TOUR_TYPE::RANDOM:
break;
case TOUR_TYPE::LOOP:
break;
}
}
if (bActivateAudio) {
bActivateAudio = false;
enum MusicSeq sequence = CM_GetProps()->Sequence;
if (sequence != MUSIC_SEQ_UNKNOWN) {
play_sequence(sequence);
}
}
bool done = TourCamera::MoveCameraAlongSpline(&extraArg, gWorldInstance.GetCurrentCourse()->TourShots[ShotIndex].Frames);
// Advance to the next camera shot
if (done) {
ShotIndex += 1;
}
//printf("cam %f %f %f prog %f idx %d\n", camera->pos[0], camera->pos[1], camera->pos[2], Progress, KeyFrameIndex);
bShotComplete = done;
// This is required for actors billboarding to work.
_camera->rot[1] = atan2s(_camera->lookAt[0] - _camera->pos[0], _camera->lookAt[2] - _camera->pos[2]);
}
bool TourCamera::MoveCameraAlongSpline(f32* arg1, std::vector<KeyFrame>& keyFrame) {
bool finished = false;
Mat4 matrix;
Mat4 lookAtMatrix;
s32 i = 0;
f32 u = KeyFrameProgress;
f32 progressChange;
f32 firstSpeed = 0;
f32 secondSpeed = 0;
s32 keyFrameIdx = KeyFrameIndex;
f32 unk = 1.0f;
if (KeyFrameIndex < 0) {
u = 0;
}
// Check for end of the spline
if ( (keyFrameIdx + 3) >= keyFrame.size() ) {
return true;
}
for (i = 0; i < 4; i++) {
matrix[i][0] = keyFrame[keyFrameIdx + i].Pos.x;
matrix[i][1] = keyFrame[keyFrameIdx + i].Pos.y;
matrix[i][2] = keyFrame[keyFrameIdx + i].Pos.z;
matrix[i][3] = unk * 256.0f; //spline[segment + i].unk4 * 256.0f;
lookAtMatrix[i][0] = keyFrame[keyFrameIdx + i].LookAt.x;
lookAtMatrix[i][1] = keyFrame[keyFrameIdx + i].LookAt.y;
lookAtMatrix[i][2] = keyFrame[keyFrameIdx + i].LookAt.z;
lookAtMatrix[i][3] = unk * 256.0f; //spline[segment + i].unk4 * 256.0f;
}
evaluate_cubic_spline(u, _camera->pos, arg1, matrix[0], matrix[1], matrix[2], matrix[3]);
evaluate_cubic_spline(u, _camera->lookAt, arg1, lookAtMatrix[0], lookAtMatrix[1], lookAtMatrix[2], lookAtMatrix[3]);
if (keyFrame[KeyFrameIndex + 1].Duration != 0) {
firstSpeed = 1.0f / keyFrame[KeyFrameIndex + 1].Duration;
}
if (keyFrame[KeyFrameIndex + 2].Duration != 0) {
secondSpeed = 1.0f / keyFrame[KeyFrameIndex + 2].Duration;
}
progressChange = (((secondSpeed - firstSpeed)) * KeyFrameProgress + firstSpeed);
if (1 <= (KeyFrameProgress += progressChange)) {
KeyFrameIndex++;
if ( (KeyFrameIndex + 3 ) >= keyFrame.size()) {
KeyFrameIndex = 0;
finished = true;
}
KeyFrameProgress--;
}
return finished;
}
bool TourCamera::IsTourComplete() {
return bTourComplete;
}
void TourCamera::SetViewProjection() {
u16 perspNorm;
Mat4 matrix;
Mat4 persp;
Mat4 lookAt;
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH);
gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK | G_CULL_BOTH | G_CULL_FRONT);
// Perspective (camera movement)
FrameInterpolation_RecordOpenChild("tourcam_persp", FrameInterpolation_GetCameraEpoch());
guPerspective(&PerspectiveMatrix, &perspNorm, 40, gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, &PerspectiveMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
// LookAt (camera rotation)
FrameInterpolation_RecordOpenChild("tourcam_lookAt", FrameInterpolation_GetCameraEpoch());
guLookAt(&LookAtMatrix, _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++, &LookAtMatrix, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
gDPPipeSync(gDisplayListHead++);
}
void TourCamera::Draw() {
gDPPipeSync(gDisplayListHead++);
gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetPrimColor(gDisplayListHead++, 0, 0, 0, 0, 0, Alpha);
gDPSetCombineMode(gDisplayListHead++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gDPFillWideRectangle(gDisplayListHead++, OTRGetRectDimensionFromLeftEdge(0), 0, OTRGetGameRenderWidth(), 239);
gDPPipeSync(gDisplayListHead++);
}

View File

@ -0,0 +1,64 @@
#pragma once
#include <libultraship.h>
#include "GameCamera.h"
#include "CoreMath.h"
extern "C" {
#include "camera.h"
}
/**
* Tour: A cutscene camera system to provide an overview of the track.
* How this works:
*
* A tour consists of a series of camera shots.
* A shot consists of a series of keyframes.
* The camera is smoothly translated between keyframes using a cubic spline algorithm.
*
*/
class TourCamera : public GameCamera {
public:
enum class TOUR_TYPE {
SEQUENTIAL = 0,
RANDOM,
LOOP
};
// State for the track's introductory camera sequence
TOUR_TYPE Type;
size_t ShotIndex;
size_t KeyFrameIndex;
f32 KeyFrameProgress; // The progress from one point to the next (0.0 - 1.0f).
bool bShotComplete; // Is the current shot complete?
bool bTourComplete; // Is the whole camera sequence complete?
bool bActivateAudio;
uint8_t Alpha;
// A single camera keyframe.
// The camera is smoothly translated between keyframes using
// a cubic spline algorithm.
struct KeyFrame {
FVector Pos;
FVector LookAt;
f32 Duration;
};
// A sequence of keyframes that make up a cutscene shot.
struct CameraShot {
FVector Pos; // Start pos
FVector LookAt; // Start lookat
std::vector<KeyFrame> Frames;
};
TourCamera(FVector pos, s16 rot, u32 mode);
virtual void Tick() override;
virtual void SetViewProjection() override;
void NextShot();
void Reset();
void Stop();
bool IsTourComplete();
bool MoveCameraAlongSpline(f32* arg1, std::vector<KeyFrame>& keyFrame);
void Draw();
};

View File

@ -9,6 +9,7 @@
#include <optional>
#include <nlohmann/json.hpp>
#include "engine/objects/Lakitu.h"
#include "engine/cameras/TourCamera.h"
#include "port/resource/type/TrackSections.h"
extern "C" {
#endif
@ -318,6 +319,10 @@ public:
bool bIsMod = false;
std::vector<SpawnParams> SpawnList;
bool bTourEnabled = false;
std::vector<TourCamera::CameraShot> TourShots;
virtual ~Course() = default;
explicit Course();

View File

@ -62,7 +62,7 @@ FVector ScreenRayTrace() {
Mat4 perspMtx;
u16 perspNorm;
guPerspectiveF(perspMtx, &perspNorm, gCameraZoom[0], OTRGetAspectRatio(), CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
guPerspectiveF(perspMtx, &perspNorm, gCameraFOV[0], OTRGetAspectRatio(), CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
Mat4 inversePerspMtx;
if (InverseMatrix((float*)&perspMtx, (float*)&inversePerspMtx) != 2) {

View File

@ -1,4 +1,5 @@
#include "SceneManager.h"
#include "port/Game.h"
#include "engine/CoreMath.h"
#include "World.h"
@ -19,7 +20,7 @@
#include "engine/objects/Object.h"
#include "engine/objects/Thwomp.h"
#include "engine/objects/Snowman.h"
#include <iostream>
#include "engine/cameras/TourCamera.h"
extern "C" {
#include "common_structs.h"
@ -28,112 +29,98 @@ extern "C" {
}
namespace Editor {
std::shared_ptr<Ship::Archive> CurrentArchive;
std::string SceneFile = "";
void SaveLevel() {
auto props = gWorldInstance.GetCurrentCourse()->Props;
if ((!CurrentArchive) || (SceneFile.empty())) {
SPDLOG_INFO("[SceneManager] [SaveLevel] Could not save scene file, SceneFile or CurrentArchive not set");
return;
}
nlohmann::json data;
if ((CurrentArchive) && (!SceneFile.empty())) {
nlohmann::json data;
data["Props"] = props.to_json();
/**
* Save track properties, static mesh actors, actors, and tour camera
*/
data["Props"] = gWorldInstance.GetCurrentCourse()->Props.to_json();
nlohmann::json staticMesh;
nlohmann::json staticMesh;
SaveStaticMeshActors(staticMesh);
data["StaticMeshActors"] = staticMesh;
for (const auto& mesh : gWorldInstance.StaticMeshActors) {
staticMesh.push_back(mesh->to_json());
}
data["StaticMeshActors"] = staticMesh;
nlohmann::json actors;
nlohmann::json actors;
SaveActors(actors);
data["Actors"] = actors;
SaveActors(actors);
data["Actors"] = actors;
if (gWorldInstance.GetCurrentCourse()->TourShots.size() != 0) {
nlohmann::json tour;
SaveTour(tour);
data["Tour"] = tour;
}
try {
auto dat = data.dump(2);
std::vector<uint8_t> stringify;
stringify.assign(dat.begin(), dat.end());
/**
* Write data to file
*/
try {
std::string jsonStr = data.dump(2);
std::vector<uint8_t> bytes; // Turn the str into raw data
bytes.assign(jsonStr.begin(), jsonStr.end());
bool wrote = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->WriteFile(CurrentArchive, SceneFile, stringify);
if (wrote) {
// Tell the cache this needs to be reloaded
auto resource = GameEngine::Instance->context->GetResourceManager()->GetCachedResource(SceneFile);
if (resource) {
resource->Dirty();
}
} else {
printf("[SceneManager::SaveLevel] Failed to write scene file!\n");
// Write file to disk
bool wrote = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->WriteFile(CurrentArchive, SceneFile, bytes);
if (wrote) {
// Tell the cache this file needs to be reloaded
auto resource = GameEngine::Instance->context->GetResourceManager()->GetCachedResource(SceneFile);
if (resource) {
resource->Dirty();
}
} catch (const nlohmann::json::exception& e) {
printf("[SceneManager::SaveLevel]\n JSON error during dump: %s\n", e.what());
} else {
SPDLOG_INFO("[SceneManager] [SaveLevel] Failed to write scene file!");
}
} else {
printf("Could not save scene file, SceneFile or CurrentArchive not set\n");
} catch (const nlohmann::json::exception& e) {
SPDLOG_INFO("[SceneManager] [SaveLevel] JSON error during dump: {}", e.what());
}
}
/** Do not use gWorldInstance.CurrentCourse during loading! The current track is not guaranteed! **/
void LoadLevel(Course* course, std::string sceneFile) {
SceneFile = sceneFile;
if ((nullptr != course) && (nullptr != course->RootArchive)) {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = course->RootArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
initData->ResourceVersion = 0;
nlohmann::json data = std::static_pointer_cast<Ship::Json>(
GameEngine::Instance->context->GetResourceManager()->LoadResource(sceneFile, true, initData))->Data;
if (data.is_null() || data.empty()) {
return;
}
// Load the Props (deserialize it)
if (data.contains("Props")) {
auto& propsJson = data["Props"];
try {
course->Props.from_json(propsJson);
} catch(const std::exception& e) {
std::cerr << "SceneManager::LoadLevel() Error parsing track properties: " << e.what() << std::endl;
std::cerr << " Is your scene.json file out of date?" << std::endl;
}
} else {
std::cerr << "Props data not found in the JSON file!" << std::endl;
}
/** Populate Track SpawnParams for spawning actors **/
if (data.contains("Actors")) {
auto & actorsJson = data["Actors"];
course->SpawnList.clear();
for (const auto& actor : actorsJson) {
SpawnParams params;
params.from_json(actor); //<SpawnParams>();
if (!params.Name.empty()) {
course->SpawnList.push_back(params);
}
}
SPDLOG_INFO("[SceneManager] Loaded Scene File!");
}
// Load the Actors (deserialize them)
if (data.contains("StaticMeshActors")) {
auto& actorsJson = data["StaticMeshActors"];
gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any
for (const auto& actorJson : actorsJson) {
Load_AddStaticMeshActor(actorJson);
}
} else {
SPDLOG_INFO("[SceneManager::LoadLevel] [scene.json] This track contains no StaticMeshActors!");
}
if ((nullptr == course) || (nullptr == course->RootArchive)) {
SPDLOG_INFO("[SceneManager] [LoadLevel] Failed to load scenefile, course or rootarchive were null");
return;
}
/*
* Manually loading a custom asset file (scene.json) with no extractor class means that
* the init data needs to be manually populated
*/
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = course->RootArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
initData->ResourceVersion = 0;
// Load the scene file and return the json data
nlohmann::json data = std::static_pointer_cast<Ship::Json>(
GameEngine::Instance->context->GetResourceManager()->LoadResource(sceneFile, true, initData))->Data;
// Check that the data is valid
if (data.is_null() || !data.is_object() || data.empty()) {
SPDLOG_INFO("[SceneManager] [LoadLevel] Scenefile corrupted or contained no data");
return;
}
SPDLOG_INFO("[SceneManager] [LoadLevel] Loading track scenefile...");
// Load the Props, and populate actors
LoadProps(course, data);
LoadActors(course, data);
LoadStaticMeshActors(course, data);
LoadTour(course, data);
SPDLOG_INFO("[SceneManager] [LoadLevel] Scene File Loaded!");
}
void Load_AddStaticMeshActor(const nlohmann::json& actorJson) {
@ -150,31 +137,46 @@ namespace Editor {
SceneFile = sceneFile;
}
// Called from ContentBrowser.cpp
void LoadMinimap(Course* course, std::string filePath) {
printf("LOADING MINIMAP %s\n", filePath.c_str());
if ((nullptr != course) && (nullptr != course->RootArchive)) {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = course->RootArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(MK64::ResourceType::Minimap);
initData->ResourceVersion = 0;
std::shared_ptr<MK64::Minimap> ptr = std::static_pointer_cast<MK64::Minimap>(
GameEngine::Instance->context->GetResourceManager()->LoadResource(filePath, true, initData));
if (ptr) {
printf("LOADED MINIMAP!\n");
MK64::MinimapTexture texture = ptr->Texture;
course->Props.Minimap.Texture = (const char*)texture.Data;
course->Props.Minimap.Width = texture.Width;
course->Props.Minimap.Height = texture.Height;
} else { // Fallback
course->Props.Minimap.Texture = minimap_mario_raceway;
course->Props.Minimap.Width = ResourceGetTexWidthByName(course->Props.Minimap.Texture);
course->Props.Minimap.Height = ResourceGetTexHeightByName(course->Props.Minimap.Texture);
}
SPDLOG_INFO(" Loading {} minimap...", filePath);
if (nullptr == course->RootArchive) {
SPDLOG_INFO("[SceneManager] [LoadMinimap] Root archive is nullptr");
SetDefaultMinimap(course);
return;
}
/*
* Manually loading a custom asset file with no extractor class means that
* the init data needs to be manually populated
*/
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = course->RootArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(MK64::ResourceType::Minimap);
initData->ResourceVersion = 0;
std::shared_ptr<MK64::Minimap> ptr = std::static_pointer_cast<MK64::Minimap>(
GameEngine::Instance->context->GetResourceManager()->LoadResource(filePath, true, initData));
if (ptr) {
SPDLOG_INFO(" Minimap Loaded!");
MK64::MinimapTexture texture = ptr->Texture;
course->Props.Minimap.Texture = (const char*)texture.Data;
course->Props.Minimap.Width = texture.Width;
course->Props.Minimap.Height = texture.Height;
} else { // Fallback
SetDefaultMinimap(course);
}
}
// Sets the default minimap if none has been set
void SetDefaultMinimap(Course* course) {
course->Props.Minimap.Texture = minimap_mario_raceway;
course->Props.Minimap.Width = ResourceGetTexWidthByName(course->Props.Minimap.Texture);
course->Props.Minimap.Height = ResourceGetTexHeightByName(course->Props.Minimap.Texture);
SPDLOG_INFO(" No minimap found! Falling back to default minimap");
}
void SaveActors(nlohmann::json& actorList) {
@ -243,4 +245,89 @@ namespace Editor {
}
}
}
void SaveStaticMeshActors(nlohmann::json& actorList) {
for (const auto& mesh : gWorldInstance.StaticMeshActors) {
actorList.push_back(mesh->to_json());
}
}
void SaveTour(nlohmann::json& tour) {
tour["Enabled"] = gWorldInstance.GetCurrentCourse()->bTourEnabled;
// Camera shots
tour["Shots"] = nlohmann::json::array();
for (const auto& shot : gWorldInstance.GetCurrentCourse()->TourShots) {
tour["Shots"].push_back(ToJson(shot));
}
}
void LoadProps(Course* course, nlohmann::json& data) {
if (!data.contains("Props") || !data["Props"].is_object()) {
SPDLOG_INFO("Track is missing props data. Is the scene.json file corrupt?");
return;
}
try {
course->Props.from_json(data["Props"]);
} catch(const std::exception& e) {
std::cerr << " Error parsing track properties: " << e.what() << std::endl;
std::cerr << " Is your scene.json file out of date?" << std::endl;
}
}
void LoadActors(Course* course, nlohmann::json& data) {
if (!data.contains("Actors") || !data["Actors"].is_object()) {
SPDLOG_INFO(" This track contains no actors");
return;
}
course->SpawnList.clear(); // Clear existing actors, if any
for (const auto& actor : data["Actors"]) {
SpawnParams params;
params.from_json(actor); //<SpawnParams>();
if (!params.Name.empty()) {
course->SpawnList.push_back(params);
}
}
}
void LoadStaticMeshActors(Course* course, nlohmann::json& data) {
if (!data.contains("StaticMeshActors") || !data["StaticMeshActors"].is_object()) {
SPDLOG_INFO(" This track contains no StaticMeshActors!");
return;
}
gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any
for (const auto& actorJson : data["StaticMeshActors"]) {
Load_AddStaticMeshActor(actorJson);
}
}
void LoadTour(Course* course, nlohmann::json& data) {
if (!data.contains("Tour") || !data["Tour"].is_object()) {
SPDLOG_INFO(" This track does not contain a camera tour");
return;
}
nlohmann::json& tours = data["Tour"];
// Enable flag
if (tours.contains("Enabled")) {
course->bTourEnabled = tours["Enabled"].get<bool>();
} else {
course->bTourEnabled = false;
}
// Camera shots
if (tours.contains("Shots") && tours["Shots"].is_array()) {
course->TourShots.clear();
for (const auto& shotJson : tours["Shots"]) {
course->TourShots.push_back(FromJsonCameraShot(shotJson));
}
}
}
}

View File

@ -12,10 +12,81 @@ namespace Editor {
void Load_AddStaticMeshActor(const nlohmann::json& actorJson);
void SetSceneFile(std::shared_ptr<Ship::Archive> archive, std::string sceneFile);
void LoadMinimap(Course* course, std::string filePath);
void SetDefaultMinimap(Course* course);
void SaveActors(nlohmann::json& actorList);
void SaveStaticMeshActors(nlohmann::json& actorList);
void SaveTour(nlohmann::json& tour);
void LoadProps(Course* course, nlohmann::json& data);
void LoadActors(Course* course, nlohmann::json& data);
void LoadStaticMeshActors(Course* course, nlohmann::json& data);
void LoadTour(Course* course, nlohmann::json& data);
void SpawnActors(std::vector<std::pair<std::string, SpawnParams>> spawnList);
extern std::shared_ptr<Ship::Archive> CurrentArchive; // This is used to retrieve and write the scene data file
extern std::string SceneFile;
inline nlohmann::json ToJson(const FVector& v) {
return {
{"x", v.x},
{"y", v.y},
{"z", v.z}
};
}
inline nlohmann::json ToJson(const TourCamera::KeyFrame& kf) {
return {
{"Pos", ToJson(kf.Pos)},
{"LookAt", ToJson(kf.LookAt)},
{"Duration", kf.Duration}
};
}
inline nlohmann::json ToJson(const TourCamera::CameraShot& shot) {
nlohmann::json j;
j["StartPos"] = ToJson(shot.Pos);
j["StartLookAt"] = ToJson(shot.LookAt);
// KeyFrames
nlohmann::json keyframes = nlohmann::json::array();
for (const auto& kf : shot.Frames) {
keyframes.push_back(ToJson(kf));
}
j["KeyFrames"] = keyframes;
return j;
}
inline FVector FromJsonVec(const nlohmann::json& j) {
FVector v{};
if (j.contains("x")) v.x = j["x"].get<float>();
if (j.contains("y")) v.y = j["y"].get<float>();
if (j.contains("z")) v.z = j["z"].get<float>();
return v;
}
inline TourCamera::KeyFrame FromJsonKeyFrame(const nlohmann::json& j) {
TourCamera::KeyFrame kf{};
if (j.contains("Pos")) kf.Pos = FromJsonVec(j["Pos"]);
if (j.contains("LookAt")) kf.LookAt = FromJsonVec(j["LookAt"]);
if (j.contains("Duration")) kf.Duration = j["Duration"].get<float>();
return kf;
}
inline TourCamera::CameraShot FromJsonCameraShot(const nlohmann::json& j) {
TourCamera::CameraShot shot{};
if (j.contains("StartPos")) shot.Pos = FromJsonVec(j["StartPos"]);
if (j.contains("StartLookAt")) shot.LookAt = FromJsonVec(j["StartLookAt"]);
if (j.contains("KeyFrames") && j["KeyFrames"].is_array()) {
for (const auto& kfJson : j["KeyFrames"]) {
shot.Frames.push_back(FromJsonKeyFrame(kfJson));
}
}
return shot;
}
}

View File

@ -41,6 +41,7 @@ public:
}
explicit OCrab(const SpawnParams& params);
~OCrab() {
_count--;
}

View File

@ -99,7 +99,14 @@ void OLakitu::Draw(s32 cameraId) {
FrameInterpolation_RecordOpenChild("Lakitu", (uintptr_t) this);
objectIndex = gIndexLakituList[cameraId];
//! @warning This usage may be problematic
if (cameras[cameraId].playerId >= 4) {
printf("[Lakitu.cpp] Preventing out of bounds access in gIndexLakituList\n", cameras[cameraId].playerId);
throw std::runtime_error("Good bye!");
return;
}
objectIndex = gIndexLakituList[cameras[cameraId].playerId];
camera = &camera1[cameraId];
if (is_obj_flag_status_active(objectIndex, 0x00000010) != 0) {
object = &gObjectList[objectIndex];

View File

@ -231,14 +231,10 @@ void OTrophy::Draw(s32 cameraId) {
if (*_toggleVisibility == true) {
object = &gObjectList[listIndex];
if (object->state >= 2) {
// Prevents a perspective glitch
if (CVarGetInteger("gFreecam", 0) == true) {
cameraId = CAMERA_FREECAM;
}
gSPMatrix(gDisplayListHead++, GetPerspMatrix(cameraId),
gSPMatrix(gDisplayListHead++, cameras[cameraId].perspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(cameraId),
gSPMatrix(gDisplayListHead++, cameras[cameraId].lookAtMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
mtxf_set_matrix_transformation(someMatrix1, object->pos, object->direction_angle, object->sizeScaling);
//convert_to_fixed_point_matrix(&gGfxPool->mtxHud[gMatrixHudCount], someMatrix1);
@ -249,8 +245,10 @@ void OTrophy::Draw(s32 cameraId) {
gSPDisplayList(gDisplayListHead++, (Gfx*)D_0D0077A0);
gSPDisplayList(gDisplayListHead++, object->model);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(cameraId),
gSPMatrix(gDisplayListHead++, cameras[cameraId].lookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
mtxf_identity(someMatrix2);
render_set_position(someMatrix2, 0);
}

View File

@ -67,6 +67,8 @@ u32 bFreecamUseController = false;
* Camera mode 2: Enter freecam at previous freecam spot
*
*/
// This function is no longer used because FreeCamera.cpp
void freecam(Camera* camera, Player* player, s8 index) {
f32 dirX;
f32 dirY;
@ -81,7 +83,7 @@ void freecam(Camera* camera, Player* player, s8 index) {
freecamEnabled = false;
CVarSetInteger("gFreecam", false);
}
if (freecamEnabled && !enabled) {
enabled = true; // Mark that freecam was activated
on_freecam();
@ -92,11 +94,11 @@ void freecam(Camera* camera, Player* player, s8 index) {
// Freecam mode is enabled
if (enabled && (player == gPlayerOne)) {
freecam_loop(camera, player, index);
freecam_loop(camera);
} else {
func_8001E45C(camera, player, index);
// func_8001E45C(camera, player, index);
// Required if freecam were to use its own camera instead of borrowing the player camera
//func_8001EE98(gPlayerOne, camera, index);
// func_8001EE98(gPlayerOne, camera, index);
}
}
@ -110,7 +112,7 @@ void off_freecam(void) {
gPlayerOne->type &= ~PLAYER_CPU;
}
void freecam_loop(Camera* camera, Player* player, s8 index) {
void freecam_loop(Camera* camera) {
if ((fController.buttonPressed & L_TRIG) && (fController.buttonPressed & R_TRIG)) {
// Toggle freecam
CVarSetInteger("gFreecam", !CVarGetInteger("gFreecam", 0));
@ -129,7 +131,11 @@ void freecam_loop(Camera* camera, Player* player, s8 index) {
freecam_keyboard_manager(camera, freeCam.forwardVector);
// Apply final position, velocity, and lookAt
//if (0) {
//Tour_Tick(camera);
//} else {
freecam_tick(camera, freeCam.forwardVector);
//}
}
void freecam_mouse_manager(Camera* camera, Vec3f forwardVector) {
@ -377,6 +383,7 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) {
if (Down) {
totalMove[1] -= moveSpeed; // Move down
}
freeCam.velocity[0] += totalMove[0];
freeCam.velocity[1] += totalMove[1];
freeCam.velocity[2] += totalMove[2];
@ -399,31 +406,3 @@ 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(Camera* camera) {
u16 perspNorm;
Mat4 matrix;
Mat4 persp;
Mat4 lookAt;
gSPSetGeometryMode(gDisplayListHead++, G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH);
gSPClearGeometryMode(gDisplayListHead++, G_CULL_BACK | G_CULL_BOTH | G_CULL_FRONT);
// Perspective (camera movement)
FrameInterpolation_RecordOpenChild("freecam_persp", FrameInterpolation_GetCameraEpoch());
guPerspective(GetPerspMatrix(4), &perspNorm, gCameraZoom[0], gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(4), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
// LookAt (camera rotation)
FrameInterpolation_RecordOpenChild("freecam_lookAt", FrameInterpolation_GetCameraEpoch());
guLookAt(GetLookAtMatrix(4), 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++, GetLookAtMatrix(4), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
gDPPipeSync(gDisplayListHead++);
}

View File

@ -11,9 +11,8 @@ extern "C" {
void freecam(Camera*, Player*, s8);
void on_freecam(void);
void off_freecam(void);
void freecam_loop(Camera*, Player*, s8);
void freecam_loop(Camera*);
void freecam_update_controller(void);
void freecam_render_setup(Camera* camera);
void freecam_mouse_manager(Camera*, Vec3f);
void freecam_keyboard_manager(Camera*, Vec3f);

View File

@ -123,7 +123,7 @@ s32 D_80150120;
s32 gGotoMode;
UNUSED s32 D_80150128;
UNUSED s32 D_8015012C;
f32 gCameraZoom[4]; // look like to be the fov of each character
f32 gCameraFOV[NUM_CAMERAS]; // Field-of-view for each camera
UNUSED s32 D_80150140;
UNUSED s32 D_80150144;
f32 gScreenAspect;
@ -146,7 +146,6 @@ Mat4 sBillBoardMtx; // Faces 2D actors at the camera
s32 padding[2048];
u16 D_80152300[4];
u16 D_80152308;
UNUSED OSThread paddingThread;
@ -172,7 +171,6 @@ s32 gGamestate = 0xFFFF;
// gRaceState is externed as an s32 in other files. D_800DC514 is only used in main.c, likely a developer mistake.
s32 gRaceState = RACE_INIT;
u16 D_800DC514 = 0;
u16 creditsRenderMode = 0; // Renders the whole track. Displays red if used in normal race mode.
u16 gDemoMode = DEMO_MODE_INACTIVE;
u16 gEnableDebugMode = DEBUG_MODE;
s32 gGamestateNext = 7; // = COURSE_DATA_MENU?;
@ -181,6 +179,7 @@ s32 gActiveScreenMode = SCREEN_MODE_1P;
s32 gScreenModeSelection = SCREEN_MODE_1P;
UNUSED s32 D_800DC534 = 0;
s32 gPlayerCountSelection1 = 2;
bool gTourComplete = false;
s32 gModeSelection = GRAND_PRIX;
s32 D_800DC540 = 0;
@ -681,48 +680,23 @@ void process_game_tick(void) {
handle_a_press_for_all_players_during_race();
}
// tick camera
// This looks like it should be in the switch below.
// But it needs to be here for player 1 to work in all modes.
if (CVarGetInteger("gFreecam", 0) == true) {
freecam(gFreecamCamera, gPlayerOne, 0);
} else {
func_8001EE98(gPlayerOne, camera1, 0);
}
CM_TickCameras();
// Editor requires this so the camera keeps moving while the game is paused.
if (gIsEditorPaused == true) {
return;
}
switch(gActiveScreenMode) {
case SCREEN_MODE_1P:
func_80028F70();
break;
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
func_80029060();
func_8001EE98(gPlayerTwo, camera2, 1);
func_80029150();
break;
case SCREEN_MODE_3P_4P_SPLITSCREEN:
func_80029158();
func_8001EE98(gPlayerTwo, camera2, 1);
func_800291E8();
func_8001EE98(gPlayerThree, camera3, 2);
func_800291F0();
func_8001EE98(gPlayerFour, camera4, 3);
func_800291F8();
break;
}
func_80028F70(); // Player controller
func_8028F474();
func_80059AC8();
update_course_actors();
CM_TickActors();
func_802966A0();
func_8028FCBC();
if (CM_IsTourEnabled() == false) {
func_8028FCBC();
}
}
void race_logic_loop(void) {

View File

@ -167,7 +167,7 @@ extern u16 D_8015011E;
extern s32 D_80150120;
extern s32 gGotoMode;
extern f32 gCameraZoom[];
extern f32 gCameraFOV[];
extern f32 gScreenAspect;
extern f32 D_8015014C;
@ -185,7 +185,6 @@ extern Mat4 sBillBoardMtx;
extern s32 padding[];
extern u16 D_80152300[];
extern u16 D_80152308;
extern OSThread gIdleThread;
@ -207,13 +206,13 @@ extern s32 gGamestate;
extern s32 gRaceState;
extern u16 D_800DC514;
extern u16 creditsRenderMode;
extern u16 gDemoMode;
extern u16 gEnableDebugMode;
extern s32 gGamestateNext;
extern s32 gActiveScreenMode;
extern s32 gScreenModeSelection;
extern s32 gPlayerCountSelection1;
extern bool gTourComplete;
extern s32 gModeSelection;
extern s32 D_800DC540;

View File

@ -1521,7 +1521,7 @@ void func_80091FA4(void) {
func_80092258();
// Do not display grand prix name/cup name in editor at race staging
if (CVarGetInteger("gEditorEnabled", 0) == false) {
if ((CVarGetInteger("gEditorEnabled", 0) == false) && (CM_IsTourEnabled() == false)) {
add_menu_item(MENU_ITEM_TYPE_096, 0x00000064, 0x00000024, MENU_ITEM_PRIORITY_1);
add_menu_item(MENU_ITEM_TYPE_097, 0x00000064, 0x000000DD, MENU_ITEM_PRIORITY_1);
add_menu_item(MENU_ITEM_TYPE_098, 0, 0, MENU_ITEM_PRIORITY_0);

View File

@ -680,54 +680,22 @@ void func_80028E70(Player* player, Camera* camera, s8 playerId, s8 screenId) {
}
}
UNUSED void func_80028F5C(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED s32 arg2, UNUSED s32 arg3) {
}
void func_80028F70(void) {
// ClearEffectsMatrixPool();
gMatrixEffectCount = 0;
func_80028E70(gPlayerOne, camera1, 0, 0);
func_80028E70(gPlayerTwo, camera1, 1, 0);
func_80028E70(gPlayerThree, camera1, 2, 0);
func_80028E70(gPlayerFour, camera1, 3, 0);
func_80028E70(gPlayerFive, camera1, 4, 0);
func_80028E70(gPlayerSix, camera1, 5, 0);
func_80028E70(gPlayerSeven, camera1, 6, 0);
func_80028E70(gPlayerEight, camera1, 7, 0);
}
void func_80029060(void) {
// ClearEffectsMatrixPool();
gMatrixEffectCount = 0;
func_80028E70(gPlayerOne, camera1, 0, 0);
func_80028E70(gPlayerTwo, camera1, 1, 0);
func_80028E70(gPlayerThree, camera1, 2, 0);
func_80028E70(gPlayerFour, camera1, 3, 0);
func_80028E70(gPlayerFive, camera1, 4, 0);
func_80028E70(gPlayerSix, camera1, 5, 0);
func_80028E70(gPlayerSeven, camera1, 6, 0);
func_80028E70(gPlayerEight, camera1, 7, 0);
}
void func_80029150(void) {
}
void func_80029158(void) {
// ClearEffectsMatrixPool();
gMatrixEffectCount = 0;
func_80028E70(gPlayerOne, camera1, 0, 0);
func_80028E70(gPlayerTwo, camera1, 1, 0);
func_80028E70(gPlayerThree, camera1, 2, 0);
func_80028E70(gPlayerFour, camera1, 3, 0);
}
void func_800291E8(void) {
}
void func_800291F0(void) {
}
void func_800291F8(void) {
switch(gActiveScreenMode) {
default:
for (size_t i = 0; i < NUM_PLAYERS; i++) {
func_80028E70(&gPlayers[i], camera1, i, 0);
}
break;
case SCREEN_MODE_3P_4P_SPLITSCREEN:
for (size_t i = 0; i < 4; i++) {
func_80028E70(&gPlayers[i], camera1, i, 0);
}
break;
}
}
void func_80029200(Player* player, s8 screenId) {

View File

@ -19,15 +19,8 @@ void func_80028864(Player*, Camera*, s8, s8);
void func_80028C44(Player*, Camera*, s8, s8);
void func_80028D3C(Player*, Camera*, s8, s8);
void func_80028E70(Player*, Camera*, s8, s8);
void func_80028F5C(s32, s32, s32, s32);
void func_80028F70(void);
void func_80029060(void);
void func_80029150(void);
void func_80029158(void);
void func_800291E8(void);
void func_800291F0(void);
void func_800291F8(void);
void func_80029200(Player*, s8);
void func_8002934C(Player*, Camera*, s8, s8);

View File

@ -44,6 +44,11 @@
#include "engine/editor/SceneManager.h"
#include "RegisteredActors.h"
#include "engine/cameras/GameCamera.h"
#include "engine/cameras/FreeCamera.h"
#include "engine/cameras/TourCamera.h"
#include "engine/cameras/LookBehindCamera.h"
#ifdef _WIN32
#include <locale.h>
#endif
@ -54,6 +59,9 @@ extern "C" {
#include "audio/external.h"
#include "render_courses.h"
#include "menus.h"
#include "update_objects.h"
#include "spawn_players.h"
#include "src/enhancements/collision_viewer.h"
// #include "engine/wasm.h"
}
@ -301,26 +309,42 @@ s32 CM_GetCrossingOnTriggered(uintptr_t* crossing) {
}
}
void CM_RenderCourse(struct UnkStruct_800DC5EC* arg0) {
if (gWorldInstance.GetCurrentCourse()->IsMod() == false) {
if ((CVarGetInteger("gFreecam", 0) == true)) {
// Render credits courses
//gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
//gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_CULL_BACK | G_SHADING_SMOOTH);
// render_credits();
// return;
/**
* Tracks are rendered in two ways
* 1) Track sections --> The scene is split into multiple sections and rendered piece by piece
* 2) Full scene --> The entire scene is rendered at once
*
* Custom tracks only use the Render() method, and they only render the full scene.
* They do not use RenderCredits() and they do not use track sections.
*/
void CM_RenderCourse(struct UnkStruct_800DC5EC* screen) {
if (nullptr == gWorldInstance.GetCurrentCourse()) {
return;
}
// Custom tracks should never use RenderCredits();
if (gWorldInstance.GetCurrentCourse()->IsMod()) {
switch(screen->camera->renderMode) {
default:
gWorldInstance.GetCurrentCourse()->Render(screen);
break;
case RENDER_COLLISION_MESH:
render_collision();
break;
}
} else {
switch(screen->camera->renderMode) {
case RENDER_FULL_SCENE:
gWorldInstance.GetCurrentCourse()->RenderCredits();
break;
case RENDER_TRACK_SECTIONS:
gWorldInstance.GetCurrentCourse()->Render(screen);
break;
case RENDER_COLLISION_MESH:
render_collision();
break;
}
}
if (gWorldInstance.GetCurrentCourse()) {
gWorldInstance.GetCurrentCourse()->Render(arg0);
}
}
void CM_RenderCredits() {
if (gWorldInstance.GetCurrentCourse()) {
gWorldInstance.GetCurrentCourse()->RenderCredits();
}
}
void CM_TickActors() {
@ -336,6 +360,14 @@ void CM_DrawActors(Camera* camera) {
actor->Draw(camera);
}
}
for (auto* camera : gWorldInstance.Cameras) {
if (auto* tourCam = dynamic_cast<TourCamera*>(camera)) {
if (tourCam->IsActive()) {
tourCam->Draw();
}
}
}
}
void CM_DrawStaticMeshActors() {
@ -343,17 +375,168 @@ void CM_DrawStaticMeshActors() {
}
void CM_BeginPlay() {
static bool tour = false;
auto course = gWorldInstance.GetCurrentCourse();
if (nullptr == course) {
return;
}
if (tour) {
// gWorldInstance.Cameras[2]->SetActive(true);
// D_800DC5EC->camera = gWorldInstance.Cameras[2]->Get();
if (reinterpret_cast<TourCamera*>(gWorldInstance.Cameras[2])->IsTourComplete()) {
tour = false;
D_800DC5EC->pendingCamera = &cameras[0];
}
}
if (gWorldInstance.GetCurrentCourse()) {
// This line should likely be moved.
// It's here so PreInit is after the scene file has been loaded
// It used to be at the start of BeginPlay
Editor::LoadLevel(gWorldInstance.GetCurrentCourse().get(), gWorldInstance.GetCurrentCourse()->SceneFilePtr);
}
gWorldInstance.GetRaceManager().PreInit();
gWorldInstance.GetRaceManager().BeginPlay();
gWorldInstance.GetRaceManager().PostInit();
}
Camera* CM_GetPlayerCamera(s32 playerIndex) {
for (GameCamera* cam : gWorldInstance.Cameras) {
// Make sure this is a player camera and not a different type of camera
if (typeid(*cam) == typeid(GameCamera)) {
Camera* camera = cam->Get();
if (camera->playerId == playerIndex) {
return camera;
}
}
}
return nullptr;
}
void CM_SetViewProjection(Camera* camera) {
for (GameCamera* gameCamera : gWorldInstance.Cameras) {
if (camera == gameCamera->Get()) {
gameCamera->SetViewProjection();
}
}
}
void CM_TickCameras() {
gWorldInstance.TickCameras();
}
Camera* CM_AddCamera(Vec3f spawn, s16 rot, u32 mode) {
if (gWorldInstance.Cameras.size() >= NUM_CAMERAS) {
printf("Reached the max number of cameras, %d\n", NUM_CAMERAS);
return nullptr;
}
gWorldInstance.Cameras.push_back(new GameCamera(FVector(spawn[0], spawn[1], spawn[2]), rot, mode));
return gWorldInstance.Cameras.back()->Get();
}
Camera* CM_AddFreeCamera(Vec3f spawn, s16 rot, u32 mode) {
if (gWorldInstance.Cameras.size() >= NUM_CAMERAS) {
printf("Reached the max number of cameras, %d\n", NUM_CAMERAS);
return nullptr;
}
gWorldInstance.Cameras.push_back(new FreeCamera(FVector(spawn[0], spawn[1], spawn[2]), rot, mode));
return gWorldInstance.Cameras.back()->Get();
}
Camera* CM_AddTourCamera(Vec3f spawn, s16 rot, u32 mode) {
if (gWorldInstance.Cameras.size() >= NUM_CAMERAS) {
// This is to prevent soft locking the game
printf("Reached the max number of cameras, %d\n", NUM_CAMERAS);
if (gWorldInstance.GetCurrentCourse()->bTourEnabled) {
spawn_and_set_player_spawns();
}
return nullptr;
}
if (nullptr == gWorldInstance.GetCurrentCourse()) {
// This is to prevent soft locking the game
if (gWorldInstance.GetCurrentCourse()->bTourEnabled) {
spawn_and_set_player_spawns();
}
return nullptr;
}
if (gWorldInstance.GetCurrentCourse()->TourShots.size() == 0) {
// This is to prevent soft locking the game
if (gWorldInstance.GetCurrentCourse()->bTourEnabled) {
spawn_and_set_player_spawns();
}
return nullptr;
}
gWorldInstance.Cameras.push_back(new TourCamera(FVector(spawn[0], spawn[1], spawn[2]), rot, mode));
TourCamera* tour = static_cast<TourCamera*>(gWorldInstance.Cameras.back());
tour->SetActive(true);
return tour->Get();
}
bool CM_IsTourEnabled() {
if (nullptr != gWorldInstance.GetCurrentCourse()) {
if ((gWorldInstance.GetCurrentCourse()->bTourEnabled) && (gTourComplete == false)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Camera* CM_AddLookBehindCamera(Vec3f spawn, s16 rot, u32 mode) {
if (gWorldInstance.Cameras.size() >= NUM_CAMERAS) {
printf("Reached the max number of cameras, %d\n", NUM_CAMERAS);
return nullptr;
}
gWorldInstance.Cameras.push_back(new LookBehindCamera(FVector(spawn[0], spawn[1], spawn[2]), rot, mode));
return gWorldInstance.Cameras.back()->Get();
}
void CM_AttachCamera(Camera* camera, s32 playerIdx) {
camera->playerId = playerIdx;
}
void CM_CameraSetActive(size_t idx, bool state) {
if (idx < gWorldInstance.Cameras.size()) {
gWorldInstance.Cameras[idx]->SetActive(state);
}
}
void CM_SetFreeCamera(bool state) {
for (auto* cam : gWorldInstance.Cameras) {
if (cam->Get() == D_800DC5EC->freeCamera) {
if (state) {
D_800DC5EC->pendingCamera = D_800DC5EC->freeCamera;
cam->SetActive(true);
} else {
if (nullptr != D_800DC5EC->raceCamera) {
if (gGamestate == RACING) {
D_800DC5EC->pendingCamera = D_800DC5EC->raceCamera;
cam->SetActive(false);
} else {
cam->SetActive(false);
}
}
}
}
}
}
void CM_ActivateTourCamera(Camera* camera) {
for (auto* cam : gWorldInstance.Cameras) {
if (cam->Get() == camera) {
cam->SetActive(true);
}
}
}
void CM_TickObjects() {
if (gWorldInstance.GetCurrentCourse()) {
gWorldInstance.TickObjects();
@ -598,7 +781,15 @@ void CM_DeleteActor(size_t index) {
* Clean up actors and other game objects.
*/
void CM_CleanWorld(void) {
gWorldInstance.ClearWorld();
gWorldInstance.CleanWorld();
}
void CM_CleanCameras(void) {
for (auto& camera : gWorldInstance.Cameras) {
delete camera;
}
gWorldInstance.Cameras.clear();
}
struct Actor* CM_AddBaseActor() {
@ -723,6 +914,19 @@ void* GetBattleCup(void) {
void CM_RunGarbageCollector(void) {
RunGarbageCollector();
}
void CM_ResetAudio(void) {
if(HMAS_IsPlaying(HMAS_MUSIC)){
HMAS_AddEffect(HMAS_MUSIC, HMAS_EFFECT_VOLUME, HMAS_LINEAR, 10, 0);
HMAS_AddEffect(HMAS_MUSIC, HMAS_EFFECT_STOP, HMAS_INSTANT, 1, 0);
}
// Fade out music for all sequences and music player indexes 0, and 1
for (size_t soundId = 0; soundId < MUSIC_SEQ_MAX; soundId++) {
func_800C3448(0x10100000 | soundId);
func_800C3448(0x11100000 | soundId);
}
}
}
void push_frame() {

View File

@ -57,8 +57,6 @@ void CM_SetCupIndex(size_t index);
void CM_RenderCourse(struct UnkStruct_800DC5EC* arg0);
void CM_RenderCredits();
void CM_SpawnStarterLakitu();
void CM_ActivateFinishLakitu(s32 playerId);
void CM_ActivateSecondLapLakitu(s32 playerId);
@ -70,6 +68,18 @@ void CM_InitClouds();
void CM_DrawActors(Camera* camera);
void CM_DrawStaticMeshActors();
Camera* CM_GetPlayerCamera(s32 playerIndex);
void CM_SetViewProjection(Camera* camera);
void CM_TickCameras();
Camera* CM_AddCamera(Vec3f spawn, s16 rot, u32 mode);
Camera* CM_AddFreeCamera(Vec3f spawn, s16 rot, u32 mode);
Camera* CM_AddTourCamera(Vec3f spawn, s16 rot, u32 mode);
bool CM_IsTourEnabled();
Camera* CM_AddLookBehindCamera(Vec3f spawn, s16 rot, u32 mode);
void CM_AttachCamera(Camera* camera, s32 playerIdx);
void CM_SetFreeCamera(bool state);
void CM_CameraSetActive(size_t idx, bool state);
void CM_ActivateTourCamera(Camera* camera);
void CM_TickObjects();
void CM_TickObjects60fps();
void CM_DrawObjects(s32 cameraId);
@ -153,6 +163,7 @@ void Editor_AddLight(s8* direction);
size_t CM_GetActorSize();
size_t CM_FindActorIndex(struct Actor* actor);
void CM_ActorCollision(Player* player, struct Actor* actor);
void CM_CleanCameras(void);
void CM_CleanWorld(void);
f32 CM_GetWaterLevel(Vec3f pos, Collision* collision);
@ -214,6 +225,7 @@ void* GetBattleCup(void);
void* GetCup();
void CM_RunGarbageCollector(void);
void CM_ResetAudio(void);
#ifdef __cplusplus
}

View File

@ -1,5 +1,6 @@
#include "FreecamWindow.h"
#include "port/ui/PortMenu.h"
#include "port/Game.h"
#include "UIWidgets.h"
#include "libultraship/src/Context.h"
@ -10,6 +11,7 @@
#include "spdlog/formatter.h"
#include <common_structs.h>
#include <defines.h>
#include "engine/cameras/FreeCamera.h"
#include "enhancements/freecam/freecam_engine.h"
#include "enhancements/freecam/freecam.h"
@ -67,7 +69,11 @@ void RegisterFreecamWidgets() {
mPortMenu->AddWidget(path, "Controller: Up: A, Down: B, Faster: Z\n Target Player Mode: R, Next: Right DPad, Previous: Left DPad\n Driving Mode: L and R Buttons", WIDGET_TEXT);
mPortMenu->AddWidget(path, "Enable Freecam", WIDGET_CVAR_CHECKBOX)
.CVar("gFreecam")
.Options(UIWidgets::CheckboxOptions({{ .tooltip = "Allows you to fly around the course"}}));
.Options(UIWidgets::CheckboxOptions({{ .tooltip = "Allows you to fly around the track"}}))
.Callback([](WidgetInfo& info) {
bool state = (bool) CVarGetInteger("gFreecam", false);
CM_SetFreeCamera(state);
});
mPortMenu->AddWidget(path, "Camera Damping", WIDGET_SLIDER_FLOAT)
.ValuePointer(&gDampValue)

View File

@ -4,13 +4,15 @@
#include <libultraship/libultraship.h>
#include "UIWidgets.h"
#include "MenuTypes.h"
#include "../port/Game.h"
#include "src/port/Game.h"
#include "src/port/audio/HMAS.h"
extern "C" {
#include "defines.h"
#include "main.h"
#include "menus.h"
#include "code_800029B0.h"
#include "external.h"
}
namespace Ship {
@ -61,10 +63,15 @@ class Menu : public GuiWindow {
virtual void ProcessReset() {
gGamestateNext = MAIN_MENU_FROM_QUIT;
gIsGamePaused = 0;
// Reset credits
D_800DC5E4 = 0;
gTourComplete = false;
SetMarioRaceway();
memset(&gGameModeMenuColumn, 0, sizeof(s8) * NUM_ROWS_GAME_MODE_MENU);
memset(&gGameModeSubMenuColumn, 0, sizeof(s8) * NUM_COLUMN_GAME_MODE_SUB_MENU * NUM_ROWS_GAME_MODE_SUB_MENU);
CM_ResetAudio();
switch(CVarGetInteger("gSkipIntro", 0)) {
case 0:
gMenuSelection = HARBOUR_MASTERS_MENU;

View File

@ -107,8 +107,6 @@ void DrawColumn2(WidgetInfo& info) {
if (ImGui::Button("test", ImVec2(-1, 0))) {
// Add disconnect logic here
cameras[0].playerId = 2;
D_800DC5EC->player = &gPlayers[2];
}
for (size_t i = 0; i < NETWORK_MAX_PLAYERS; i++) {

View File

@ -403,6 +403,10 @@ void PortMenu::AddEnhancements() {
.CVar("gShowSpaghettiVersion")
.Options(CheckboxOptions().Tooltip("Show the Spaghetti Kart version on the Mario Kart menu").DefaultValue(true));
AddWidget(path, "Enable Look Behind Camera", WIDGET_CVAR_CHECKBOX)
.CVar("gLookBehind")
.Options(CheckboxOptions().Tooltip("Press C-Left to look behind you"));
AddRulesets();
path = { "Enhancements", "Cheats", SECTION_COLUMN_1 };
@ -424,6 +428,9 @@ void PortMenu::AddEnhancements() {
AddWidget(path, "Enable HM64 Labs", WIDGET_CVAR_CHECKBOX)
.CVar("gEditorEnabled")
.Callback([](WidgetInfo& info) {
if (CVarGetInteger("gEditorEnabled", false) == false) {
gIsEditorPaused = false;
}
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();

View File

@ -141,14 +141,21 @@ namespace Editor {
if (ImGui::Button(gIsEditorPaused ? ICON_FA_PLAY : ICON_FA_STOP, ImVec2(50, 25))) {
if (gIsEditorPaused) {
SaveLevel();
CVarSetInteger("gFreecam", false);
CM_SetFreeCamera(false);
} else {
CM_ResetAudio();
CVarSetInteger("gFreecam", true);
CM_SetFreeCamera(true);
}
gEditor.ResetGizmo();
gIsEditorPaused = !gIsEditorPaused;
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = RACING;
}
ImGui::PopStyleColor();
ImGui::SameLine();
@ -162,6 +169,7 @@ namespace Editor {
if (ImGui::Button(videoToolLabel, ImVec2(50, 25))) {
CVarSetInteger("gFreecam", !CVarGetInteger("gFreecam", 0));
CM_SetFreeCamera(CVarGetInteger("gFreecam", 0));
}
ImGui::PopStyleColor();

View File

@ -13,6 +13,8 @@
#include "port/Game.h"
#include "engine/cameras/TourCamera.h"
extern "C" {
#include "code_800029B0.h"
#include "sounds.h"
@ -33,6 +35,10 @@ namespace Editor {
static char debugNameBuffer[256] = "m circuit";
static char lengthBuffer[256] = "567m";
if (nullptr == gWorldInstance.GetCurrentCourse()) {
return;
}
ImGui::InputText("ID", idBuffer, IM_ARRAYSIZE(idBuffer));
ImGui::InputText("Name", gWorldInstance.GetCurrentCourse()->Props.Name, IM_ARRAYSIZE(nameBuffer));
ImGui::InputText("Debug Name", gWorldInstance.GetCurrentCourse()->Props.DebugName, IM_ARRAYSIZE(debugNameBuffer));
@ -165,6 +171,7 @@ namespace Editor {
FloatToRGB8(floorTopLeft, (u8*)&gWorldInstance.GetCurrentCourse()->Props.Skybox.FloorTopLeft);
TrackPropertiesWindow::DrawMusic();
TrackPropertiesWindow::DrawTourCamera();
}
void TrackPropertiesWindow::DrawMusic() {
@ -187,7 +194,7 @@ namespace Editor {
// Update the sequence when an option is selected
gWorldInstance.GetCurrentCourse()->Props.Sequence = static_cast<MusicSeq>(i);
play_sequence(gWorldInstance.GetCurrentCourse()->Props.Sequence); // Call play_sequence with the updated sequence
// Update currentItem after selection is made
currentItem = items[i];
}
@ -224,7 +231,7 @@ namespace Editor {
case MUSIC_SEQ_DK_JUNGLE: return "DK Jungle";
case MUSIC_SEQ_GAME_OVER: return "Game Over";
case MUSIC_SEQ_TOADS_TURNPIKE: return "Toad's Turnpike";
case MUSIC_SEQ_START_GIRD_TIME_ATTACK: return "Start Grid Time Attack";
case MUSIC_SEQ_START_GRID_TIME_ATTACK: return "Start Grid Time Attack";
case MUSIC_SEQ_VS_BATTLE_RESULTS: return "VS Battle Results";
case MUSIC_SEQ_LOSING_RESULTS: return "Losing Results";
case MUSIC_SEQ_BATTLE_ARENAS: return "Battle Arenas";
@ -287,4 +294,128 @@ namespace Editor {
}
}
int32_t TrackPropertiesWindow::SelectedShot = -1;
int32_t TrackPropertiesWindow::SelectedKeyframe = -1;
void TrackPropertiesWindow::DrawTourCamera() {
std::shared_ptr<Course> track = gWorldInstance.GetCurrentCourse();
if (nullptr == track) {
return;
}
Camera* camera = D_800DC5EC->camera;
if (nullptr == camera) {
return;
}
FVector camPos = FVector(camera->pos[0], camera->pos[1], camera->pos[2]);
FVector camLookAt = FVector(camera->lookAt[0], camera->lookAt[1], camera->lookAt[2]);
// Enable / disable
ImGui::Checkbox("Enable Tour Camera", &track->bTourEnabled);
if (!track->bTourEnabled) {
return;
}
ImGui::SeparatorText("Tour Camera Controls");
// Button to add a new empty shot
if (ImGui::Button("Add CameraShot")) {
TourCamera::CameraShot shot;
shot.Pos = camPos; // start where the camera currently is
shot.LookAt = camLookAt; // or however your camera exposes these
track->TourShots.push_back(shot);
}
ImGui::Spacing();
// ============================
// Display Camera Shots
// ============================
for (int32_t i = 0; i < track->TourShots.size(); i++)
{
TourCamera::CameraShot& shot = track->TourShots[i];
ImGui::PushID(i);
bool open = ImGui::CollapsingHeader(
("CameraShot " + std::to_string(i)).c_str(),
ImGuiTreeNodeFlags_DefaultOpen
);
// Select the shot
if (ImGui::Selectable("Select Shot", SelectedShot == i)) {
SelectedShot = i;
}
// Delete shot
ImGui::SameLine();
if (ImGui::Button("Delete Shot")) {
track->TourShots.erase(track->TourShots.begin() + i);
if (SelectedShot == i) SelectedShot = -1;
ImGui::PopID();
break;
}
if (open) {
ImGui::Indent();
// Start pos / lookAt editing
ImGui::InputFloat3("Start Pos", &shot.Pos.x);
ImGui::InputFloat3("Start LookAt", &shot.LookAt.x);
ImGui::Spacing();
// Record keyframe from current camera
if (ImGui::Button("Record KeyFrame From Camera")) {
TourCamera::KeyFrame kf;
kf.Pos = camPos;
kf.LookAt = camLookAt;
kf.Duration = 60.0f;
shot.Frames.push_back(kf);
}
ImGui::SeparatorText("KeyFrames");
// ============================
// KeyFrame List
// ============================
for (int32_t k = 0; k < shot.Frames.size(); k++)
{
TourCamera::KeyFrame& kf = shot.Frames[k];
ImGui::PushID(k);
bool kOpen = ImGui::TreeNode(("KeyFrame " + std::to_string(k)).c_str());
// Select keyframe
if (ImGui::Selectable("Select KeyFrame", SelectedKeyframe == k))
SelectedKeyframe = k;
ImGui::SameLine();
if (ImGui::Button("Delete")) {
shot.Frames.erase(shot.Frames.begin() + k);
if (SelectedKeyframe == k) SelectedKeyframe = -1;
ImGui::PopID();
break;
}
if (kOpen) {
ImGui::InputFloat3("Position", &kf.Pos.x);
ImGui::InputFloat3("LookAt", &kf.LookAt.x);
ImGui::DragFloat("Duration", &kf.Duration, 1.0f, 1.0f, 5000.0f);
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::Unindent();
}
ImGui::PopID();
}
}
}

View File

@ -21,5 +21,8 @@ protected:
void RGB8ToFloat(const u8* src, float* dst);
void FloatToRGB8(const float* src, u8* dst);
const char* MusicSeqToString(MusicSeq seq);
void DrawTourCamera();
static int32_t SelectedShot;
static int32_t SelectedKeyframe;
};
}

View File

@ -534,7 +534,7 @@ void render_cows(Camera* camera, Mat4 arg1) {
sp88[0] = var_s1->pos[0] * gCourseDirection;
sp88[1] = var_s1->pos[1];
sp88[2] = var_s1->pos[2];
temp_f0 = is_within_render_distance(camera->pos, sp88, camera->rot[1], 0.0f, gCameraZoom[camera - camera1],
temp_f0 = is_within_render_distance(camera->pos, sp88, camera->rot[1], 0.0f, gCameraFOV[camera - camera1],
4000000.0f);
if (temp_f0 > 0.0f) {
if (temp_f0 < D_8015F704) {
@ -677,7 +677,7 @@ void render_palm_trees(Camera* camera, Mat4 arg1) {
spD4[1] = var_s1->pos[1];
spD4[2] = var_s1->pos[2];
if (is_within_render_distance(camera->pos, spD4, camera->rot[1], 0.0f, gCameraZoom[camera - camera1], var_f22) <
if (is_within_render_distance(camera->pos, spD4, camera->rot[1], 0.0f, gCameraFOV[camera - camera1], var_f22) <
0.0f &&
CVarGetInteger("gNoCulling", 0) == 0) {
var_s1++;
@ -743,7 +743,7 @@ void render_actor_shell(Camera* camera, Mat4 matrix, struct ShellActor* shell) {
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);
is_within_render_distance(camera->pos, shell->pos, camera->rot[1], 0, gCameraFOV[camera - camera1], 490000.0f);
if (CVarGetInteger("gNoCulling", 0) == 1) {
temp_f0 = CLAMP(temp_f0, 0.0f, 40000.0f);
}
@ -823,7 +823,7 @@ UNUSED void func_8029ABD4(f32* pos, s16 state) {
}
void func_8029AC18(Camera* camera, Mat4 arg1, struct Actor* arg2) {
if (is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraZoom[camera - camera1],
if (is_within_render_distance(camera->pos, arg2->pos, camera->rot[1], 0, gCameraFOV[camera - camera1],
4000000.0f) < 0 &&
CVarGetInteger("gNoCulling", 0) == 0) {
return;

View File

@ -655,7 +655,7 @@ void func_8028F4E8(void) {
void func_8028F588(void) {
s16 screenWidth;
if (CVarGetInteger("gEditorEnabled", 0) == true) {
if ((CVarGetInteger("gEditorEnabled", 0) == true) || (CM_IsTourEnabled() == true)) {
D_800DC5EC->screenWidth = SCREEN_WIDTH;
D_800DC5EC->screenHeight = SCREEN_HEIGHT;
return;
@ -875,17 +875,17 @@ void func_8028FCBC(void) {
case RACE_INIT:
if (!gDemoMode) {
if (gModeSelection == GRAND_PRIX) {
func_800C8EF8(11);
play_sequence2(MUSIC_SEQ_START_GRID_GP_VS);
play_sound2(SOUND_ACTION_REV_ENGINE);
play_sound2(SOUND_ACTION_REV_ENGINE_2);
} else {
func_800C8EF8(22);
play_sequence2(MUSIC_SEQ_START_GRID_TIME_ATTACK);
}
}
func_80002DAC();
gRaceState = RACE_SETUP;
D_80150118 = 3.0f;
creditsRenderMode = 0;
// creditsRenderMode = 0; This is now set in GameCamera class
D_802BA032 = 0;
D_8015011E = 0;
gCourseTimer = 0.0f;
@ -1037,6 +1037,7 @@ void func_8028FCBC(void) {
if (D_802BA034 <= 0) {
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gTourComplete = false;
}
break;
case RACE_EXIT:
@ -1048,30 +1049,35 @@ UNUSED void func_80290314(void) {
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = START_MENU_FROM_QUIT;
gTourComplete = false;
}
void func_80290338(void) {
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = MAIN_MENU_FROM_QUIT;
gTourComplete = false;
}
void func_80290360(void) {
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = PLAYER_SELECT_MENU_FROM_QUIT;
gTourComplete = false;
}
void func_80290388(void) {
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = COURSE_SELECT_MENU_FROM_QUIT;
gTourComplete = false;
}
void func_802903B0(void) {
gIsInQuitToMenuTransition = 1;
gQuitToMenuTransitionCounter = 5;
gGotoMode = RACING;
gTourComplete = false;
// Stop when retrying
if(HMAS_IsPlaying(HMAS_MUSIC)) {
HMAS_Stop(HMAS_MUSIC);

View File

@ -126,7 +126,7 @@ void render_course_segments(const char* addr[], struct UnkStruct_800DC5EC* arg1)
}
arg1->playerDirection = direction;
if (D_80152300[camera - camera1] == 1) {
if (camera->mode == 1) {
sp1E = get_track_section_id(camera->collision.meshIndexZX);
temp_v0_3 = get_track_section_id(player->collision.meshIndexZX);
index = sp1E - temp_v0_3;
@ -200,9 +200,9 @@ void func_80291198(void) {
gSPDisplayList(gDisplayListHead++, (Gfx*) d_course_mario_raceway_packed_dl_1140); //
}
void func_8029122C(struct UnkStruct_800DC5EC* arg0, s32 playerId) {
void func_8029122C(struct UnkStruct_800DC5EC* screen, s32 playerId) {
UNUSED s32 pad;
Player* player = arg0->player;
Player* player = screen->player;
Mat4 matrix;
Vec3f vector;
u16 pathCounter;
@ -210,38 +210,20 @@ void func_8029122C(struct UnkStruct_800DC5EC* arg0, s32 playerId) {
s16 playerDirection;
init_rdp();
pathCounter = (u16) arg0->pathCounter;
cameraRot = (u16) arg0->camera->rot[1];
playerDirection = arg0->playerDirection;
pathCounter = (u16) screen->pathCounter;
cameraRot = (u16) screen->camera->rot[1];
playerDirection = screen->playerDirection;
// This pushes the camera matrices to the top of the stack.
// It does not appear to really do anything.
// Perhaps they thought it was necessary to set the camera back to projection mode since rainbow road uses model
// mode. But that issue should be cleared up in render_screens() already.
switch (playerId) {
case PLAYER_ONE:
size_t playerIdx = PLAYER_ONE;
if (CVarGetInteger("gFreecam", 0) == true) {
playerIdx = CAMERA_FREECAM;
}
gSPMatrix(gDisplayListHead++, GetPerspMatrix(playerIdx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(playerIdx), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
break;
case PLAYER_TWO:
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_TWO), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_TWO), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
break;
case PLAYER_THREE:
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_THREE), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_THREE), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
break;
case PLAYER_FOUR:
gSPMatrix(gDisplayListHead++, GetPerspMatrix(PLAYER_FOUR), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, GetLookAtMatrix(PLAYER_FOUR), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
break;
}
// Perhaps they thought it was necessary to set the camera back to projection mode since rainbow road uses model mode.
// But that issue should be cleared up in render_screens() already.
gSPMatrix(gDisplayListHead++, screen->camera->perspectiveMatrix,
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
gSPMatrix(gDisplayListHead++, screen->camera->lookAtMatrix,
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordOpenChild("track_water", playerId);
FrameInterpolation_RecordOpenChild("track_water", screen->camera->cameraId);
mtxf_identity(matrix);
if (gIsMirrorMode != 0) {
@ -251,29 +233,13 @@ void func_8029122C(struct UnkStruct_800DC5EC* arg0, s32 playerId) {
}
render_set_position(matrix, 0);
CM_DrawWater(arg0, pathCounter, cameraRot, playerDirection);
CM_DrawWater(screen, pathCounter, cameraRot, playerDirection);
FrameInterpolation_RecordCloseChild();
}
void render_credits(void) {
CM_RenderCredits();
}
void render_course(struct UnkStruct_800DC5EC* arg0) {
void render_course(struct UnkStruct_800DC5EC* screen) {
set_track_light_direction(D_800DC610, D_802B87D4, 0, 1);
// Freecam priority renders collision.
if (CVarGetInteger("gRenderCollisionMesh", 0) == true) {
render_collision();
return;
}
if (creditsRenderMode) {
render_credits();
return;
}
CM_RenderCourse(arg0);
CM_RenderCourse(screen);
}
void func_80295BF8(s32 playerIndex) {

View File

@ -10,7 +10,6 @@ s32 func_80290C20(Camera*);
void parse_course_displaylists(TrackSections* asset);
void render_course_segments(const char*[], struct UnkStruct_800DC5EC*);
void func_80291198(void);
void render_credits(void);
void course_init(void);
void render_course(struct UnkStruct_800DC5EC*);
void func_80295BF8(s32);

View File

@ -560,22 +560,22 @@ void func_802A4D18(void) {
void func_802A4EF4(void) {
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
func_8001F394(gPlayerOne, &gCameraZoom[0]);
func_8001F394(gPlayerOne, &gCameraFOV[0]);
break;
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
func_8001F394(gPlayerOne, &gCameraZoom[0]);
func_8001F394(gPlayerTwo, &gCameraZoom[1]);
func_8001F394(gPlayerOne, &gCameraFOV[0]);
func_8001F394(gPlayerTwo, &gCameraFOV[1]);
break;
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
func_8001F394(gPlayerOne, &gCameraZoom[0]);
func_8001F394(gPlayerTwo, &gCameraZoom[1]);
func_8001F394(gPlayerOne, &gCameraFOV[0]);
func_8001F394(gPlayerTwo, &gCameraFOV[1]);
break;
case SCREEN_MODE_3P_4P_SPLITSCREEN:
func_8001F394(gPlayerOne, &gCameraZoom[0]);
func_8001F394(gPlayerTwo, &gCameraZoom[1]);
func_8001F394(gPlayerThree, &gCameraZoom[2]);
func_8001F394(gPlayerFour, &gCameraZoom[3]);
func_8001F394(gPlayerOne, &gCameraFOV[0]);
func_8001F394(gPlayerTwo, &gCameraFOV[1]);
func_8001F394(gPlayerThree, &gCameraFOV[2]);
func_8001F394(gPlayerFour, &gCameraFOV[3]);
break;
}
}
@ -585,15 +585,15 @@ void func_802A5004(void) {
init_rdp();
func_802A3730(D_800DC5F0);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
func_802A39E0(D_800DC5F0);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[1]);
func_802A4A0C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[1]);
func_80057FC4(2);
func_802A487C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[1]);
func_802A487C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[1]);
func_80093A30(2);
}
}
@ -603,14 +603,14 @@ void func_802A50EC(void) {
init_rdp();
func_802A3730(D_800DC5EC);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
func_802A39E0(D_800DC5EC);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[0]);
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[0]);
func_80057FC4(1);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[0]);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[0]);
func_80093A30(1);
}
}
@ -621,13 +621,13 @@ void func_802A51D4(void) {
func_802A39E0(D_800DC5EC);
func_802A3730(D_800DC5EC);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[0]);
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[0]);
func_80057FC4(3);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[0]);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[0]);
func_80093A30(3);
}
}
@ -638,13 +638,13 @@ void func_802A52BC(void) {
func_802A39E0(D_800DC5F0);
func_802A3730(D_800DC5F0);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[1]);
func_802A4A0C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[1]);
func_80057FC4(4);
func_802A487C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[1]);
func_802A487C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[1]);
func_80093A30(4);
}
}
@ -653,17 +653,17 @@ void func_802A53A4(void) {
init_rdp();
func_802A3730(D_800DC5EC);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
init_z_buffer();
select_framebuffer();
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraZoom[0]);
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraFOV[0]);
if (gGamestate != CREDITS_SEQUENCE) {
func_80057FC4(0);
}
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraZoom[0]);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraFOV[0]);
func_80093A30(0);
}
}
@ -674,13 +674,13 @@ void func_802A54A8(void) {
func_802A39E0(D_800DC5EC);
func_802A3730(D_800DC5EC);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraZoom[0]);
func_802A4A0C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraFOV[0]);
func_80057FC4(8);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraZoom[0]);
func_802A487C((Vtx*) D_802B8890, D_800DC5EC, 0x140, 0xF0, &gCameraFOV[0]);
func_80093A30(8);
}
}
@ -691,13 +691,13 @@ void func_802A5590(void) {
func_802A39E0(D_800DC5F0);
func_802A3730(D_800DC5F0);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[1]);
func_802A4A0C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[1]);
func_80057FC4(9);
func_802A487C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[1]);
func_802A487C((Vtx*) D_802B8910, D_800DC5F0, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[1]);
func_80093A30(9);
}
}
@ -708,13 +708,13 @@ void func_802A5678(void) {
func_802A39E0(D_800DC5F4);
func_802A3730(D_800DC5F4);
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
if (D_800DC5B4 != 0) {
func_802A4A0C((Vtx*) D_802B8990, D_800DC5F4, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[2]);
func_802A4A0C((Vtx*) D_802B8990, D_800DC5F4, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[2]);
func_80057FC4(10);
func_802A487C((Vtx*) D_802B8990, D_800DC5F4, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[2]);
func_802A487C((Vtx*) D_802B8990, D_800DC5F4, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[2]);
func_80093A30(10);
}
}
@ -723,7 +723,7 @@ void func_802A5760(void) {
init_rdp();
gSPClearGeometryMode(gDisplayListHead++, 0xFFFFFFFF);
gSPClearGeometryMode(gDisplayListHead++, G_CLEAR_ALL_MODES);
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CLIPPING);
if (gPlayerCountSelection1 == 3) {
@ -747,44 +747,14 @@ void func_802A5760(void) {
func_802A39E0(D_800DC5F8);
if (D_800DC5B4 != 0) {
func_802A4A0C(D_802B8A10, D_800DC5F8, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[3]);
func_802A4A0C(D_802B8A10, D_800DC5F8, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[3]);
func_80057FC4(11);
func_802A487C(D_802B8A10, D_800DC5F8, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraZoom[3]);
func_802A487C(D_802B8A10, D_800DC5F8, SCREEN_WIDTH, SCREEN_HEIGHT, &gCameraFOV[3]);
func_80093A30(11);
}
}
}
// Setup the cameras perspective and lookAt (movement/rotation)
void setup_camera(Camera* camera, s32 playerId, s32 cameraId, struct UnkStruct_800DC5EC* screen) {
u16 perspNorm;
// This allows freecam to create a new separate camera
if (CVarGetInteger("gFreecam", 0) == true) {
freecam_render_setup(gFreecamCamera);
return;
}
// Tag the camera for the interpolation engine
FrameInterpolation_RecordOpenChild("camera",
(FrameInterpolation_GetCameraEpoch() | (playerId | (cameraId << 8))));
// Calculate camera perspective (camera movement/location)
guPerspective(GetPerspMatrix(cameraId), &perspNorm, gCameraZoom[cameraId], gScreenAspect,
CM_GetProps()->NearPersp, CM_GetProps()->FarPersp, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, GetPerspMatrix(cameraId),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
// Calculate the camera lookAt (camera rotation)
guLookAt(GetLookAtMatrix(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++, GetLookAtMatrix(cameraId),
G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
}
void render_screens(s32 mode, s32 cameraId, s32 playerId) {
Mat4 matrix;
@ -848,16 +818,15 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
}
struct UnkStruct_800DC5EC* screen = &D_8015F480[screenId];
Camera* camera;
Camera* camera = screen->camera;
cameraId = camera->cameraId;
// CM_GetCamera(cameraId);
// Required for freecam to have its own camera
if (CVarGetInteger("gFreecam", 0) == true) {
camera = &cameras[CAMERA_FREECAM];
cameraId = CAMERA_FREECAM;
} else {
camera = &cameras[cameraId];
if (NULL == camera) {
printf("NO CAMERA SELECTED\n");
return;
}
if (screenMode == SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL) {
gSPSetGeometryMode(gDisplayListHead++, G_SHADE | G_CULL_BACK | G_LIGHTING | G_SHADING_SMOOTH);
}
@ -868,10 +837,10 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
// Setup camera perspective and lookAt
setup_camera(camera, playerId, cameraId, screen);
CM_SetViewProjection(camera);
// Create a matrix for the track and game objects
FrameInterpolation_RecordOpenChild("track", TAG_TRACK((cameraId | playerId)));
FrameInterpolation_RecordOpenChild("track", TAG_TRACK((cameraId | (playerId << 2))));
Mat4 trackMatrix;
mtxf_identity(trackMatrix);
if (gIsMirrorMode != 0) {
@ -889,22 +858,12 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
render_course_actors(screen);
CM_DrawActors(camera);
CM_DrawStaticMeshActors();
render_object(mode);
render_object(screen);
switch (screenId) {
case 0:
render_players_on_screen_one();
break;
case 1:
render_players_on_screen_two();
break;
case 2:
render_players_on_screen_three();
break;
case 3:
render_players_on_screen_four();
break;
if (CM_IsTourEnabled() == false) {
render_players(camera, screenId);
}
func_8029122C(screen, playerId); // Track water related
switch (playerId) { // Render player particles or some effect
@ -923,7 +882,7 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
};
render_item_boxes(screen);
render_player_snow_effect(mode);
render_player_snow_effect(camera);
func_80058BF4(); // Setup texture modes
if (D_800DC5B8 != 0) {
func_80058C20(mode); // Setup hud matrix
@ -952,16 +911,12 @@ void set_screen(void) {
for (i = 0; i < 4; i++) {
wrapper->controllers = controller;
if ((CVarGetInteger("gFreecam", 0) == true) && (i == PLAYER_ONE)) {
wrapper->camera = gFreecamCamera;
} else {
wrapper->camera = camera;
}
// wrapper->camera = &cameras[i]; // Done in spawn_players now
wrapper->player = player;
wrapper->unkC = unk;
// Tick is not enabled in the editor, so the screen needs to begin at the proper size.
if ((CVarGetInteger("gEditorEnabled", 0) == true) && (gIsEditorPaused) && (i == PLAYER_ONE)) {
if (((CVarGetInteger("gEditorEnabled", 0) == true) && (gIsEditorPaused) && (i == PLAYER_ONE)) || CM_IsTourEnabled() == true) {
wrapper->screenWidth = SCREEN_WIDTH;
wrapper->screenHeight = SCREEN_HEIGHT;
} else { // Normal race start, screen is small

View File

@ -263,258 +263,85 @@ void init_render_player(Player* player, Camera* camera, s8 playerId, s8 screenId
}
}
void load_kart_texture_and_render_kart_particle_on_screen_one(void) {
/**
* This function used to be split for each player screen.
* It is combined now.
*
* Check buffers.c
* // [nothing][screen][player]
* ALIGNED8 struct_D_802DFB80 gEncodedKartTexture[2][2][8];
*
* The buffer is sized for two screens. In 3P/4P mode, the player and screen indexes
* need to be adjusted like so:
*
* Screen 3 uses buffer[unused][screen 1][slots 5-8]
* Screen 4 uses buffer[unused][screen 2][slots 5-8]
*
* Due to this remapping, 3P/4P modes only support upto four racers.
*
*/
void load_kart_texture_and_render_kart_particles(s32 screenIdx) {
s16 i;
s32 screenOffset = (screenIdx >= 2) ? -2: 0;
s32 playerOffset = (screenIdx >= 2) ? 4 : 0;
load_kart_texture_non_blocking(gPlayersToRenderPlayer[0], gPlayersToRenderPlayerId[0], gPlayersToRenderScreenId[0],
gPlayersToRenderScreenId[0],
D_801651D0[gPlayersToRenderScreenId[0]][gPlayersToRenderPlayerId[0]]);
load_kart_texture_non_blocking(
gPlayersToRenderPlayer[0],
gPlayersToRenderPlayerId[0] + playerOffset,
gPlayersToRenderScreenId[0],
gPlayersToRenderScreenId[0] + screenOffset,
D_801651D0[gPlayersToRenderScreenId[0]][gPlayersToRenderPlayerId[0]]
);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
for (i = 1; i < gPlayersToRenderCount; i++) {
load_kart_texture_non_blocking(gPlayersToRenderPlayer[i], gPlayersToRenderPlayerId[i],
gPlayersToRenderScreenId[i], gPlayersToRenderScreenId[i],
D_801651D0[gPlayersToRenderScreenId[i]][gPlayersToRenderPlayerId[i]]);
#ifdef TARGET_N64
load_kart_texture_non_blocking(
gPlayersToRenderPlayer[i],
gPlayersToRenderPlayerId[i] + playerOffset,
gPlayersToRenderScreenId[i],
gPlayersToRenderScreenId[i] + screenOffset,
D_801651D0[gPlayersToRenderScreenId[i]][gPlayersToRenderPlayerId[i]]
);
mio0decode(
(u8*) gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]]
[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]]
[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]
.pixel_index_array);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
#else
strcpy(D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]]
[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]]
[gPlayersToRenderScreenId[i - 1]][gPlayersToRenderPlayerId[i - 1]]
.unk_00);
#endif
}
#ifdef TARGET_N64
mio0decode((u8*) gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.pixel_index_array);
#else
strcpy(D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.unk_00);
#endif
}
void load_kart_texture_and_render_kart_particle_on_screen_two(void) {
s16 var_s0;
load_kart_texture_non_blocking(gPlayersToRenderPlayer[0], gPlayersToRenderPlayerId[0], gPlayersToRenderScreenId[0],
gPlayersToRenderScreenId[0],
D_801651D0[gPlayersToRenderScreenId[0]][gPlayersToRenderPlayerId[0]]);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
for (var_s0 = 1; var_s0 < gPlayersToRenderCount; var_s0++) {
load_kart_texture_non_blocking(gPlayersToRenderPlayer[var_s0], gPlayersToRenderPlayerId[var_s0],
gPlayersToRenderScreenId[var_s0], gPlayersToRenderScreenId[var_s0],
D_801651D0[gPlayersToRenderScreenId[var_s0]][gPlayersToRenderPlayerId[var_s0]]);
#ifdef TARGET_N64
mio0decode(
(u8*) gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]]
[gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]
.pixel_index_array);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
#else
strcpy(
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]
.unk_00);
#endif
D_802BFB80.arraySize8[D_801651D0[gPlayersToRenderScreenId[i - 1]]
[gPlayersToRenderPlayerId[i - 1]]]
[gPlayersToRenderScreenId[i - 1] + screenOffset]
[gPlayersToRenderPlayerId[i - 1] + playerOffset]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[i - 1]]
[gPlayersToRenderPlayerId[i - 1]]]
[gPlayersToRenderScreenId[i - 1] + screenOffset]
[gPlayersToRenderPlayerId[i - 1] + playerOffset]
.unk_00
);
}
#ifdef TARGET_N64
mio0decode((u8*) gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.pixel_index_array);
#else
strcpy(D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]
.unk_00);
#endif
strcpy(
D_802BFB80.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] + screenOffset]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + playerOffset]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] + screenOffset]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + playerOffset]
.unk_00
);
}
void load_kart_texture_and_render_kart_particle_on_screen_three(void) {
s16 var_s0;
load_kart_texture_non_blocking(gPlayersToRenderPlayer[0], gPlayersToRenderPlayerId[0] + 4,
gPlayersToRenderScreenId[0], gPlayersToRenderScreenId[0] - 2,
D_801651D0[gPlayersToRenderScreenId[0]][gPlayersToRenderPlayerId[0]]);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
for (var_s0 = 1; var_s0 < gPlayersToRenderCount; var_s0++) {
load_kart_texture_non_blocking(gPlayersToRenderPlayer[var_s0], gPlayersToRenderPlayerId[var_s0] + 4,
gPlayersToRenderScreenId[var_s0], gPlayersToRenderScreenId[var_s0] - 2,
D_801651D0[gPlayersToRenderScreenId[var_s0]][gPlayersToRenderPlayerId[var_s0]]);
#ifdef TARGET_N64
mio0decode(
(u8*) gEncodedKartTexture
[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.pixel_index_array);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
#else
strcpy(
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.unk_00);
#endif
}
#ifdef TARGET_N64
mio0decode((u8*) gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.pixel_index_array);
#else
strcpy(D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.unk_00);
#endif
}
void load_kart_texture_and_render_kart_particle_on_screen_four(void) {
s16 var_s0;
load_kart_texture_non_blocking(gPlayersToRenderPlayer[0], gPlayersToRenderPlayerId[0] + 4,
gPlayersToRenderScreenId[0], gPlayersToRenderScreenId[0] - 2,
D_801651D0[gPlayersToRenderScreenId[0]][gPlayersToRenderPlayerId[0]]);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
for (var_s0 = 1; var_s0 < gPlayersToRenderCount; var_s0++) {
load_kart_texture_non_blocking(gPlayersToRenderPlayer[var_s0], gPlayersToRenderPlayerId[var_s0] + 4,
gPlayersToRenderScreenId[var_s0], gPlayersToRenderScreenId[var_s0] - 2,
D_801651D0[gPlayersToRenderScreenId[var_s0]][gPlayersToRenderPlayerId[var_s0]]);
#ifdef TARGET_N64
mio0decode(
(u8*) gEncodedKartTexture
[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.pixel_index_array);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
#else
strcpy(
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[var_s0 - 1]][gPlayersToRenderPlayerId[var_s0 - 1]]]
[gPlayersToRenderScreenId[var_s0 - 1] - 2][gPlayersToRenderPlayerId[var_s0 - 1] + 4]
.unk_00);
#endif
}
#ifdef TARGET_N64
mio0decode((u8*) gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.unk_00,
D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.pixel_index_array);
#else
strcpy(D_802BFB80
.arraySize8[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.pixel_index_array,
gEncodedKartTexture[D_801651D0[gPlayersToRenderScreenId[gPlayersToRenderCount - 1]]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1]]]
[gPlayersToRenderScreenId[gPlayersToRenderCount - 1] - 2]
[gPlayersToRenderPlayerId[gPlayersToRenderCount - 1] + 4]
.unk_00);
#endif
}
void try_rendering_player(Player* player, s8 playerId, s8 arg2) {
void try_rendering_player(Player* player, s8 playerId, s8 screenIdx) {
if (((player->type & PLAYER_EXISTS) == PLAYER_EXISTS) && ((player->type & PLAYER_UNKNOWN_0x40) == 0)) {
if ((player->unk_002 & 2 << (arg2 * 4)) == 2 << (arg2 * 4)) {
render_player(player, playerId, arg2);
if ((player->unk_002 & 2 << (screenIdx * 4)) == 2 << (screenIdx * 4)) {
render_player(player, playerId, screenIdx);
}
}
}
void render_players_on_screen_one(void) {
void render_players(Camera* camera, s32 screenIdx) {
UNUSED s32 pad;
UNUSED char* sp3C[8] = {
"S_MARIO", "S_LUIZI", "S_YOSSY", "S_KINOP", "S_DONKY", "S_WARIO", "S_PEACH", "S_KUPPA",
@ -524,57 +351,44 @@ void render_players_on_screen_one(void) {
};
gPlayersToRenderCount = 0;
init_render_player(gPlayerOne, camera1, PLAYER_ONE, PLAYER_ONE);
init_render_player(gPlayerTwo, camera1, PLAYER_TWO, PLAYER_ONE);
init_render_player(gPlayerThree, camera1, PLAYER_THREE, PLAYER_ONE);
init_render_player(gPlayerFour, camera1, PLAYER_FOUR, PLAYER_ONE);
init_render_player(gPlayerOne, camera, PLAYER_ONE, screenIdx);
init_render_player(gPlayerTwo, camera, PLAYER_TWO, screenIdx);
init_render_player(gPlayerThree, camera, PLAYER_THREE, screenIdx);
init_render_player(gPlayerFour, camera, PLAYER_FOUR, screenIdx);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
init_render_player(gPlayerFive, camera1, PLAYER_FIVE, PLAYER_ONE);
init_render_player(gPlayerSix, camera1, PLAYER_SIX, PLAYER_ONE);
init_render_player(gPlayerSeven, camera1, PLAYER_SEVEN, PLAYER_ONE);
init_render_player(gPlayerEight, camera1, PLAYER_EIGHT, PLAYER_ONE);
init_render_player(gPlayerFive, camera, PLAYER_FIVE, screenIdx);
init_render_player(gPlayerSix, camera, PLAYER_SIX, screenIdx);
init_render_player(gPlayerSeven, camera, PLAYER_SEVEN, screenIdx);
init_render_player(gPlayerEight, camera, PLAYER_EIGHT, screenIdx);
}
// This call moved here to sync kart texture and wheel texture tlut loading/rendering
if (gPlayersToRenderCount != 0) {
load_kart_texture_and_render_kart_particle_on_screen_one();
load_kart_texture_and_render_kart_particles(screenIdx);
}
try_rendering_player(gPlayerOne, PLAYER_ONE, PLAYER_ONE);
try_rendering_player(gPlayerTwo, PLAYER_TWO, PLAYER_ONE);
try_rendering_player(gPlayerThree, PLAYER_THREE, PLAYER_ONE);
try_rendering_player(gPlayerFour, PLAYER_FOUR, PLAYER_ONE);
try_rendering_player(gPlayerOne, PLAYER_ONE, screenIdx);
try_rendering_player(gPlayerTwo, PLAYER_TWO, screenIdx);
try_rendering_player(gPlayerThree, PLAYER_THREE, screenIdx);
try_rendering_player(gPlayerFour, PLAYER_FOUR, screenIdx);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
try_rendering_player(gPlayerFive, PLAYER_FIVE, PLAYER_ONE);
try_rendering_player(gPlayerSix, PLAYER_SIX, PLAYER_ONE);
try_rendering_player(gPlayerSeven, PLAYER_SEVEN, PLAYER_ONE);
try_rendering_player(gPlayerEight, PLAYER_EIGHT, PLAYER_ONE);
try_rendering_player(gPlayerFive, PLAYER_FIVE, screenIdx);
try_rendering_player(gPlayerSix, PLAYER_SIX, screenIdx);
try_rendering_player(gPlayerSeven, PLAYER_SEVEN, screenIdx);
try_rendering_player(gPlayerEight, PLAYER_EIGHT, screenIdx);
}
if (gPlayersToRenderCount != 0) {
// Old call which is out of sync
// load_kart_texture_and_render_kart_particle_on_screen_one();
render_kart_particle_on_screen_one(gPlayerOne, PLAYER_ONE, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerTwo, PLAYER_TWO, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerThree, PLAYER_THREE, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerFour, PLAYER_FOUR, PLAYER_ONE);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
render_kart_particle_on_screen_one(gPlayerFive, PLAYER_FIVE, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerSix, PLAYER_SIX, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerSeven, PLAYER_SEVEN, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerEight, PLAYER_EIGHT, PLAYER_ONE);
}
} else {
render_kart_particle_on_screen_one(gPlayerOne, PLAYER_ONE, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerTwo, PLAYER_TWO, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerThree, PLAYER_THREE, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerFour, PLAYER_FOUR, PLAYER_ONE);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
render_kart_particle_on_screen_one(gPlayerFive, PLAYER_FIVE, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerSix, PLAYER_SIX, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerSeven, PLAYER_SEVEN, PLAYER_ONE);
render_kart_particle_on_screen_one(gPlayerEight, PLAYER_EIGHT, PLAYER_ONE);
}
// Old call which results in out of sync kart textures
// load_kart_texture_and_render_kart_particle_on_screen_one();
render_kart_particles(gPlayerOne, PLAYER_ONE, screenIdx);
render_kart_particles(gPlayerTwo, PLAYER_TWO, screenIdx);
render_kart_particles(gPlayerThree, PLAYER_THREE, screenIdx);
render_kart_particles(gPlayerFour, PLAYER_FOUR, screenIdx);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
render_kart_particles(gPlayerFive, PLAYER_FIVE, screenIdx);
render_kart_particles(gPlayerSix, PLAYER_SIX, screenIdx);
render_kart_particles(gPlayerSeven, PLAYER_SEVEN, screenIdx);
render_kart_particles(gPlayerEight, PLAYER_EIGHT, screenIdx);
}
gPlayersToRenderCount = 0;
}
@ -726,121 +540,6 @@ const char** wheelPtr[] = {
s32 D_800DDE74[] = { 96, 128, 192, 256, 288, 384, 512, 544, 576, 0, 0 };
void render_players_on_screen_two(void) {
gPlayersToRenderCount = 0;
init_render_player(gPlayerOne, camera2, PLAYER_ONE, PLAYER_TWO);
init_render_player(gPlayerTwo, camera2, PLAYER_TWO, PLAYER_TWO);
init_render_player(gPlayerThree, camera2, PLAYER_THREE, PLAYER_TWO);
init_render_player(gPlayerFour, camera2, PLAYER_FOUR, PLAYER_TWO);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
init_render_player(gPlayerFive, camera2, PLAYER_FIVE, PLAYER_TWO);
init_render_player(gPlayerSix, camera2, PLAYER_SIX, PLAYER_TWO);
init_render_player(gPlayerSeven, camera2, PLAYER_SEVEN, PLAYER_TWO);
init_render_player(gPlayerEight, camera2, PLAYER_EIGHT, PLAYER_TWO);
}
// Call moved to sync kart and wheel tlut loading/rendering
if (gPlayersToRenderCount != 0) {
load_kart_texture_and_render_kart_particle_on_screen_two();
}
try_rendering_player(gPlayerOne, PLAYER_ONE, PLAYER_TWO);
try_rendering_player(gPlayerTwo, PLAYER_TWO, PLAYER_TWO);
try_rendering_player(gPlayerThree, PLAYER_THREE, PLAYER_TWO);
try_rendering_player(gPlayerFour, PLAYER_FOUR, PLAYER_TWO);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
try_rendering_player(gPlayerFive, PLAYER_FIVE, PLAYER_TWO);
try_rendering_player(gPlayerSix, PLAYER_SIX, PLAYER_TWO);
try_rendering_player(gPlayerSeven, PLAYER_SEVEN, PLAYER_TWO);
try_rendering_player(gPlayerEight, PLAYER_EIGHT, PLAYER_TWO);
}
if (gPlayersToRenderCount != 0) {
// load_kart_texture_and_render_kart_particle_on_screen_two();
render_kart_particle_on_screen_two(gPlayerOne, PLAYER_ONE, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerTwo, PLAYER_TWO, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerThree, PLAYER_THREE, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerFour, PLAYER_FOUR, PLAYER_TWO);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
render_kart_particle_on_screen_two(gPlayerFive, PLAYER_FIVE, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerSix, PLAYER_SIX, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerSeven, PLAYER_SEVEN, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerEight, PLAYER_EIGHT, PLAYER_TWO);
}
} else {
render_kart_particle_on_screen_two(gPlayerOne, PLAYER_ONE, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerTwo, PLAYER_TWO, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerThree, PLAYER_THREE, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerFour, PLAYER_FOUR, PLAYER_TWO);
if (gActiveScreenMode != SCREEN_MODE_3P_4P_SPLITSCREEN) {
render_kart_particle_on_screen_two(gPlayerFive, PLAYER_FIVE, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerSix, PLAYER_SIX, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerSeven, PLAYER_SEVEN, PLAYER_TWO);
render_kart_particle_on_screen_two(gPlayerEight, PLAYER_EIGHT, PLAYER_TWO);
}
}
gPlayersToRenderCount = 0;
}
void render_players_on_screen_three(void) {
gPlayersToRenderCount = 0;
init_render_player(gPlayerOne, camera3, PLAYER_ONE, PLAYER_THREE);
init_render_player(gPlayerTwo, camera3, PLAYER_TWO, PLAYER_THREE);
init_render_player(gPlayerThree, camera3, PLAYER_THREE, PLAYER_THREE);
init_render_player(gPlayerFour, camera3, PLAYER_FOUR, PLAYER_THREE);
if (gPlayersToRenderCount != 0) {
load_kart_texture_and_render_kart_particle_on_screen_three();
}
try_rendering_player(gPlayerOne, PLAYER_ONE, PLAYER_THREE);
try_rendering_player(gPlayerTwo, PLAYER_TWO, PLAYER_THREE);
try_rendering_player(gPlayerThree, PLAYER_THREE, PLAYER_THREE);
try_rendering_player(gPlayerFour, PLAYER_FOUR, PLAYER_THREE);
if (gPlayersToRenderCount != 0) {
// load_kart_texture_and_render_kart_particle_on_screen_three();
render_kart_particle_on_screen_three(gPlayerOne, PLAYER_ONE, PLAYER_THREE);
render_kart_particle_on_screen_three(gPlayerTwo, PLAYER_TWO, PLAYER_THREE);
render_kart_particle_on_screen_three(gPlayerThree, PLAYER_THREE, PLAYER_THREE);
render_kart_particle_on_screen_three(gPlayerFour, PLAYER_FOUR, PLAYER_THREE);
} else {
render_kart_particle_on_screen_three(gPlayerOne, PLAYER_ONE, PLAYER_THREE);
render_kart_particle_on_screen_three(gPlayerTwo, PLAYER_TWO, PLAYER_THREE);
render_kart_particle_on_screen_three(gPlayerThree, PLAYER_THREE, PLAYER_THREE);
render_kart_particle_on_screen_three(gPlayerFour, PLAYER_FOUR, PLAYER_THREE);
}
gPlayersToRenderCount = 0;
}
void render_players_on_screen_four(void) {
gPlayersToRenderCount = 0;
init_render_player(gPlayerOne, camera4, PLAYER_ONE, PLAYER_FOUR);
init_render_player(gPlayerTwo, camera4, PLAYER_TWO, PLAYER_FOUR);
init_render_player(gPlayerThree, camera4, PLAYER_THREE, PLAYER_FOUR);
init_render_player(gPlayerFour, camera4, PLAYER_FOUR, PLAYER_FOUR);
if (gPlayersToRenderCount != 0) {
load_kart_texture_and_render_kart_particle_on_screen_four();
}
try_rendering_player(gPlayerOne, PLAYER_ONE, PLAYER_FOUR);
try_rendering_player(gPlayerTwo, PLAYER_TWO, PLAYER_FOUR);
try_rendering_player(gPlayerThree, PLAYER_THREE, PLAYER_FOUR);
try_rendering_player(gPlayerFour, PLAYER_FOUR, PLAYER_FOUR);
if (gPlayersToRenderCount != 0) {
// load_kart_texture_and_render_kart_particle_on_screen_four();
render_kart_particle_on_screen_four(gPlayerOne, PLAYER_ONE, PLAYER_FOUR);
render_kart_particle_on_screen_four(gPlayerTwo, PLAYER_TWO, PLAYER_FOUR);
render_kart_particle_on_screen_four(gPlayerThree, PLAYER_THREE, PLAYER_FOUR);
render_kart_particle_on_screen_four(gPlayerFour, PLAYER_FOUR, PLAYER_FOUR);
} else {
render_kart_particle_on_screen_four(gPlayerOne, PLAYER_ONE, PLAYER_FOUR);
render_kart_particle_on_screen_four(gPlayerTwo, PLAYER_TWO, PLAYER_FOUR);
render_kart_particle_on_screen_four(gPlayerThree, PLAYER_THREE, PLAYER_FOUR);
render_kart_particle_on_screen_four(gPlayerFour, PLAYER_FOUR, PLAYER_FOUR);
}
gPlayersToRenderCount = 0;
}
void func_80021B0C(void) {
func_8006E7CC(gPlayerOne, 0, 0);
func_8006E7CC(gPlayerTwo, 1, 0);

View File

@ -14,15 +14,9 @@ void func_8001F9E4(Player*, Camera*, s8);
u16 check_player_camera_collision(Player*, Camera*, f32, f32);
u16 func_8001FD78(Player*, f32, f32, f32);
void init_render_player(Player*, Camera*, s8, s8);
void load_kart_texture_and_render_kart_particle_on_screen_one(void);
void load_kart_texture_and_render_kart_particle_on_screen_two(void);
void load_kart_texture_and_render_kart_particle_on_screen_three(void);
void load_kart_texture_and_render_kart_particle_on_screen_four(void);
void load_kart_texture_and_render_kart_particles(s32 screenIdx);
void try_rendering_player(Player*, s8, s8);
void render_players_on_screen_one(void);
void render_players_on_screen_two(void);
void render_players_on_screen_three(void);
void render_players_on_screen_four(void);
void render_players(Camera* camera, s32 screenIdx);
void func_80021B0C(void);
void func_80021C78(void);
void func_80021D40(void);

View File

@ -868,16 +868,25 @@ void func_8003BE30(void) {
}
void func_8003C0F0(void) {
s16 sp5E;
s16 sp5C;
s16 sp5A = 0;
s32 temp;
UNUSED s32 pad[4];
if (gModeSelection == BATTLE) {
func_8000EEDC();
} else if (!IsPodiumCeremony()) {
init_course_path_point();
}
// The tour delays player spawning until the end of the tour
if ((CM_IsTourEnabled() == false) || (gIsEditorPaused == true)) {
spawn_and_set_player_spawns();
}
}
void spawn_and_set_player_spawns(void) {
s16 sp5E;
s16 sp5C;
s16 sp5A = 0;
s32 temp;
if ((!IsPodiumCeremony()) && (gModeSelection != BATTLE)) {
sp5E = (f32) gTrackPaths[0][0].x;
sp5C = (f32) gTrackPaths[0][0].z;
sp5A = (f32) gTrackPaths[0][0].y;
@ -1172,174 +1181,173 @@ void func_8003CD98(Player* player, Camera* camera, s8 playerId, s8 screenId) {
}
}
void func_8003D080(void) {
void spawn_players_and_cameras(void) {
UNUSED s32 pad;
Player* player = &gPlayers[0];
Camera* camera;
// Load textures for balloons and kart shadows
func_8005D290();
// Spawn players
if (gGamestate == ENDING) {
func_8003CD78();
} else {
func_8003C0F0();
}
if (!gDemoMode) {
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
switch (gModeSelection) {
case GRAND_PRIX:
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],
player->rotation[1], 8, 0);
}
break;
u32 mode; // set camera mode
switch (gModeSelection) {
case GRAND_PRIX:
if (gActiveScreenMode == SCREEN_MODE_1P) {
mode = 8;
} else {
mode = 1;
}
break;
case TIME_TRIALS:
mode = 1;
break;
case BATTLE:
mode = 9;
break;
default:
mode = 1;
break;
}
case TIME_TRIALS:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 0);
break;
if (gDemoMode) {
mode = 3;
}
default:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 10, 0);
break;
}
break;
for (size_t i = 0; i < 4; i++) {
D_80164A08[i] = 0;
D_80164498[i] = 0;
}
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
switch (gModeSelection) {
case GRAND_PRIX:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 1);
break;
case BATTLE:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 9, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 9, 1);
break;
default:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 1);
break;
}
break;
case SCREEN_MODE_3P_4P_SPLITSCREEN:
if (gModeSelection == BATTLE) {
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 9, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 9, 1);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 9, 2);
if (gPlayerCountSelection1 == 4) {
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 9, 3);
}
} else {
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 1);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 2);
if (gPlayerCountSelection1 == 4) {
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 3);
}
}
break;
}
if (gActiveScreenMode == SCREEN_MODE_1P) {
spawn_single_player_camera(mode);
} else {
switch (gActiveScreenMode) {
case SCREEN_MODE_1P:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 0);
break;
spawn_multiplayer_cameras(mode);
}
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 1);
break;
// Add freecam, tourcam, and lookbehind cameras
Vec3f spawn = {player->pos[0], player->pos[1], player->pos[2]};
camera = CM_AddFreeCamera(spawn, player->rotation[1], 1);
D_8015F480[PLAYER_ONE].freeCamera = camera;
if (CVarGetInteger("gFreecam", false) == true) {
CM_SetFreeCamera(true);
D_8015F480[PLAYER_ONE].camera = camera;
}
if ((CM_IsTourEnabled() == true) && (gModeSelection == GRAND_PRIX) && (gIsEditorPaused == false)) {
camera = CM_AddTourCamera(spawn, player->rotation[1], 1);
if (NULL != camera) {
CM_AttachCamera(camera, PLAYER_ONE);
D_8015F480[PLAYER_ONE].camera = camera;
D_8015F480[PLAYER_ONE].pendingCamera = NULL;
CM_CameraSetActive(0, false);
CM_ActivateTourCamera(camera);
}
}
}
void spawn_single_player_camera(u32 mode) {
Vec3f spawn = {gPlayerOne->pos[0], gPlayerOne->pos[1], gPlayerOne->pos[2]};
// Technically there should be a default case of mode 10 here. Except it never gets used.
if (gModeSelection == GRAND_PRIX && !gDemoMode) {
if (IsToadsTurnpike()) {
spawn[0] = 0.0f;
spawn[2] = D_80165230[7];
} else {
spawn[0] = (D_80165210[7] + D_80165210[6]) / 2;
spawn[2] = D_80165230[7];
case SCREEN_MODE_3P_4P_SPLITSCREEN:
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 0);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 1);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 2);
player++;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 3);
break;
}
}
// Init freecam
freecam_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 1, 4);
Camera* camera = CM_AddCamera(spawn, gPlayerOne->rotation[1], mode);
if (camera) {
CM_AttachCamera(camera, PLAYER_ONE);
D_8015F480[PLAYER_ONE].camera = camera;
D_8015F480[PLAYER_ONE].raceCamera = camera;
}
switch (gActiveScreenMode) {
camera = CM_AddLookBehindCamera(spawn, gPlayerOne->rotation[1], mode);
if (camera) {
CM_AttachCamera(camera, PLAYER_ONE);
D_8015F480[PLAYER_ONE].lookBehindCamera = camera;
}
}
void spawn_multiplayer_cameras(u32 mode) {
Camera* camera;
for (size_t i = 0; i < gPlayerCountSelection1; i++) {
Vec3f spawn = {gPlayers[i].pos[0], gPlayers[i].pos[1], gPlayers[i].pos[2]};
camera = CM_AddCamera(spawn, gPlayers[i].rotation[1], mode);
if (camera) {
CM_AttachCamera(camera, i);
D_8015F480[i].camera = camera;
D_8015F480[i].raceCamera = camera;
}
}
for (size_t i = 0; i < gPlayerCountSelection1; i++) {
Vec3f spawn = {gPlayers[i].pos[0], gPlayers[i].pos[1], gPlayers[i].pos[2]};
camera = CM_AddLookBehindCamera(spawn, gPlayers[i].rotation[1], mode);
if (camera) {
CM_AttachCamera(camera, i);
D_8015F480[i].lookBehindCamera = camera;
}
}
}
/**
* Loads 8 players per screen in 1p/2p mode
* Loads 4 players per screen in 3p/4p mode
*/
void load_kart_textures(void) {
size_t screens = 0;
switch(gActiveScreenMode) {
case SCREEN_MODE_1P:
func_8003CD98(gPlayerOne, camera1, 0, 0); // sic
func_8003CD98(gPlayerTwo, camera1, 1, 0);
func_8003CD98(gPlayerThree, camera1, 2, 0);
func_8003CD98(gPlayerFour, camera1, 3, 0);
func_8003CD98(gPlayerFive, camera1, 4, 0);
func_8003CD98(gPlayerSix, camera1, 5, 0);
func_8003CD98(gPlayerSeven, camera1, 6, 0);
func_8003CD98(gPlayerEight, camera1, 7, 0);
screens = 1;
break;
case SCREEN_MODE_2P_SPLITSCREEN_HORIZONTAL:
case SCREEN_MODE_2P_SPLITSCREEN_VERTICAL:
func_8003CD98(gPlayerOne, camera1, 0, 0);
func_8003CD98(gPlayerTwo, camera1, 1, 0);
func_8003CD98(gPlayerThree, camera1, 2, 0);
func_8003CD98(gPlayerFour, camera1, 3, 0);
func_8003CD98(gPlayerFive, camera1, 4, 0);
func_8003CD98(gPlayerSix, camera1, 5, 0);
func_8003CD98(gPlayerSeven, camera1, 6, 0);
func_8003CD98(gPlayerEight, camera1, 7, 0);
func_8003CD98(gPlayerOne, camera2, 0, 1);
func_8003CD98(gPlayerTwo, camera2, 1, 1);
func_8003CD98(gPlayerThree, camera2, 2, 1);
func_8003CD98(gPlayerFour, camera2, 3, 1);
func_8003CD98(gPlayerFive, camera2, 4, 1);
func_8003CD98(gPlayerSix, camera2, 5, 1);
func_8003CD98(gPlayerSeven, camera2, 6, 1);
func_8003CD98(gPlayerEight, camera2, 7, 1);
screens = 2;
break;
case SCREEN_MODE_3P_4P_SPLITSCREEN:
func_8003CD98(gPlayerOne, camera1, 0, 0);
func_8003CD98(gPlayerTwo, camera1, 1, 0);
func_8003CD98(gPlayerThree, camera1, 2, 0);
func_8003CD98(gPlayerFour, camera1, 3, 0);
func_8003CD98(gPlayerOne, camera2, 0, 1);
func_8003CD98(gPlayerTwo, camera2, 1, 1);
func_8003CD98(gPlayerThree, camera2, 2, 1);
func_8003CD98(gPlayerFour, camera2, 3, 1);
func_8003CD98(gPlayerOne, camera3, 0, 2);
func_8003CD98(gPlayerTwo, camera3, 1, 2);
func_8003CD98(gPlayerThree, camera3, 2, 2);
func_8003CD98(gPlayerFour, camera3, 3, 2);
func_8003CD98(gPlayerOne, camera4, 0, 3);
func_8003CD98(gPlayerTwo, camera4, 1, 3);
func_8003CD98(gPlayerThree, camera4, 2, 3);
func_8003CD98(gPlayerFour, camera4, 3, 3);
screens = 4;
break;
}
static const size_t playerCounts[4] = { 8, 8, 4, 4 };
for (size_t i = 0; i < screens; i++) {
for (size_t ply = 0; ply < playerCounts[i]; ply++) {
func_8003CD98(&gPlayers[ply], D_8015F480[i].camera, ply, i);
}
}
}
void func_8003DB5C(void) {
Player* player = gPlayerOne;
Camera* camera;
s32 playerId;
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 0);
camera_init(player->pos[0], player->pos[1], player->pos[2], player->rotation[1], 3, 1);
Vec3f spawn = {player->pos[0], player->pos[1], player->pos[2]};
camera = CM_AddCamera(spawn, player->rotation[1], 3);
if (camera) {
CM_AttachCamera(camera, PLAYER_ONE);
}
camera = CM_AddCamera(spawn, player->rotation[1], 3);
if (camera) {
CM_AttachCamera(camera, PLAYER_ONE);
}
for (playerId = 0; playerId < NUM_PLAYERS; playerId++, player++) {
load_kart_palette(player, playerId, 1, 0);

View File

@ -9,6 +9,7 @@
void spawn_player(Player*, s8, f32, f32, f32, f32, u16, s16);
void func_80039AE4(void);
void func_80039DA4(void);
void spawn_and_set_player_spawns(void);
void spawn_players_gp_one_player(f32*, f32*, f32);
void spawn_players_versus_one_player(f32*, f32*, f32);
void spawn_players_gp_two_player(f32* arg0, f32* arg1, f32);
@ -22,7 +23,10 @@ void func_8003BE30(void);
void func_8003C0F0(void);
void func_8003CD78(void);
void func_8003CD98(Player*, Camera*, s8, s8);
void func_8003D080(void);
void spawn_players_and_cameras(void);
void spawn_single_player_camera(u32 mode);
void spawn_multiplayer_cameras(u32 mode);
void load_kart_textures(void);
void func_8003DB5C(void);
extern f32 D_80165210[];

View File

@ -2532,27 +2532,27 @@ void func_80078C70(s32 arg0) {
case 0: /* switch 1 */
sp1C = 0;
camera = camera1;
D_8018D200 = gCameraZoom[0] + 40.0f;
D_8018D200 = gCameraFOV[0] + 40.0f;
break;
case 1: /* switch 1 */
sp1C = 0;
camera = camera1;
D_8018D200 = gCameraZoom[0] + 40.0f;
D_8018D200 = gCameraFOV[0] + 40.0f;
break;
case 2: /* switch 1 */
camera = camera2;
sp1C = D_8018D1F0;
D_8018D200 = gCameraZoom[1] + 40.0f;
D_8018D200 = gCameraFOV[1] + 40.0f;
break;
case 3: /* switch 1 */
sp1C = 0;
camera = camera1;
D_8018D200 = gCameraZoom[0] + 40.0f;
D_8018D200 = gCameraFOV[0] + 40.0f;
break;
case 4: /* switch 1 */
camera = camera2;
sp1C = D_8018D1F0;
D_8018D200 = gCameraZoom[1] + 40.0f;
D_8018D200 = gCameraFOV[1] + 40.0f;
break;
}