diff --git a/src/engine/HM_Intro.cpp b/src/engine/HM_Intro.cpp index e5fd4e03b..f7c33d3b4 100644 --- a/src/engine/HM_Intro.cpp +++ b/src/engine/HM_Intro.cpp @@ -90,8 +90,8 @@ void HarbourMastersIntro::HM_TickIntro() { gFadeModeSelection = FADE_MODE_LOGO; } - find_and_set_tile_size((uintptr_t) ((void*)mat_water_water1), 0, _water); - find_and_set_tile_size((uintptr_t) ((void*)mat_water_water2), _water, 0);; + scroll_texture_interpolated(scroll, (const char*)mat_water_water1, 0, 1); + scroll_texture_interpolated(scroll2, (const char*)mat_water_water2, 1, 0); } void HarbourMastersIntro::Bob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) { diff --git a/src/engine/HM_Intro.h b/src/engine/HM_Intro.h index 1f9b142e9..28d31486b 100644 --- a/src/engine/HM_Intro.h +++ b/src/engine/HM_Intro.h @@ -22,6 +22,8 @@ class HarbourMastersIntro { void HM_TickIntro(); void HM_DrawIntro(); private: + Gfx scroll[3]; + Gfx scroll2[3]; void Setup(); void Sync(); void Bob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed); diff --git a/src/engine/tracks/BansheeBoardwalk.cpp b/src/engine/tracks/BansheeBoardwalk.cpp index 4614f6852..928f4a020 100644 --- a/src/engine/tracks/BansheeBoardwalk.cpp +++ b/src/engine/tracks/BansheeBoardwalk.cpp @@ -149,6 +149,7 @@ void BansheeBoardwalk::Load() { parse_track_displaylists((TrackSections*) LOAD_ASSET_RAW(d_course_banshee_boardwalk_track_sections)); func_80295C6C(); find_vtx_and_set_colours((Gfx*) d_course_banshee_boardwalk_packed_dl_878, 128, 0, 0, 0); + scroll_texture_interpolated(scroll, d_course_banshee_boardwalk_dl_B278, 0, 2); } void BansheeBoardwalk::BeginPlay() { @@ -307,15 +308,6 @@ void BansheeBoardwalk::DrawCredits() { gSPDisplayList(gDisplayListHead++, (Gfx*) (d_course_banshee_boardwalk_dl_B308)); } -void BansheeBoardwalk::ScrollingTextures() { - D_802B87BC++; - - if (D_802B87BC >= 0x100) { - D_802B87BC = 0; - } - find_and_set_tile_size((uintptr_t) LOAD_ASSET_RAW(d_course_banshee_boardwalk_dl_B278), 0, D_802B87BC); -} - void BansheeBoardwalk::Waypoints(Player* player, int8_t playerId) { s16 waypoint = gNearestPathPointByPlayerId[playerId]; if ((waypoint >= 0x12C) && (waypoint < 0x13C)) { diff --git a/src/engine/tracks/BansheeBoardwalk.h b/src/engine/tracks/BansheeBoardwalk.h index 2b13ddf24..cca239b10 100644 --- a/src/engine/tracks/BansheeBoardwalk.h +++ b/src/engine/tracks/BansheeBoardwalk.h @@ -34,9 +34,10 @@ class BansheeBoardwalk : public Track { virtual void WhatDoesThisDoAI(Player* player, int8_t playerId) override; virtual void Draw(ScreenContext*) override; virtual void DrawCredits() override; - virtual void ScrollingTextures() override; virtual void Waypoints(Player*, int8_t) override; virtual void DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; virtual void CreditsSpawnActors() override; virtual void Destroy() override; +private: + Gfx scroll[3]; }; diff --git a/src/engine/tracks/DKJungle.cpp b/src/engine/tracks/DKJungle.cpp index 11e8cf6c1..fe5c8a0ea 100644 --- a/src/engine/tracks/DKJungle.cpp +++ b/src/engine/tracks/DKJungle.cpp @@ -132,6 +132,15 @@ void DKJungle::Load() { func_80295C6C(); // d_course_dks_jungle_parkway_packed_dl_3FA8 find_vtx_and_set_colours((Gfx*) d_course_dks_jungle_parkway_packed_dl_3FA8, 120, 255, 255, 255); + + // These can share the same writableGfx because they use the same settings + scroll_texture_interpolated(scroll, d_course_dks_jungle_parkway_packed_dl_3DD0, 0, 4); + scroll_texture_interpolated(scroll, d_course_dks_jungle_parkway_packed_dl_3E40, 0, 4); + scroll_texture_interpolated(scroll, d_course_dks_jungle_parkway_packed_dl_3EB0, 0, 4); + scroll_texture_interpolated(scroll, d_course_dks_jungle_parkway_packed_dl_3F30, 0, 4); + scroll_texture_interpolated(scroll, d_course_dks_jungle_parkway_packed_dl_36A8, 0, 4); + + scroll_texture_interpolated(scroll2, d_course_dks_jungle_parkway_packed_dl_9880, 0, -40); } f32 DKJungle::GetWaterLevel(FVector pos, Collision* collision) { @@ -302,26 +311,6 @@ void DKJungle::Waypoints(Player* player, int8_t playerId) { } void DKJungle::ScrollingTextures() { - D_802B87BC += 2; - if (D_802B87BC > 255) { - D_802B87BC = 0; - } - // d_course_dks_jungle_parkway_packed_dl_3DD0 - find_and_set_tile_size((uintptr_t) (Gfx*) d_course_dks_jungle_parkway_packed_dl_3DD0, 0, D_802B87BC); - // d_course_dks_jungle_parkway_packed_dl_3E40 - find_and_set_tile_size((uintptr_t) (Gfx*) d_course_dks_jungle_parkway_packed_dl_3E40, 0, D_802B87BC); - // d_course_dks_jungle_parkway_packed_dl_3EB0 - find_and_set_tile_size((uintptr_t) (Gfx*) d_course_dks_jungle_parkway_packed_dl_3EB0, 0, D_802B87BC); - // d_course_dks_jungle_parkway_packed_dl_3F30 - find_and_set_tile_size((uintptr_t) (Gfx*) d_course_dks_jungle_parkway_packed_dl_3F30, 0, D_802B87BC); - // d_course_dks_jungle_parkway_packed_dl_36A8 - find_and_set_tile_size((uintptr_t) (Gfx*) d_course_dks_jungle_parkway_packed_dl_36A8, 0, D_802B87BC); - D_802B87C4 -= 20; - if (D_802B87C4 < 0) { - D_802B87C4 = 0xFF; - } - // d_course_dks_jungle_parkway_packed_dl_9880 - find_and_set_tile_size((uintptr_t) (Gfx*) d_course_dks_jungle_parkway_packed_dl_9880, 0, D_802B87C4); evaluate_collision_players_palm_trees(); } diff --git a/src/engine/tracks/DKJungle.h b/src/engine/tracks/DKJungle.h index 6e3d94491..73dd397a7 100644 --- a/src/engine/tracks/DKJungle.h +++ b/src/engine/tracks/DKJungle.h @@ -41,4 +41,7 @@ class DKJungle : public Track { virtual void DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; virtual void CreditsSpawnActors() override; virtual void Destroy() override; +private: + Gfx scroll[3]; + Gfx scroll2[3]; }; diff --git a/src/engine/tracks/KoopaTroopaBeach.cpp b/src/engine/tracks/KoopaTroopaBeach.cpp index 63bf80de7..ff3d321dc 100644 --- a/src/engine/tracks/KoopaTroopaBeach.cpp +++ b/src/engine/tracks/KoopaTroopaBeach.cpp @@ -136,6 +136,12 @@ void KoopaTroopaBeach::Load() { find_vtx_and_set_colours((Gfx*) d_course_koopa_troopa_beach_packed_dl_A540, 150, 255, 255, 255); find_vtx_and_set_colours((Gfx*) d_course_koopa_troopa_beach_packed_dl_9E70, 150, 255, 255, 255); find_vtx_and_set_colours((Gfx*) d_course_koopa_troopa_beach_packed_dl_358, 150, 255, 255, 255); + + // waterfall animation + scroll_texture_interpolated(scroll, d_course_koopa_troopa_beach_packed_dl_9D58, 0, 18); + scroll_texture_interpolated(scroll2, d_course_koopa_troopa_beach_packed_dl_9CD0, 0, 6); + // Waterfall bubbling effect? + scroll_texture_interpolated(scroll3, d_course_koopa_troopa_beach_packed_dl_2E8, 0, 0); } void KoopaTroopaBeach::BeginPlay() { @@ -261,29 +267,15 @@ void KoopaTroopaBeach::ScrollingTextures() { // clang-format on Props.WaterLevel += gWaterVelocity; - D_802B87BC += 9; - if (D_802B87BC > 255) { - D_802B87BC = 0; - } - D_802B87C4 += 3; - if (D_802B87C4 > 255) { - D_802B87C4 = 0; - } - // waterfall animation - // d_course_koopa_troopa_beach_packed_dl_9D58 - find_and_set_tile_size((uintptr_t) d_course_koopa_troopa_beach_packed_dl_9D58, 0, D_802B87BC); - // d_course_koopa_troopa_beach_packed_dl_9CD0 - find_and_set_tile_size((uintptr_t) d_course_koopa_troopa_beach_packed_dl_9CD0, 0, D_802B87C4); D_802B87CC = random_int(300) / 40; if (D_802B87C8 < 0) { D_802B87C8 = random_int(300) / 40; } else { D_802B87C8 = -(random_int(300) / 40); } - // Waterfall bubbling effect? (unused) - // d_course_koopa_troopa_beach_packed_dl_2E8 - find_and_set_tile_size((uintptr_t) d_course_koopa_troopa_beach_packed_dl_2E8, D_802B87C8, D_802B87CC); + // Waterfall bubbling effect? + scroll3[0].words.w1 = ((uintptr_t) (uint32_t) D_802B87C8 << 32) | (uint32_t)D_802B87CC; } void KoopaTroopaBeach::DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) { diff --git a/src/engine/tracks/KoopaTroopaBeach.h b/src/engine/tracks/KoopaTroopaBeach.h index 15ae3e829..e817fe4ec 100644 --- a/src/engine/tracks/KoopaTroopaBeach.h +++ b/src/engine/tracks/KoopaTroopaBeach.h @@ -40,4 +40,8 @@ class KoopaTroopaBeach : public Track { virtual void ScrollingTextures() override; virtual void DrawWater(ScreenContext* screen, uint16_t pathCounter, uint16_t cameraRot, uint16_t playerDirection) override; virtual void Destroy() override; +private: + Gfx scroll[3]; + Gfx scroll2[3]; + Gfx scroll3[3]; }; diff --git a/src/engine/tracks/RoyalRaceway.cpp b/src/engine/tracks/RoyalRaceway.cpp index 510518e5e..01bc9e507 100644 --- a/src/engine/tracks/RoyalRaceway.cpp +++ b/src/engine/tracks/RoyalRaceway.cpp @@ -123,6 +123,8 @@ void RoyalRaceway::Load() { } parse_track_displaylists((TrackSections*)LOAD_ASSET_RAW(d_course_royal_raceway_addr)); func_80295C6C(); + scroll_texture_interpolated(scroll, d_course_royal_raceway_packed_dl_A6A8, 0, -40); + scroll_texture_interpolated(scroll2, d_course_royal_raceway_packed_dl_A648, 0, -40); } void RoyalRaceway::BeginPlay() { @@ -241,13 +243,3 @@ void RoyalRaceway::Waypoints(Player* player, int8_t playerId) { } } -void RoyalRaceway::ScrollingTextures() { - D_802B87BC -= 20; - if (D_802B87BC < 0) { - D_802B87BC = 0xFF; - } - // d_course_royal_raceway_packed_dl_A6A8 - find_and_set_tile_size((uintptr_t) d_course_royal_raceway_packed_dl_A6A8, 0, D_802B87BC); - // d_course_royal_raceway_packed_dl_A648 - find_and_set_tile_size((uintptr_t) d_course_royal_raceway_packed_dl_A648, 0, D_802B87BC); -} diff --git a/src/engine/tracks/RoyalRaceway.h b/src/engine/tracks/RoyalRaceway.h index 095330b14..c3c34b40e 100644 --- a/src/engine/tracks/RoyalRaceway.h +++ b/src/engine/tracks/RoyalRaceway.h @@ -31,6 +31,8 @@ class RoyalRaceway : public Track { virtual void SetStaffGhost() override; virtual void Draw(ScreenContext*) override; virtual void DrawCredits() override; - virtual void ScrollingTextures() override; virtual void Waypoints(Player* player, int8_t playerId) override; +private: + Gfx scroll[3]; + Gfx scroll2[3]; }; diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 8bbd65cab..663272a5a 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -405,10 +405,17 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vectorHandleEvents(); interpreter->mInterpolationIndex = 0; + interpreter->mTargetFps = CVarGetInteger("gInterpolationFPS", 30); + interpreter->mInterpolationCount = mtx_replacements.size(); for (const auto& m : mtx_replacements) { wnd->DrawAndRunGraphicsCommands(Commands, m); interpreter->mInterpolationIndex++; + interpreter->mFpsIndex++; + } + + if (interpreter->mFpsIndex >= interpreter->mTargetFps) { + interpreter->mFpsIndex = 0; } bool curAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0); diff --git a/src/racing/collision.c b/src/racing/collision.c index 6d0d7717d..2840c1f78 100644 --- a/src/racing/collision.c +++ b/src/racing/collision.c @@ -2161,27 +2161,39 @@ bool is_cull_box(const char* filePath) { } /** - * Search for G_SETTILESIZE and set its args. + * This function finds a G_SETTILESIZE command and hooks it. + * Then writes the interpolation command into the provided gfx array + * The game continues as normal after leaving the writableDList + * + * @arg gfxAsset the model needing interpolated scrolling textures + * @arg writableDList - Provide Gfx myGfx[3]. This memory MUST stay alive for the lifetime of the object */ -void find_and_set_tile_size(uintptr_t addr, s32 uls, s32 ult) { - Gfx* gfx = (Gfx*) addr; +void scroll_texture_interpolated(Gfx* writableDList, const char* gfxAsset, s32 stepX, s32 stepY) { + int8_t opcode = 0; + if ((NULL == writableDList) || (NULL == gfxAsset)) { + return; + } + + Gfx* gfx = (Gfx*) gfxAsset; if (GameEngine_OTRSigCheck(gfx)) { gfx = (Gfx*) ResourceGetDataByName(gfx); } - u32 opcode; - - uls = (uls << 12) & 0xFFF000; - ult &= 0xFFF; - - while (true) { - - opcode = GFX_GET_OPCODE(gfx->words.w0); - - if (opcode == (u32) G_ENDDL << 24) { - break; - } else if (opcode == (u32) (G_SETTILESIZE << 24)) { - gfx->words.w0 = (G_SETTILESIZE << 24) | uls | ult; + while ((opcode = GFX_GET_OPCODE(gfx->words.w0) >> 24) != G_ENDDL) { + if (opcode == (int8_t)G_SETTILESIZE) { + // Get values from the old tile size command + int32_t tile = _SHIFTR(gfx->words.w1, 24, 12); + int32_t uls = _SHIFTR(gfx->words.w0, 12, 12); + int32_t ult = _SHIFTR(gfx->words.w0, 0, 12); + int32_t lrs = _SHIFTR(gfx->words.w1, 12, 12); + int32_t lrt = _SHIFTR(gfx->words.w1, 0, 12); + + // Write over old command to point to the new writeableDList + __gSPDisplayList(gfx, &writableDList[0]); + + // Write DL data into writableDList. gDPScrollTexture takes up two Gfx + gDPScrollTexture(&writableDList[0], tile, uls, ult, lrs, lrt, stepX, stepY); + gSPEndDisplayList(&writableDList[2]); break; } gfx++; diff --git a/src/racing/collision.h b/src/racing/collision.h index 4720daf55..261e28b84 100644 --- a/src/racing/collision.h +++ b/src/racing/collision.h @@ -34,9 +34,9 @@ void generate_collision_grid(void); void generate_collision_mesh_with_defaults(Gfx*); void generate_collision_mesh_with_default_section_id(Gfx*, s8); void generate_collision_mesh(Gfx*, s8, u16); -void find_and_set_tile_size(uintptr_t, s32, s32); void set_vertex_colours(uintptr_t, u32, s32, s8, u8, u8, u8); void find_vtx_and_set_colours(Gfx*, s8, u8, u8, u8); void subtract_scaled_vector(Vec3f, f32, Vec3f); +void scroll_texture_interpolated(Gfx* writableDList, const char* gfxAsset, s32 stepX, s32 stepY); #endif