diff --git a/src/engine/graph_node.h b/src/engine/graph_node.h index 27b40957..08b99f03 100644 --- a/src/engine/graph_node.h +++ b/src/engine/graph_node.h @@ -1,8 +1,10 @@ #ifndef GRAPH_NODE_H #define GRAPH_NODE_H +#ifndef __cplusplus #include #include +#endif #include "types.h" #include "game/memory.h" diff --git a/src/game/game_init.c b/src/game/game_init.c index a90cf0ff..af42de80 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -327,6 +327,7 @@ void render_init(void) { init_rcp(); clear_framebuffer(0); end_master_display_list(); + exec_display_list(&gGfxPool->spTask); sRenderingFramebuffer++; @@ -358,6 +359,9 @@ void display_and_vsync(void) { gGoddardVblankCallback(); gGoddardVblankCallback = NULL; } + if(GfxDebuggerIsDebuggingRequested()) { + GfxDebuggerDebugDisplayList(gGfxPool->spTask.task.t.data_ptr); + } exec_display_list(&gGfxPool->spTask); profiler_log_thread5_time(AFTER_DISPLAY_LISTS); osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_NOBLOCK); @@ -647,6 +651,11 @@ void thread5_game_loop(void) { } void thread5_iteration(void){ + if (GfxDebuggerIsDebugging()) { + exec_display_list(&gGfxPool->spTask); + return; + } + // If the reset timer is active, run the process to reset the game. if (gResetTimer != 0) { draw_reset_bars(); diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp index 8703f1c4..cd380462 100644 --- a/src/port/Engine.cpp +++ b/src/port/Engine.cpp @@ -18,9 +18,11 @@ #include extern "C" { +#include "sm64.h" #include "audio/external.h" #include "audio/internal.h" #include "game/ingame_menu.h" +float gInterpolationStep = 0.0f; } GameEngine* GameEngine::Instance; @@ -93,16 +95,6 @@ void GameEngine::StartFrame() const{ this->context->GetWindow()->StartFrame(); } -void GameEngine::RunCommands(Gfx* Commands) { - gfx_run(Commands, {}); - gfx_end_frame(); - - if (ShouldClearTextureCacheAtEndOfFrame) { - gfx_texture_cache_clear(); - ShouldClearTextureCacheAtEndOfFrame = false; - } -} - void GameEngine::ProcessFrame(void (*run_one_game_iter)()) const { this->context->GetWindow()->MainLoop(run_one_game_iter); } @@ -217,6 +209,62 @@ uint32_t GameEngine::GetGameVersion() { return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[0]; } +void GameEngine::RunCommands(Gfx* Commands) { + gfx_run(Commands, {}); + gfx_end_frame(); + + if (ShouldClearTextureCacheAtEndOfFrame) { + gfx_texture_cache_clear(); + ShouldClearTextureCacheAtEndOfFrame = false; + } +} + +void GameEngine::PatchInterpolations() { + mtx_patch_interpolated(); + patch_screen_transition_interpolated(); + patch_title_screen_scales(); + patch_interpolated_dialog(); + patch_interpolated_hud(); + patch_interpolated_paintings(); + patch_interpolated_bubble_particles(); + patch_interpolated_snow_particles(); +} + +void GameEngine::ProcessGfxCommands(Gfx* commands) { + int target_fps = GetInterpolationFPS(); + static int last_fps; + static int time; + int fps = target_fps; + int original_fps = 30; + + if (target_fps == 30 || original_fps > target_fps) { + fps = original_fps; + } + + if (last_fps != fps) { + time = 0; + } + + int next_original_frame = fps; + while (time + original_fps <= next_original_frame) { + time += original_fps; + if (time != next_original_frame) { + gInterpolationStep = (float)time / next_original_frame; + } + RunCommands(commands); + PatchInterpolations(); + } + + time -= fps; + + Instance->context->GetWindow()->SetTargetFps(fps); + + int threshold = CVarGetInteger("gExtraLatencyThreshold", 80); + Instance->context->GetWindow()->SetMaximumFrameLatency(threshold > 0 && target_fps >= threshold ? 2 : 1); + + last_fps = fps; +} + extern "C" uint32_t GameEngine_GetInterpolatedFPS() { return GameEngine::GetInterpolationFPS(); } diff --git a/src/port/Engine.h b/src/port/Engine.h index 120461f0..19f22509 100644 --- a/src/port/Engine.h +++ b/src/port/Engine.h @@ -37,6 +37,8 @@ class GameEngine { static void StartAudioFrame(); static void EndAudioFrame(); static void AudioExit(); + static void PatchInterpolations(); + static void ProcessGfxCommands(Gfx* commands); static uint8_t GetBankIdByName(const std::string& name); void LoadDictionary(); uint32_t GetGameVersion(); @@ -44,6 +46,7 @@ class GameEngine { static void Destroy(); }; #else +void GameEngine_ProcessGfxCommands(Gfx* commands); uint32_t GameEngine_GetInterpolatedFPS(); uint32_t GameEngine_GetSampleRate(); uint32_t GameEngine_GetSamplesPerFrame(); diff --git a/src/port/Game.cpp b/src/port/Game.cpp index be7197fa..b53d2ae9 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -7,7 +7,6 @@ extern "C" { #include "audio/external.h" #include "game/game_init.h" #include "sm64.h" -float gInterpolationStep = 0.0f; } void alloc_pool() { @@ -29,38 +28,7 @@ void patch_interpolations() { extern "C" void exec_display_list(SPTask *spTask) { - int target_fps = GameEngine::GetInterpolationFPS(); - static int last_fps; - static int time; - int fps = target_fps; - int original_fps = 30; - - if (target_fps == 30 || original_fps > target_fps) { - fps = original_fps; - } - - if (last_fps != fps) { - time = 0; - } - - int next_original_frame = fps; - while (time + original_fps <= next_original_frame) { - time += original_fps; - if (time != next_original_frame) { - gInterpolationStep = (float)time / next_original_frame; - } - GameEngine::RunCommands((Gfx *) spTask->task.t.data_ptr); - patch_interpolations(); - } - - time -= fps; - - GameEngine::Instance->context->GetWindow()->SetTargetFps(fps); - - int threshold = CVarGetInteger("gExtraLatencyThreshold", 80); - GameEngine::Instance->context->GetWindow()->SetMaximumFrameLatency(threshold > 0 && target_fps >= threshold ? 2 : 1); - - last_fps = fps; + GameEngine::ProcessGfxCommands((Gfx *) spTask->task.t.data_ptr); } void push_frame() { diff --git a/src/port/game/GeoLayoutParser.cpp b/src/port/game/GeoLayoutParser.cpp index ab5a470f..b6809f41 100644 --- a/src/port/game/GeoLayoutParser.cpp +++ b/src/port/game/GeoLayoutParser.cpp @@ -300,6 +300,7 @@ void process_cmd_node_translation() { if (params & 0x80) { displayList = ResourceGetDataByCrc(GeoLayoutParser::mReader->ReadUInt64()); drawingLayer = params & 0x0F; + SPDLOG_INFO("Current Offset {}", GeoLayoutParser::mReader->GetBaseAddress()); } GraphNodeTranslation* graphNode = @@ -315,7 +316,7 @@ void process_cmd_node_rotation() { s16 drawingLayer = 0; void *displayList = nullptr; - ReadVec3s(rotation); + ReadVec3sAngle(rotation); if (params & 0x80) { displayList = ResourceGetDataByCrc(GeoLayoutParser::mReader->ReadUInt64()); diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp index 6b7fedf0..e628f13e 100644 --- a/src/port/ui/ImguiUI.cpp +++ b/src/port/ui/ImguiUI.cpp @@ -19,6 +19,7 @@ std::shared_ptr mGameMenuBar; std::shared_ptr mConsoleWindow; std::shared_ptr mStatsWindow; std::shared_ptr mInputEditorWindow; +std::shared_ptr mGfxDebuggerWindow; std::shared_ptr mSaveEditorWindow; std::shared_ptr mAdvancedResolutionSettingsWindow; @@ -48,6 +49,11 @@ void SetupGuiElements() { return; } + mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow"); + if (mGfxDebuggerWindow == nullptr) { + SPDLOG_ERROR("Could not find input GfxDebuggerWindow"); + } + mAdvancedResolutionSettingsWindow = std::make_shared("gAdvancedResolutionEditorEnabled", "Advanced Resolution Settings"); gui->AddGuiWindow(mAdvancedResolutionSettingsWindow); mSaveEditorWindow = std::make_shared("gSaveEditorEnabled", "Save Editor"); @@ -450,6 +456,10 @@ const char* debugInfoPages[6] = { void DrawDebugMenu() { if (UIWidgets::BeginMenu("Developer")) { + UIWidgets::WindowButton("Gfx Debugger", "gGfxDebuggerEnabled", GameUI::mGfxDebuggerWindow, { + .tooltip = "Enables the Gfx Debugger window, allowing you to input commands, type help for some examples" + }); + UIWidgets::CVarCheckbox("Debug mode", "gEnableDebugMode", { .tooltip = "Various debug features, including a level selector from the main menu" });