More debug features: pause/step/resume (#140)

* More debug features: pause/step/resume

* Fix palette order (I think)

* Revert "Fix palette order (I think)"

This reverts commit a81de08f78.
This commit is contained in:
Anonymous Maarten 2025-05-21 19:54:22 +02:00 committed by GitHub
parent 911330e61c
commit 183efa3d8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 267 additions and 18 deletions

View File

@ -2,6 +2,10 @@ name: CI
on: [push, pull_request] on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs: jobs:
clang-format: clang-format:
name: 'clang-format' name: 'clang-format'

View File

@ -353,13 +353,13 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
switch (event->type) { switch (event->type) {
case SDL_EVENT_WINDOW_FOCUS_GAINED: case SDL_EVENT_WINDOW_FOCUS_GAINED:
if (!g_debugEnabled) { if (!IsleDebug_Enabled()) {
g_isle->SetWindowActive(TRUE); g_isle->SetWindowActive(TRUE);
Lego()->Resume(); Lego()->Resume();
} }
break; break;
case SDL_EVENT_WINDOW_FOCUS_LOST: case SDL_EVENT_WINDOW_FOCUS_LOST:
if (!g_debugEnabled) { if (!IsleDebug_Enabled()) {
g_isle->SetWindowActive(FALSE); g_isle->SetWindowActive(FALSE);
Lego()->Pause(); Lego()->Pause();
} }
@ -722,6 +722,10 @@ inline bool IsleApp::Tick()
// GLOBAL: ISLE 0x4101bc // GLOBAL: ISLE 0x4101bc
static MxS32 g_startupDelay = 200; static MxS32 g_startupDelay = 200;
if (IsleDebug_Paused() && IsleDebug_StepModeEnabled()) {
IsleDebug_SetPaused(false);
}
if (!m_windowActive) { if (!m_windowActive) {
SDL_Delay(1); SDL_Delay(1);
return true; return true;
@ -752,6 +756,11 @@ inline bool IsleApp::Tick()
} }
g_lastFrameTime = currentTime; g_lastFrameTime = currentTime;
if (IsleDebug_StepModeEnabled()) {
IsleDebug_SetPaused(true);
IsleDebug_ResetStepMode();
}
if (g_startupDelay == 0) { if (g_startupDelay == 0) {
return true; return true;
} }
@ -845,7 +854,7 @@ MxResult IsleApp::ParseArguments(int argc, char** argv)
} }
#ifdef ISLE_DEBUG #ifdef ISLE_DEBUG
else if (strcmp(argv[i], "--debug") == 0) { else if (strcmp(argv[i], "--debug") == 0) {
g_debugEnabled = true; IsleDebug_SetEnabled(true);
consumed = 1; consumed = 1;
} }
#endif #endif

View File

@ -1,22 +1,150 @@
#include "isledebug.h" #include "isledebug.h"
#include "isleapp.h" #include "isleapp.h"
#include "lego/sources/roi/legoroi.h"
#include "legobuildingmanager.h" #include "legobuildingmanager.h"
#include "legoentity.h"
#include "legogamestate.h" #include "legogamestate.h"
#include "legoplantmanager.h" #include "legoplantmanager.h"
#include "legosoundmanager.h" #include "legosoundmanager.h"
#include "legovideomanager.h" #include "legovideomanager.h"
#include "misc.h" #include "misc.h"
#include "mxticklemanager.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <backends/imgui_impl_sdl3.h> #include <backends/imgui_impl_sdl3.h>
#include <backends/imgui_impl_sdlrenderer3.h> #include <backends/imgui_impl_sdlrenderer3.h>
#include <imgui.h> #include <imgui.h>
bool g_debugEnabled; #define SCANCODE_KEY_PAUSE SDL_SCANCODE_KP_0
bool g_debugPaused; #define SCANCODE_KEY_RESUME SDL_SCANCODE_KP_PERIOD
SDL_Window* g_debugWindow;
SDL_Renderer* g_debugRenderer; static bool g_debugEnabled;
static bool g_debugPaused;
static bool g_debugDoStep;
static SDL_Window* g_debugWindow;
static SDL_Renderer* g_debugRenderer;
static SDL_Texture* g_videoPalette;
class DebugViewer {
public:
static void InsidePlantManager()
{
LegoPlantManager* plantManager = Lego()->GetPlantManager();
ImGui::Value("#plants", plantManager->GetNumPlants());
ImGui::Value("#entries", plantManager->m_numEntries);
if (plantManager->m_numEntries) {
if (ImGui::BeginTable("Animated Entries", 4, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("ROI Name");
ImGui::TableSetupColumn("ROI m_unk0x100");
ImGui::TableSetupColumn("Entity Name");
ImGui::TableSetupColumn("Time");
ImGui::TableHeadersRow();
for (MxS8 i = 0; i < plantManager->m_numEntries; i++) {
const auto* entry = plantManager->m_entries[i];
ImGui::TableNextRow();
ImGui::Text("%s", entry->m_roi->m_name);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_roi->m_unk0x100);
ImGui::TableNextColumn();
ImGui::Text("%s", entry->m_roi->m_entity->ClassName());
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_time);
}
ImGui::EndTable();
}
}
}
static void InsideBuildingManager()
{
auto buildingManager = Lego()->GetBuildingManager();
ImGui::Text("nextVariant: %d", buildingManager->m_nextVariant);
ImGui::Text("m_unk0x09: %d", buildingManager->m_unk0x09);
ImGui::Text("m_unk0x28: %d", buildingManager->m_unk0x28);
ImGui::Text("#Animated Entries", buildingManager->m_numEntries);
if (buildingManager->m_numEntries) {
if (ImGui::BeginTable("Animated Entries", 6, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("ROI Name");
ImGui::TableSetupColumn("ROI m_unk0x100");
ImGui::TableSetupColumn("Entity Name");
ImGui::TableSetupColumn("Time");
ImGui::TableSetupColumn("unk_0x0c");
ImGui::TableSetupColumn("Muted");
ImGui::TableHeadersRow();
for (MxS8 i = 0; i < buildingManager->m_numEntries; i++) {
const auto* entry = buildingManager->m_entries[i];
ImGui::TableNextRow();
ImGui::Text("%s", entry->m_roi->m_name);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_roi->m_unk0x100);
ImGui::TableNextColumn();
ImGui::Text("%s", entry->m_roi->m_entity->ClassName());
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_time);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_unk0x0c);
ImGui::TableNextColumn();
ImGui::Text("%d", entry->m_muted);
}
ImGui::EndTable();
}
}
}
static void InsideTickleManager()
{
auto tickleManager = Lego()->GetTickleManager();
ImGui::Value("#clients", static_cast<int>(tickleManager->m_clients.size()));
if (ImGui::BeginTable("Clients", 3, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("Client");
ImGui::TableSetupColumn("Interval");
ImGui::TableSetupColumn("Flags");
ImGui::TableHeadersRow();
for (const auto* ticleClient : tickleManager->m_clients) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", ticleClient->GetClient()->ClassName());
ImGui::TableNextColumn();
ImGui::Text("%d", ticleClient->GetTickleInterval());
ImGui::TableNextColumn();
ImGui::Text("0x%x", ticleClient->GetFlags());
}
ImGui::EndTable();
}
}
static void InsideVideoManager()
{
auto videoManager = Lego()->GetVideoManager();
SDL_UpdateTexture(g_videoPalette, NULL, videoManager->m_paletteEntries, 4 * 16);
ImGui::Text("Elapsed: %gs", static_cast<float>(videoManager->GetElapsedSeconds()));
ImGui::Text("Render3D: %d", videoManager->GetRender3D());
ImGui::Text("unk0xe5: %d", videoManager->m_unk0xe5);
ImGui::Text("unk0xe5: %d", videoManager->m_unk0xe6);
ImGui::Text("unk0x54c: %f", videoManager->m_unk0x54c);
ImGui::Text("unk0x54c: %f", videoManager->m_unk0x550);
ImGui::Text("unk0x54c: %d", videoManager->m_unk0x554);
ImGui::Text("unk0x70: %u", videoManager->m_unk0x70);
ImGui::Text("Dither: %d", videoManager->m_dither);
ImGui::Text("BufferCount: %u", videoManager->m_bufferCount);
ImGui::Text("Paused: %f", videoManager->m_paused);
ImGui::Text("back: %g", videoManager->m_back);
ImGui::Text("front: %g", videoManager->m_front);
ImGui::Text("cameraWidth: %g", videoManager->m_cameraWidth);
ImGui::Text("cameraHeight: %g", videoManager->m_cameraHeight);
ImGui::Text("fov: %g", videoManager->m_fov);
ImVec2 uv_min = ImVec2(0.0f, 0.0f);
ImVec2 uv_max = ImVec2(1.0f, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, SDL_max(1.0f, ImGui::GetStyle().ImageBorderSize));
ImGui::ImageWithBg(
(ImTextureID) (uintptr_t) g_videoPalette,
ImVec2(200, 200),
uv_min,
uv_max,
ImVec4(0.0f, 0.0f, 0.0f, 1.0f)
);
ImGui::PopStyleVar();
}
};
void IsleDebug_Init() void IsleDebug_Init()
{ {
@ -38,11 +166,15 @@ void IsleDebug_Init()
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
if (!ImGui_ImplSDL3_InitForSDLRenderer(g_debugWindow, g_debugRenderer)) { if (!ImGui_ImplSDL3_InitForSDLRenderer(g_debugWindow, g_debugRenderer)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ImGui_ImplSDL3_InitForSDLRenderer failed"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ImGui_ImplSDL3_InitForSDLRenderer failed");
g_debugEnabled = false; g_debugEnabled = false;
break; break;
} }
g_videoPalette =
SDL_CreateTexture(g_debugRenderer, SDL_PIXELFORMAT_RGBX32, SDL_TEXTUREACCESS_STREAMING, 16, 16);
SDL_SetTextureScaleMode(g_videoPalette, SDL_SCALEMODE_PIXELART);
if (!ImGui_ImplSDLRenderer3_Init(g_debugRenderer)) { if (!ImGui_ImplSDLRenderer3_Init(g_debugRenderer)) {
g_debugEnabled = false; g_debugEnabled = false;
break; break;
@ -65,6 +197,24 @@ bool IsleDebug_Event(SDL_Event* event)
if (!g_debugEnabled) { if (!g_debugEnabled) {
return false; return false;
} }
if (event->type == SDL_EVENT_KEY_DOWN) {
if (event->key.scancode == SCANCODE_KEY_PAUSE) {
if (!g_debugPaused) {
IsleDebug_SetPaused(true);
}
else {
g_debugDoStep = true;
}
return true;
}
if (event->key.scancode == SCANCODE_KEY_RESUME) {
g_debugDoStep = false;
if (g_debugPaused) {
IsleDebug_SetPaused(false);
}
return true;
}
}
if (SDL_GetWindowFromEvent(event) != g_debugWindow) { if (SDL_GetWindowFromEvent(event) != g_debugWindow) {
return false; return false;
} }
@ -97,6 +247,7 @@ void IsleDebug_Render()
} }
} }
ImGui::EndMainMenuBar(); ImGui::EndMainMenuBar();
ImGui::ShowDemoWindow(nullptr);
LegoOmni* lego = Lego(); LegoOmni* lego = Lego();
if (ImGui::Begin("LEGO")) { if (ImGui::Begin("LEGO")) {
if (ImGui::TreeNode("Game State")) { if (ImGui::TreeNode("Game State")) {
@ -121,24 +272,24 @@ void IsleDebug_Render()
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Video Manager")) { if (ImGui::TreeNode("Video Manager")) {
LegoVideoManager* videoManager = lego->GetVideoManager(); DebugViewer::InsideVideoManager();
ImGui::Text("Elapsed: %g", static_cast<float>(videoManager->GetElapsedSeconds()));
ImGui::Value("Render3D", videoManager->GetRender3D());
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Plant Manager")) { if (ImGui::TreeNode("Plant Manager")) {
LegoPlantManager* plantManager = lego->GetPlantManager(); DebugViewer::InsidePlantManager();
ImGui::Value("#plants", plantManager->GetNumPlants());
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Building Manager")) { if (ImGui::TreeNode("Building Manager")) {
LegoBuildingManager* buildingManager = lego->GetBuildingManager(); DebugViewer::InsideBuildingManager();
ImGui::TreePop();
}
if (ImGui::TreeNode("Tickle Manager")) {
DebugViewer::InsideTickleManager();
ImGui::TreePop(); ImGui::TreePop();
} }
} }
ImGui::End(); ImGui::End();
} }
ImGui::ShowDemoWindow(nullptr);
ImGui::Render(); ImGui::Render();
SDL_RenderClear(g_debugRenderer); SDL_RenderClear(g_debugRenderer);
@ -153,3 +304,52 @@ void IsleDebug_Render()
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), g_debugRenderer); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), g_debugRenderer);
SDL_RenderPresent(g_debugRenderer); SDL_RenderPresent(g_debugRenderer);
} }
bool IsleDebug_Enabled()
{
return g_debugEnabled;
}
void IsleDebug_SetEnabled(bool v)
{
if (v) {
SDL_Log(
"Press \"%s\" for pausing/stepping the game",
SDL_GetKeyName(SDL_GetKeyFromScancode(SCANCODE_KEY_PAUSE, 0, false))
);
SDL_Log(
"Press \"%s\" for resuming the game",
SDL_GetKeyName(SDL_GetKeyFromScancode(SCANCODE_KEY_RESUME, 0, false))
);
}
g_debugEnabled = v;
}
void IsleDebug_SetPaused(bool v)
{
SDL_assert(g_debugPaused == !v);
g_debugPaused = v;
if (g_debugPaused) {
g_isle->SetWindowActive(false);
Lego()->Pause();
}
else {
g_isle->SetWindowActive(true);
Lego()->Resume();
}
}
bool IsleDebug_Paused()
{
return g_debugPaused;
}
void IsleDebug_ResetStepMode()
{
g_debugDoStep = false;
}
bool IsleDebug_StepModeEnabled()
{
return g_debugDoStep;
}

View File

@ -3,29 +3,55 @@
#if defined(ISLE_DEBUG) #if defined(ISLE_DEBUG)
extern bool g_debugEnabled;
typedef union SDL_Event SDL_Event; typedef union SDL_Event SDL_Event;
extern bool IsleDebug_Enabled();
extern void IsleDebug_SetEnabled(bool);
extern void IsleDebug_Init(); extern void IsleDebug_Init();
extern bool IsleDebug_Event(SDL_Event* event); extern bool IsleDebug_Event(SDL_Event* event);
extern void IsleDebug_Render(); extern void IsleDebug_Render();
extern void IsleDebug_SetPaused(bool v);
extern bool IsleDebug_Paused();
extern bool IsleDebug_StepModeEnabled();
extern void IsleDebug_ResetStepMode();
#else #else
#define IsleDebug_Enabled() (false)
#define IsleDebug_SetEnabled(V) \
do { \
} while (0)
#define IsleDebug_Init() \ #define IsleDebug_Init() \
do { \ do { \
} while (0) } while (0)
#define IsleDebug_Event(EVENT) false #define IsleDebug_Event(EVENT) (false)
#define IsleDebug_Render() \ #define IsleDebug_Render() \
do { \ do { \
} while (0) } while (0)
#define g_debugEnabled false #define IsleDebug_SetPaused(X) \
do { \
} while (0)
#define IsleDebug_Paused() (false)
#define IsleDebug_StepModeEnabled() (false)
#define IsleDebug_ResetStepMode() \
do { \
} while (0)
#endif #endif

View File

@ -108,6 +108,8 @@ class LegoBuildingManager : public MxCore {
LegoCacheSound* m_sound; // 0x24 LegoCacheSound* m_sound; // 0x24
MxBool m_unk0x28; // 0x28 MxBool m_unk0x28; // 0x28
LegoWorld* m_world; // 0x2c LegoWorld* m_world; // 0x2c
friend class DebugViewer;
}; };
#endif // LEGOBUILDINGMANAGER_H #endif // LEGOBUILDINGMANAGER_H

View File

@ -82,6 +82,8 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore {
AnimEntry* m_entries[5]; // 0x10 AnimEntry* m_entries[5]; // 0x10
MxS8 m_numEntries; // 0x24 MxS8 m_numEntries; // 0x24
LegoWorld* m_world; // 0x28 LegoWorld* m_world; // 0x28
friend class DebugViewer;
}; };
#endif // LEGOPLANTMANAGER_H #endif // LEGOPLANTMANAGER_H

View File

@ -124,6 +124,8 @@ class LegoVideoManager : public MxVideoManager {
D3DRMRENDERMODE m_rendermode; // 0x584 D3DRMRENDERMODE m_rendermode; // 0x584
BOOL m_dither; // 0x588 BOOL m_dither; // 0x588
DWORD m_bufferCount; // 0x58c DWORD m_bufferCount; // 0x58c
friend class DebugViewer;
}; };
// SYNTHETIC: LEGO1 0x1007ab20 // SYNTHETIC: LEGO1 0x1007ab20

View File

@ -89,6 +89,8 @@ class LegoROI : public ViewROI {
BoundingSphere m_sphere; // 0xe8 BoundingSphere m_sphere; // 0xe8
undefined m_unk0x100; // 0x100 undefined m_unk0x100; // 0x100
LegoEntity* m_entity; // 0x104 LegoEntity* m_entity; // 0x104
friend class DebugViewer;
}; };
// VTABLE: LEGO1 0x100dbea8 // VTABLE: LEGO1 0x100dbea8

View File

@ -55,6 +55,8 @@ class MxTickleManager : public MxCore {
private: private:
MxTickleClientPtrList m_clients; // 0x08 MxTickleClientPtrList m_clients; // 0x08
friend class DebugViewer;
}; };
#define TICKLE_MANAGER_NOT_FOUND 0x80000000 #define TICKLE_MANAGER_NOT_FOUND 0x80000000