Skip to content

Commit 20be083

Browse files
committed
Overlay: add draw distance debugger/exclusion tool (F11)
1 parent 19e1d33 commit 20be083

File tree

4 files changed

+161
-50
lines changed

4 files changed

+161
-50
lines changed

src/game.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,12 @@ static_assert(sizeof(EvWorkCamera) == 0x3B4);
188188

189189
struct OnRoadPlace
190190
{
191-
DWORD loadColiType_0;
191+
uint32_t loadColiType_0;
192192
uint32_t field_4;
193193
__int16 roadSectionNum_8;
194194
uint8_t field_A;
195195
uint8_t unk_B;
196-
DWORD curStageIdx_C;
196+
uint32_t curStageIdx_C;
197197
};
198198
static_assert(sizeof(OnRoadPlace) == 0x10);
199199

src/game_addrs.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ namespace Game
2020
inline int* game_start_progress_code = nullptr;
2121
inline int* file_load_progress_code = nullptr;
2222

23-
inline uint8_t* Sumo_CountdownTimerEnable = nullptr;
24-
inline uint8_t* Sumo_IntroLogosEnable = nullptr;
23+
static_assert(sizeof(bool) == sizeof(uint8_t)); // the following bools take 1 byte each
24+
inline bool* Sumo_CountdownTimerEnable = nullptr;
25+
inline bool* Sumo_IntroLogosEnable = nullptr;
2526

2627
inline D3DPRESENT_PARAMETERS* D3DPresentParams = nullptr;
2728
inline IDirect3DDevice9** D3DDevice_ptr = nullptr;
@@ -135,8 +136,8 @@ namespace Game
135136
current_mode = Module::exe_ptr<GameState>(0x38026C);
136137
game_start_progress_code = Module::exe_ptr<int>(0x4367A8);
137138
file_load_progress_code = Module::exe_ptr<int>(0x436718);
138-
Sumo_CountdownTimerEnable = Module::exe_ptr<uint8_t>(0x237911);
139-
Sumo_IntroLogosEnable = Module::exe_ptr<uint8_t>(0x2319A1);
139+
Sumo_CountdownTimerEnable = Module::exe_ptr<bool>(0x237911);
140+
Sumo_IntroLogosEnable = Module::exe_ptr<bool>(0x2319A1);
140141

141142
D3DPresentParams = Module::exe_ptr<D3DPRESENT_PARAMETERS>(0x49BD64);
142143
D3DDevice_ptr = Module::exe_ptr<IDirect3DDevice9*>(0x49BD60);

src/hooks_graphics.cpp

Lines changed: 149 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,123 @@
44
#include <array>
55
#include <bitset>
66
#include <iostream>
7+
#include <imgui.h>
78

8-
#ifdef _DEBUG
9-
#define ENABLE_NODE_ID_TESTER 1
10-
#endif
11-
12-
#ifdef ENABLE_NODE_ID_TESTER
13-
// creates a list of which CullingNode IDs were added by the last distance increase loop
14-
// and allow testing the distance increase with a given CullingNode skipped
15-
// can help us to find which CullingNodes cause ugly LOD issues, and hopefully add them to filter list eventually
16-
std::vector<uint16_t> lastAdds; // list of IDs added
17-
uint16_t* lastAddsPtr = 0; // ptr to the lastAdds data, for ease of use with CE
18-
int lastAddsNum = 0; // ObjectNum that we want to populate lastAdds for
19-
int skipAddNum = -1; // if set, skips drawing this CullingNode ID, can be used to find which specific ID is troublesome
20-
int skipObjNum = -1; // skips distance-increase for this ObjectNum, can be used to find which ObjectNum is troublesome
21-
#endif
9+
std::array<std::vector<uint16_t>, 256> ObjectNodes;
10+
std::array<std::bitset<16384>, 256> ObjectExclusions;
11+
int ExclusionsStageNum = 0; // stageid the exclusions are setup for, if stageid doesn't match current exclusions will be cleared
12+
int NumObjects = 0;
13+
14+
void Overlay_DrawDistOverlay()
15+
{
16+
uint32_t cur_stage_num = Game::GetStageUniqueNum(Game::GetNowStageNum(8));
17+
18+
ImGui::Begin("Draw Distance Debugger");
19+
20+
ImGui::Checkbox("Countdown timer enabled", Game::Sumo_CountdownTimerEnable);
21+
22+
// get max column count
23+
int num_columns = 0;
24+
for (int i = 0; i < NumObjects; i++)
25+
{
26+
size_t size = ObjectNodes[i].size();
27+
if (size > num_columns)
28+
num_columns = size;
29+
}
30+
31+
static ImGuiTableFlags table_flags = ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_HighlightHoveredColumn;
32+
33+
ImGui::Text("How to use:");
34+
ImGui::Text("- When you see an ugly LOD object, pause the game with ESC, and press F11 to bring up this window");
35+
ImGui::Text("- Reduce the Draw Distance below to the lowest value which still shows the LOD object for you");
36+
ImGui::Text("- Once you find the draw-distance that shows the object, click each node checkbox until you find the node responsible");
37+
ImGui::Text("- After finding the node, you can hover over the checkbox to get the IDs for it");
38+
ImGui::Text("- Post the IDs for LODs you find in the \"DrawDistanceIncrease issue reports\" github thread and we can add exclusions for them!");
39+
ImGui::NewLine();
40+
41+
ImGui::SliderInt("Draw Distance", &Settings::DrawDistanceIncrease, 0, 1024);
42+
if (ImGui::Button("<<<"))
43+
Settings::DrawDistanceIncrease--;
44+
ImGui::SameLine();
45+
if (ImGui::Button(">>>"))
46+
Settings::DrawDistanceIncrease++;
47+
48+
ImGui::Text("cur_stage_num = 0x%X", cur_stage_num);
49+
50+
if (num_columns > 0)
51+
{
52+
ImGui::Text("Nodes at DrawDistance %d:", Settings::DrawDistanceIncrease);
53+
54+
num_columns += 1;
55+
if (ImGui::BeginTable("table_angled_headers", num_columns, table_flags))
56+
{
57+
ImGui::TableSetupColumn("Object ID", ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
58+
for (int n = 1; n < num_columns; n++)
59+
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
60+
61+
for (int objectIdx = 0; objectIdx < NumObjects; objectIdx++)
62+
{
63+
ImGui::PushID(objectIdx);
64+
ImGui::TableNextRow();
65+
ImGui::TableSetColumnIndex(0);
66+
//ImGui::AlignTextToFramePadding();
67+
ImGui::Text("Object %d", objectIdx);
68+
69+
for (int i = 0; i < ObjectNodes[objectIdx].size(); i++)
70+
if (ImGui::TableSetColumnIndex(i + 1))
71+
{
72+
ImGui::PushID(i + 1);
73+
74+
auto nodeId = ObjectNodes[objectIdx][i];
75+
bool excluded = ObjectExclusions[objectIdx][nodeId];
76+
77+
if (ImGui::Checkbox("", &excluded))
78+
ObjectExclusions[objectIdx][nodeId] = excluded;
79+
80+
ImGui::SetItemTooltip("StageNum 0x%X, object 0x%X node 0x%X", cur_stage_num, objectIdx, nodeId);
81+
82+
ImGui::PopID();
83+
}
84+
85+
ImGui::PopID();
86+
}
87+
ImGui::EndTable();
88+
}
89+
}
90+
91+
if (ImGui::Button("Clear all exclusions"))
92+
{
93+
for (int i = 0; i < ObjectExclusions.size(); i++)
94+
ObjectExclusions[i].reset();
95+
}
96+
if (ImGui::Button("Copy exclusions to clipboard"))
97+
{
98+
std::string clipboard = "";
99+
for (int objId = 0; objId < ObjectExclusions.size(); objId++)
100+
{
101+
for (int i = 0; i < ObjectExclusions[objId].size(); i++)
102+
{
103+
if (ObjectExclusions[objId][i])
104+
{
105+
clipboard += std::format("StageNum 0x{:X}, object 0x{:X} node 0x{:X}\r\n", cur_stage_num, objId, i);
106+
}
107+
}
108+
}
109+
110+
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, clipboard.length());
111+
if (hMem)
112+
{
113+
memcpy(GlobalLock(hMem), clipboard.c_str(), clipboard.length());
114+
GlobalUnlock(hMem);
115+
OpenClipboard(0);
116+
EmptyClipboard();
117+
SetClipboardData(CF_TEXT, hMem);
118+
CloseClipboard();
119+
}
120+
}
121+
122+
ImGui::End();
123+
}
22124

23125
class DrawDistanceIncrease : public Hook
24126
{
@@ -75,7 +177,15 @@ class DrawDistanceIncrease : public Hook
75177
int v6 = ctx.ebx;
76178
uint32_t* v11 = (uint32_t*)(v6 + 8);
77179

78-
int NumObjects = *(int*)(ctx.esp + 0x18);
180+
uint32_t cur_stage_num = Game::GetStageUniqueNum(Game::GetNowStageNum(8));
181+
if (ExclusionsStageNum != cur_stage_num)
182+
{
183+
for (int i = 0; i < ObjectExclusions.size(); i++)
184+
ObjectExclusions[i].reset();
185+
ExclusionsStageNum = cur_stage_num;
186+
}
187+
188+
NumObjects = *(int*)(ctx.esp + 0x18);
79189
for (int ObjectNum = 0; ObjectNum < NumObjects; ObjectNum++)
80190
{
81191
CollisionNodesToDisplay.reset();
@@ -94,44 +204,40 @@ class DrawDistanceIncrease : public Hook
94204
break;
95205
}
96206

97-
#ifdef ENABLE_NODE_ID_TESTER
98-
if (ObjectNum == lastAddsNum && csOffset == Settings::DrawDistanceIncrease)
207+
// DEBUG: clear lastadds for this objectnum here
208+
if (csOffset == Settings::DrawDistanceIncrease)
99209
{
100-
lastAdds.clear();
210+
ObjectNodes[ObjectNum].clear();
101211
}
102-
#endif
212+
103213
uint32_t sectionCollListOffset = *(uint32_t*)(v6 + *v11 + ((CsLengthNum + csOffset) * 4));
104214
uint16_t* sectionCollList = (uint16_t*)(v6 + *v11 + sectionCollListOffset);
215+
216+
int num = 0;
105217
while (*sectionCollList != 0xFFFF)
106218
{
107219
// If we haven't seen this CollisionNode idx already lets add it to our IdxArray
108220
if (!CollisionNodesToDisplay[*sectionCollList])
109221
{
110-
#ifdef ENABLE_NODE_ID_TESTER
111-
if (skipObjNum != ObjectNum || csOffset == 0)
112-
if (skipAddNum != *sectionCollList || skipAddNum < 0 || csOffset == 0)
113-
#endif
114-
{
115-
CollisionNodesToDisplay[*sectionCollList] = true;
116-
*cur = *sectionCollList;
117-
118-
#ifdef ENABLE_NODE_ID_TESTER
119-
if (ObjectNum == lastAddsNum && csOffset == Settings::DrawDistanceIncrease)
120-
lastAdds.push_back(*cur);
121-
#endif
122-
cur++;
123-
}
222+
CollisionNodesToDisplay[*sectionCollList] = true;
223+
224+
// DEBUG: check exclusions here before adding to *cur
225+
// (if we're at csOffset = 0, exclusions are ignored, since that is what vanilla game would display)
226+
if (!ObjectExclusions[ObjectNum][*sectionCollList] || csOffset == 0)
227+
{
228+
*cur = *sectionCollList;
229+
cur++;
230+
}
231+
232+
// DEBUG: add *sectionCollList to lastadds list here
233+
if (csOffset == Settings::DrawDistanceIncrease)
234+
ObjectNodes[ObjectNum].push_back(*sectionCollList);
235+
236+
num++;
124237
}
125238

126239
sectionCollList++;
127240
}
128-
129-
#ifdef ENABLE_NODE_ID_TESTER
130-
if (ObjectNum == lastAddsNum && csOffset == Settings::DrawDistanceIncrease)
131-
{
132-
lastAddsPtr = lastAdds.data();
133-
}
134-
#endif
135241
}
136242

137243
*cur = 0xFFFF;
@@ -155,15 +261,14 @@ class DrawDistanceIncrease : public Hook
155261

156262
bool apply() override
157263
{
158-
#ifdef ENABLE_NODE_ID_TESTER
159-
lastAdds.reserve(100);
160-
#endif
161-
162264
constexpr int DispStage_HookAddr = 0x4DF6D;
163265

164266
Memory::VP::Nop(Module::exe_ptr(DispStage_HookAddr), 0x4B);
165267
dest_hook = safetyhook::create_mid(Module::exe_ptr(DispStage_HookAddr), destination);
166268

269+
for (int i = 0; i < ObjectNodes.size(); i++)
270+
ObjectNodes[i].reserve(4096);
271+
167272
return true;
168273
}
169274

src/hooks_overlay.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@ bool Overlay_Update()
3737
ImGui_ImplWin32_NewFrame();
3838
ImGui::NewFrame();
3939

40+
#ifdef _DEBUG
4041
static bool show_demo_window = true;
4142
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
4243
if (show_demo_window)
4344
{
4445
ImGui::ShowDemoWindow(&show_demo_window);
4546
}
47+
#endif
48+
49+
void Overlay_DrawDistOverlay();
50+
Overlay_DrawDistOverlay();
4651

4752
ImGui::EndFrame();
4853

0 commit comments

Comments
 (0)