[Scummvm-git-logs] scummvm master -> a55fcc622e7871b2d9311ba7ec927fd6288e52d6

sev- noreply at scummvm.org
Tue Sep 30 08:41:06 UTC 2025


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
52451a34e7 WAGE: Fix string operant reading
a55fcc622e WAGE: Added ImGui-based debugger. Global script is displayed


Commit: 52451a34e7fc384e64fb2fea665fc5d05eb48480
    https://github.com/scummvm/scummvm/commit/52451a34e7fc384e64fb2fea665fc5d05eb48480
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2025-09-30T10:40:54+02:00

Commit Message:
WAGE: Fix string operant reading

Fixes crash in castleofert when going up from the current scene.

Bug #16222

Changed paths:
    engines/wage/script.cpp


diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp
index 52b93b54064..bab621175bc 100644
--- a/engines/wage/script.cpp
+++ b/engines/wage/script.cpp
@@ -499,8 +499,9 @@ Script::Operand *Script::readStringOperand() {
 
 	while (true) {
 		byte c = _data->readByte();
-		if (c >= 0x20 && c < 0x80)
-			*str += c;
+
+		if (c < 0x80)
+			*str += (c < 0x20 ? ' ' : c);
 		else
 			break;
 		if ((c < '0' || c > '9') && !(c == '-' && str->empty()))


Commit: a55fcc622e7871b2d9311ba7ec927fd6288e52d6
    https://github.com/scummvm/scummvm/commit/a55fcc622e7871b2d9311ba7ec927fd6288e52d6
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2025-09-30T10:40:54+02:00

Commit Message:
WAGE: Added ImGui-based debugger. Global script is displayed

Changed paths:
  A engines/wage/debugtools.cpp
  A engines/wage/debugtools.h
  A engines/wage/dt-internal.h
    engines/wage/configure.engine
    engines/wage/detection.cpp
    engines/wage/module.mk
    engines/wage/wage.cpp
    engines/wage/wage.h


diff --git a/engines/wage/configure.engine b/engines/wage/configure.engine
index d7cb5443685..6ac91b2932b 100644
--- a/engines/wage/configure.engine
+++ b/engines/wage/configure.engine
@@ -1,3 +1,3 @@
 # This file is included from the main "configure" script
 # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
-add_engine wage "WAGE" yes "" "" "highres"
+add_engine wage "WAGE" yes "" "" "highres" "imgui"
diff --git a/engines/wage/debugtools.cpp b/engines/wage/debugtools.cpp
new file mode 100644
index 00000000000..54d3b21d4b3
--- /dev/null
+++ b/engines/wage/debugtools.cpp
@@ -0,0 +1,254 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "backends/imgui/IconsMaterialSymbols.h"
+#define IMGUI_DEFINE_MATH_OPERATORS
+
+#include "backends/imgui/imgui.h"
+#include "backends/imgui/imgui_fonts.h"
+
+#include "common/debug.h"
+#include "common/system.h"
+
+#include "graphics/managed_surface.h"
+
+#include "wage/wage.h"
+#include "wage/dt-internal.h"
+#include "wage/script.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+ImGuiState *_state = nullptr;
+
+ImGuiImage getImageID(Common::Path filename, int frameNum) {
+	Common::String key = Common::String::format("%s:%d", filename.toString().c_str(), frameNum);
+
+	if (_state->_frames.contains(key))
+		return _state->_frames[key];
+
+	int sx = 10, sy = 10;
+	Graphics::ManagedSurface *surface = nullptr;
+
+	if (surface)
+		_state->_frames[key] = { (ImTextureID)g_system->getImGuiTexture(*surface->surfacePtr()), sx, sy };
+
+	delete surface;
+
+	return _state->_frames[key];
+}
+
+#if 0
+void showImage(const ImGuiImage &image, const char *name, float scale) {
+	ImVec2 size = { (float)image.width * scale, (float)image.height * scale };
+
+	ImGui::BeginGroup();
+	ImVec2 screenPos = ImGui::GetCursorScreenPos();
+	ImGui::GetWindowDrawList()->AddRect(screenPos, screenPos + ImVec2(size.x, size.y), 0xFFFFFFFF);
+
+	ImGui::Image(image.id, size);
+	ImGui::EndGroup();
+	//setToolTipImage(image, name);
+}
+
+static void displayTGA() {
+	ImGuiImage imgID;
+
+	imgID = getImageID(_state->_fileToDisplay, 0);
+
+	ImGui::Text("TGA %s: [%d x %d]", transCyrillic(_state->_fileToDisplay.toString()), imgID.width, imgID.height);
+
+	ImGui::Separator();
+
+	showImage(imgID, (char *)transCyrillic(_state->_fileToDisplay.toString()), 1.0);
+}
+
+void showArchives() {
+	if (!_state->_showArchives)
+		return;
+
+	// Calculate the viewport size
+	ImVec2 viewportSize = ImGui::GetMainViewport()->Size;
+
+	// Calculate the window size
+	ImVec2 windowSize = ImVec2(
+		viewportSize.x * 0.9f,
+		viewportSize.y * 0.9f
+	);
+
+	// Calculate the centered position
+	ImVec2 centeredPosition = ImVec2(
+		(viewportSize.x - windowSize.x) * 0.5f,
+		(viewportSize.y - windowSize.y) * 0.5f
+	);
+
+	// Set the next window position and size
+	ImGui::SetNextWindowPos(centeredPosition, ImGuiCond_FirstUseEver);
+	ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
+
+	if (ImGui::Begin("Archives", &_state->_showArchives)) {
+		ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.4f, ImGui::GetContentRegionAvail().y), ImGuiChildFlags_None);
+
+		ImGui::Button(ICON_MS_FILTER_ALT);
+		ImGui::SameLine();
+
+		_state->_nameFilter.Draw();
+		ImGui::Separator();
+
+		if (_state->_files.children.empty())
+			populateFileList();
+
+		displayTree(&_state->_files);
+
+		ImGui::EndChild();
+
+		ImGui::SameLine();
+
+		{ // Right pane
+			ImGui::BeginChild("ChildR", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y), ImGuiChildFlags_Borders);
+
+			if (_state->_displayMode == kDisplayQDA) {
+				displayQDA();
+			} else if (_state->_displayMode == kDisplayTGA) {
+				displayTGA();
+			}
+
+			ImGui::EndChild();
+		}
+
+	}
+	ImGui::End();
+}
+
+void showSceneObjects() {
+	if (!_state->_showSceneObjects)
+		return;
+
+	ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
+	ImGui::SetNextWindowSize(ImVec2(300, 250), ImGuiCond_FirstUseEver);
+
+	if (ImGui::Begin("Scene Objects", &_state->_showSceneObjects)) {
+		qdGameScene *scene;
+		qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher();
+		if (dp && ((scene = dp->get_active_scene()))) {
+			if (!scene->object_list().empty()) {
+				for (auto &it : g_engine->_visible_objects) {
+					if (ImGui::Selectable((char *)transCyrillic(it->name()), _state->_objectToDisplay == it->name())) {
+						_state->_objectToDisplay = it->name();
+					}
+				}
+			}
+		}
+	}
+	ImGui::End();
+}
+#endif
+
+static void showWorld() {
+	if (!_state->_showWorld)
+		return;
+
+	ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
+	ImGui::SetNextWindowSize(ImVec2(300, 250), ImGuiCond_FirstUseEver);
+
+	if (ImGui::Begin("Scene Objects", &_state->_showWorld)) {
+		ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
+		if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) {
+			if (ImGui::BeginTabItem("Scenes")) {
+				ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
+				ImGui::EndTabItem();
+			}
+			if (ImGui::BeginTabItem("Objects")) {
+				ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
+				ImGui::EndTabItem();
+			}
+			if (ImGui::BeginTabItem("Characters")) {
+				ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
+				ImGui::EndTabItem();
+			}
+			if (ImGui::BeginTabItem("Sounds")) {
+				ImGui::Text("This is the Sounds tab!\nblah blah blah blah blah");
+				ImGui::EndTabItem();
+			}
+			if (ImGui::BeginTabItem("Global Script")) {
+				for (auto &t : g_wage->_world->_globalScript->_scriptText) {
+					ImGui::Text("[%4d]", t->offset);
+					ImGui::SameLine();
+					ImGui::Text("%s", t->line.c_str());
+				}
+				ImGui::EndTabItem();
+			}
+			if (ImGui::BeginTabItem("World")) {
+				ImGui::Text("This is the Global Script tab!\nblah blah blah blah blah");
+				ImGui::EndTabItem();
+			}
+			ImGui::EndTabBar();
+		}
+	}
+
+	ImGui::End();
+}
+
+void onImGuiInit() {
+	ImGuiIO &io = ImGui::GetIO();
+	io.Fonts->AddFontDefault();
+
+	ImFontConfig icons_config;
+	icons_config.MergeMode = true;
+	icons_config.PixelSnapH = false;
+	icons_config.OversampleH = 3;
+	icons_config.OversampleV = 3;
+	icons_config.GlyphOffset = {0, 4};
+
+	static const ImWchar icons_ranges[] = {ICON_MIN_MS, ICON_MAX_MS, 0};
+	ImGui::addTTFFontFromArchive("MaterialSymbolsSharp.ttf", 16.f, &icons_config, icons_ranges);
+
+	_state = new ImGuiState();
+}
+
+void onImGuiRender() {
+	if (!debugChannelSet(-1, kDebugImGui)) {
+		ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse;
+		return;
+	}
+
+	if (!_state)
+		return;
+
+	ImGui::GetIO().ConfigFlags &= ~(ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse);
+
+	if (ImGui::BeginMainMenuBar()) {
+		if (ImGui::BeginMenu("View")) {
+			ImGui::MenuItem("World", NULL, &_state->_showWorld);
+			ImGui::EndMenu();
+		}
+		ImGui::EndMainMenuBar();
+	}
+
+	showWorld();
+}
+
+void onImGuiCleanup() {
+	delete _state;
+	_state = nullptr;
+}
+
+} // namespace Wage
diff --git a/engines/wage/debugtools.h b/engines/wage/debugtools.h
new file mode 100644
index 00000000000..757a8869402
--- /dev/null
+++ b/engines/wage/debugtools.h
@@ -0,0 +1,31 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef WAGE_DEBUGTOOLS_H
+#define WAGE_DEBUGTOOLS_H
+
+namespace Wage {
+void onImGuiInit();
+void onImGuiRender();
+void onImGuiCleanup();
+} // namespace Wage
+
+#endif // WAGE_DEBUGTOOLS_H
diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp
index 2bc747ef29f..6ffd088aee7 100644
--- a/engines/wage/detection.cpp
+++ b/engines/wage/detection.cpp
@@ -44,6 +44,11 @@ static const PlainGameDescriptor wageGames[] = {
 #include "wage/detection_tables.h"
 #include "wage/detection.h"
 
+static const DebugChannelDef debugFlagList[] = {
+	{Wage::kDebugImGui, "imgui", "Show ImGui debug window (if available)"},
+	DEBUG_CHANNEL_END
+};
+
 static ADGameDescription s_fallbackDesc = {
 	"wage",
 	"",
@@ -75,6 +80,10 @@ public:
 		return "World Builder (C) Silicon Beach Software";
 	}
 
+	const DebugChannelDef *getDebugChannels() const override {
+		return debugFlagList;
+	}
+
 	ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const override;
 };
 
diff --git a/engines/wage/dt-internal.h b/engines/wage/dt-internal.h
new file mode 100644
index 00000000000..a7dff6829ec
--- /dev/null
+++ b/engines/wage/dt-internal.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef WAGE_DT_INTERNAL_H
+#define WAGE_DT_INTERNAL_H
+
+namespace Wage {
+
+typedef struct ImGuiImage {
+	ImTextureID id;
+	int width;
+	int height;
+} ImGuiImage;
+
+typedef struct ImGuiState {
+	bool _showWorld = false;
+
+	Common::HashMap<Common::String, ImGuiImage> _frames;
+
+	Common::Path _fileToDisplay;
+	Common::String _objectToDisplay;
+
+	ImGuiTextFilter _nameFilter;
+
+
+	int _displayMode = -1;
+} ImGuiState;
+
+extern ImGuiState *_state;
+
+}
+
+#endif // WAGE_DT_INTERNAL_H
diff --git a/engines/wage/module.mk b/engines/wage/module.mk
index 0e19348c96e..3d086316dc7 100644
--- a/engines/wage/module.mk
+++ b/engines/wage/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/wage
 MODULE_OBJS := \
 	combat.o \
 	debugger.o \
+	debugtools.o \
 	design.o \
 	entities.o \
 	gui.o \
diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp
index 4c664ed060c..3624451d2cb 100644
--- a/engines/wage/wage.cpp
+++ b/engines/wage/wage.cpp
@@ -58,6 +58,7 @@
 #include "graphics/macgui/macdialog.h"
 
 #include "wage/wage.h"
+#include "wage/debugtools.h"
 #include "wage/entities.h"
 #include "wage/gui.h"
 #include "wage/script.h"
@@ -65,6 +66,8 @@
 
 namespace Wage {
 
+WageEngine *g_wage = nullptr;
+
 WageEngine::WageEngine(OSystem *syst, const ADGameDescription *desc) : Engine(syst), _gameDescription(desc) {
 	_rnd = new Common::RandomSource("wage");
 
@@ -89,6 +92,8 @@ WageEngine::WageEngine(OSystem *syst, const ADGameDescription *desc) : Engine(sy
 
 	_resManager = NULL;
 
+	g_wage = this;
+
 	debug("WageEngine::WageEngine()");
 }
 
@@ -101,6 +106,7 @@ WageEngine::~WageEngine() {
 	delete _rnd;
 
 	g_engine = nullptr;
+	g_wage = nullptr;
 }
 
 bool WageEngine::pollEvent(Common::Event &event) {
@@ -139,6 +145,15 @@ Common::Error WageEngine::run() {
 
 	_gui = new Gui(this);
 
+#ifdef USE_IMGUI
+	ImGuiCallbacks callbacks;
+	bool drawImGui = debugChannelSet(-1, kDebugImGui);
+	callbacks.init = onImGuiInit;
+	callbacks.render = drawImGui ? onImGuiRender : nullptr;
+	callbacks.cleanup = onImGuiCleanup;
+	_system->setImGuiCallbacks(callbacks);
+#endif
+
 	_temporarilyHidden = true;
 	performInitialSetup();
 	if (ConfMan.hasKey("save_slot")) {
diff --git a/engines/wage/wage.h b/engines/wage/wage.h
index 125ca1ae877..d94e1a26b26 100644
--- a/engines/wage/wage.h
+++ b/engines/wage/wage.h
@@ -87,6 +87,10 @@ typedef Common::List<Chr *> ChrList;
 
 #define STORAGESCENE "STORAGE@"
 
+enum {
+	kDebugImGui = 1,
+};
+
 enum OperandType {
 	OBJ = 0,
 	CHR = 1,
@@ -261,6 +265,8 @@ private:
 	Audio::SoundHandle _soundHandle;
 };
 
+extern WageEngine *g_wage;
+
 } // End of namespace Wage
 
 #endif




More information about the Scummvm-git-logs mailing list