diff options
| author | Nicholas Estelami <NEstelami@users.noreply.github.com> | 2025-03-28 03:25:11 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-28 04:25:11 -0300 |
| commit | 30ec4720c06dd3418641226a6d320067f2706700 (patch) | |
| tree | 39a6a83b02325b4a027d260854a84f50b5abcfcc | |
| parent | ea4254984225884476c66da8563166505bfd4aee (diff) | |
Floor Scrolling Interpolation (#176)
* Floor Scrolling Interpolation
* Scrolling Improvements
* Fix scroll stutter
* bump LUS & Torch
* missing prototype
---------
Co-authored-by: Sonic Dreamcaster <alejandro.asenjo88@gmail.com>
| -rw-r--r-- | include/gfx.h | 8 | ||||
| -rw-r--r-- | include/sf64context.h | 1 | ||||
| -rw-r--r-- | src/engine/fox_bg.c | 152 | ||||
| -rw-r--r-- | src/engine/fox_context.c | 1 | ||||
| -rw-r--r-- | src/engine/fox_game.c | 2 | ||||
| -rw-r--r-- | src/engine/fox_hud.c | 1 | ||||
| -rw-r--r-- | src/port/Engine.cpp | 12 | ||||
| -rw-r--r-- | src/port/Engine.h | 5 | ||||
| -rw-r--r-- | src/port/GBIMiddleware.cpp | 9 |
9 files changed, 170 insertions, 21 deletions
diff --git a/include/gfx.h b/include/gfx.h index 3e22a976..99eb5252 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -26,6 +26,14 @@ ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ } while (0) +#define gDPSetupTile2(pkt, fmt, siz, width, height, dw, dh, \ + cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPTileSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, 0,\ + G_TX_RENDERTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ +} + #define gDPSetupTile(pkt, fmt, siz, width, height, dw, dh, \ cms, cmt, masks, maskt, shifts, shiftt) \ { \ diff --git a/include/sf64context.h b/include/sf64context.h index 90eb3079..e4bfaf61 100644 --- a/include/sf64context.h +++ b/include/sf64context.h @@ -65,6 +65,7 @@ extern f32 gSavedPathProgress; extern UNK_TYPE F_80177CB8; extern f32 gWaterLevel; extern f32 gPathGroundScroll; +extern f32 gLastPathTexScroll; extern f32 gPathTexScroll; extern f32 gPathVelZ; extern f32 gPathProgress; diff --git a/src/engine/fox_bg.c b/src/engine/fox_bg.c index ac9683d6..31c6c59f 100644 --- a/src/engine/fox_bg.c +++ b/src/engine/fox_bg.c @@ -27,6 +27,8 @@ #include "water_effect.inc" +#include <libultra/gbi.h> + f32 gWarpZoneBgAlpha; u8 D_bg_8015F964; // related to water surfaces f32 D_bg_8015F968; // heat shimmer effect for SO and TI? @@ -1386,10 +1388,32 @@ void Background_DrawGround(void) { if (gLevelMode == LEVELMODE_ON_RAILS) { gDPSetTextureImage(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, SEGMENTED_TO_VIRTUAL(D_CO_601B6C0)); - temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); // 0.64f / 3.0f - temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); - gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + int interpolatedFrames = GameEngine_GetInterpolationFrameCount(); + + temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); // 0.64f / 3.0f + temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); + + float xScroll = temp_fv0; + float yScroll = temp_s0; + + float inc = (2.0f * (gPathTexScroll - gLastPathTexScroll) * 0.2133333f) / (float)interpolatedFrames; + + for (int i = 0; i < interpolatedFrames; i++) + { + gDPSetInterpolation(gMasterDisp++, i); + + gDPSetupTile2(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSizeInterp(gMasterDisp, G_TX_RENDERTILE, xScroll, yScroll, 32 << 2, 32 << 2); + + gMasterDisp += 3; + + yScroll += inc >= 0 ? inc : -inc; + yScroll = fabs(Math_ModF(yScroll, 128.0f)); + } + switch (gGroundSurface) { case SURFACE_GRASS: gDPLoadTileTexture(gMasterDisp++, D_CO_601B6C0, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32); @@ -1482,10 +1506,34 @@ void Background_DrawGround(void) { break; } gDPSetTextureImage(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, sp1C4); - temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); - temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); - gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + //gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, + //G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + int interpolatedFrames = GameEngine_GetInterpolationFrameCount(); + + temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); + temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); + + float xScroll = temp_fv0; + float yScroll = temp_s0; + + float inc = (2.0f * (gPathTexScroll - gLastPathTexScroll) * 0.2133333f) / (float)interpolatedFrames; + + for (int i = 0; i < interpolatedFrames; i++) + { + gDPSetInterpolation(gMasterDisp++, i); + + gDPSetupTile2(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSizeInterp(gMasterDisp, G_TX_RENDERTILE, xScroll, yScroll, 32 << 2, 32 << 2); + + gMasterDisp += 3; + + yScroll += inc >= 0 ? inc : -inc; + yScroll = fabs(Math_ModF(yScroll, 128.0f)); + } // CENTER FAR Matrix_Push(&gGfxMatrix); @@ -1569,10 +1617,31 @@ void Background_DrawGround(void) { // gPathTexScroll -= (32.0f * 36.7f) / 2.0f; // } gDPSetTextureImage(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, sp1C4); - temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); // 0.64f / 3.0f - temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); - gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + int interpolatedFrames = GameEngine_GetInterpolationFrameCount(); + + temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); // 0.64f / 3.0f + temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); + + float xScroll = temp_fv0; + float yScroll = temp_s0; + + float inc = (2.0f * (gPathTexScroll - gLastPathTexScroll) * 0.2133333f) / (float)interpolatedFrames; + + for (int i = 0; i < interpolatedFrames; i++) + { + gDPSetInterpolation(gMasterDisp++, i); + + gDPSetupTile2(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSizeInterp(gMasterDisp, G_TX_RENDERTILE, xScroll, yScroll, 32 << 2, 32 << 2); + + gMasterDisp += 3; + + yScroll += inc >= 0 ? inc : -inc; + yScroll = fabs(Math_ModF(yScroll, 128.0f)); + } // Original Display (Center) Matrix_Push(&gGfxMatrix); @@ -1641,11 +1710,32 @@ void Background_DrawGround(void) { gDPLoadTileTexture(gMasterDisp++, SEGMENTED_TO_VIRTUAL(D_AQ_600AB68), G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32); gDPSetTextureImage(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, SEGMENTED_TO_VIRTUAL(D_AQ_600AB68)); - temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); - temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); - gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + int interpolatedFrames = GameEngine_GetInterpolationFrameCount(); + + temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); + temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); + + float xScroll = temp_fv0; + float yScroll = temp_s0; + + float inc = (2.0f * (gPathTexScroll - gLastPathTexScroll) * 0.2133333f) / (float)interpolatedFrames; + + for (int i = 0; i < interpolatedFrames; i++) + { + gDPSetInterpolation(gMasterDisp++, i); + + gDPSetupTile2(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSizeInterp(gMasterDisp, G_TX_RENDERTILE, xScroll, yScroll, 32 << 2, 32 << 2); + + gMasterDisp += 3; + + yScroll += inc >= 0 ? inc : -inc; + yScroll = fabs(Math_ModF(yScroll, 128.0f)); + } + // CENTER FAR Matrix_Push(&gGfxMatrix); Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -3000.0f, MTXF_APPLY); @@ -1695,10 +1785,32 @@ void Background_DrawGround(void) { gDPLoadTileTexture(gMasterDisp++, SEGMENTED_TO_VIRTUAL(D_AQ_602ACC0), G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32); gDPSetTextureImage(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, SEGMENTED_TO_VIRTUAL(D_AQ_602ACC0)); - temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); - temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); - gDPSetupTile(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + int interpolatedFrames = GameEngine_GetInterpolationFrameCount(); + + temp_s0 = fabsf(Math_ModF(2.0f * (gPathTexScroll * 0.2133333f), 128.0f)); + temp_fv0 = Math_ModF((10000.0f - gPlayer[gPlayerNum].xPath) * 0.32f, 128.0f); + + float xScroll = temp_fv0; + float yScroll = temp_s0; + + float inc = (2.0f * (gPathTexScroll - gLastPathTexScroll) * 0.2133333f) / (float)interpolatedFrames; + + for (int i = 0; i < interpolatedFrames; i++) + { + gDPSetInterpolation(gMasterDisp++, i); + + gDPSetupTile2(gMasterDisp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, temp_fv0, temp_s0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + + gDPSetTileSizeInterp(gMasterDisp, G_TX_RENDERTILE, xScroll, yScroll, 32 << 2, 32 << 2); + + gMasterDisp += 3; + + yScroll += inc >= 0 ? inc : -inc; + yScroll = fabs(Math_ModF(yScroll, 128.0f)); + } + if (gAqDrawMode != 0) { RCP_SetupDL(&gMasterDisp, SETUPDL_47); } else { diff --git a/src/engine/fox_context.c b/src/engine/fox_context.c index b5fa2454..25b1ec72 100644 --- a/src/engine/fox_context.c +++ b/src/engine/fox_context.c @@ -77,6 +77,7 @@ f32 gSavedPathProgress; UNK_TYPE F_80177CB8; f32 gWaterLevel; f32 gPathGroundScroll; +f32 gLastPathTexScroll; f32 gPathTexScroll; f32 gPathVelZ; f32 gPathProgress; diff --git a/src/engine/fox_game.c b/src/engine/fox_game.c index 25c2e770..a0266dc6 100644 --- a/src/engine/fox_game.c +++ b/src/engine/fox_game.c @@ -612,6 +612,8 @@ void Game_Update(void) { // @port: @event: Call GamePostUpdateEvent CALL_EVENT(GamePostUpdateEvent); + + gLastPathTexScroll = gPathTexScroll; } } diff --git a/src/engine/fox_hud.c b/src/engine/fox_hud.c index 377a5ae4..2b30ab7b 100644 --- a/src/engine/fox_hud.c +++ b/src/engine/fox_hud.c @@ -6260,6 +6260,7 @@ void Venom1_LevelStart2(Player* player) { player->pos.x += player->vel.x; player->pos.y += player->vel.y; + gLastPathTexScroll = gPathTexScroll; gPathTexScroll += player->vel.z; player->bankAngle = player->rot.z + player->zRotBank + player->zRotBarrelRoll; diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 4da6fd77..e0307752 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -452,8 +452,11 @@ void GameEngine::RunCommands(Gfx* Commands, const std::vector<std::unordered_map // Process window events for resize, mouse, keyboard events wnd->HandleEvents(); + gInterpolationIndex = 0; + for (const auto& m : mtx_replacements) { wnd->DrawAndRunGraphicsCommands(Commands, m); + gInterpolationIndex++; } bool curAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0); @@ -538,6 +541,15 @@ uint32_t GameEngine::GetInterpolationFPS() { CVarGetInteger("gInterpolationFPS", 60)); } +uint32_t GameEngine::GetInterpolationFrameCount() +{ + return ceil((float)GetInterpolationFPS() / 30.0f); +} + +extern "C" uint32_t GameEngine_GetInterpolationFrameCount() { + return GameEngine::GetInterpolationFrameCount(); +} + void GameEngine::ShowMessage(const char* title, const char* message, SDL_MessageBoxFlags type) { #if defined(__SWITCH__) SPDLOG_ERROR(message); diff --git a/src/port/Engine.h b/src/port/Engine.h index 26f9109f..43dbf066 100644 --- a/src/port/Engine.h +++ b/src/port/Engine.h @@ -39,7 +39,8 @@ class GameEngine { static void AudioExit(); static void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements); static void Destroy(); - static uint32_t GetInterpolationFPS(); + static uint32_t GetInterpolationFPS(); + static uint32_t GetInterpolationFrameCount(); static void ProcessGfxCommands(Gfx* commands); static int ShowYesNoBox(const char* title, const char* box); @@ -80,5 +81,7 @@ uint32_t OTRGetGameRenderWidth(); uint32_t OTRGetGameRenderHeight(); void* GameEngine_Malloc(size_t size); void GameEngine_GetTextureInfo(const char* path, int32_t* width, int32_t* height, float* scale, bool* custom); +void gDPSetTileSizeInterp(Gfx* pkt, int t, float uls, float ult, float lrs, float lrt); +uint32_t GameEngine_GetInterpolationFrameCount(); #define memalloc(size) GameEngine_Malloc(size) #endif
\ No newline at end of file diff --git a/src/port/GBIMiddleware.cpp b/src/port/GBIMiddleware.cpp index 5e35e312..e0355a6d 100644 --- a/src/port/GBIMiddleware.cpp +++ b/src/port/GBIMiddleware.cpp @@ -20,6 +20,15 @@ extern "C" void gSPDisplayList(Gfx* pkt, Gfx* dl) { __gSPDisplayList(pkt, dl); } +extern "C" void gDPSetTileSizeInterp(Gfx* pkt, int t, float uls, float ult, float lrs, float lrt) +{ + __gDPSetTileSizeInterp(pkt++, t, 0, 0, 0, 0); + memcpy(&pkt[0].words.w0, &uls, sizeof(float)); + memcpy(&pkt[0].words.w1, &ult, sizeof(float)); + memcpy(&pkt[1].words.w0, &lrs, sizeof(float)); + memcpy(&pkt[1].words.w1, &lrt, sizeof(float)); +} + extern "C" void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0) { if (GameEngine_OTRSigCheck((char*)v) == 1) { |
