Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,475 @@
/* 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 "twine/debugger/console.h"
#include "common/scummsys.h"
#include "common/util.h"
#include "twine/debugger/debug_state.h"
#include "twine/holomap.h"
#include "twine/renderer/redraw.h"
#include "twine/resources/hqr.h"
#include "twine/scene/gamestate.h"
#include "twine/scene/scene.h"
#include "twine/renderer/screens.h"
#include "twine/text.h"
#include "twine/twine.h"
#include "twine/audio/music.h"
namespace TwinE {
TwinEConsole::TwinEConsole(TwinEEngine *engine) : _engine(engine), GUI::Debugger() {
registerCmd("give_item", WRAP_METHOD(TwinEConsole, doGiveItem));
registerCmd("give_allitems", WRAP_METHOD(TwinEConsole, doGiveAllItems));
registerCmd("give_key", WRAP_METHOD(TwinEConsole, doGiveKey));
registerCmd("give_gas", WRAP_METHOD(TwinEConsole, doGiveGas));
registerCmd("give_kashes", WRAP_METHOD(TwinEConsole, doGiveKashes));
registerCmd("play_video", WRAP_METHOD(TwinEConsole, doPlayVideo));
registerCmd("play_midi", WRAP_METHOD(TwinEConsole, doPlayMidi));
registerCmd("play_music", WRAP_METHOD(TwinEConsole, doPlayMusic));
registerCmd("change_scene", WRAP_METHOD(TwinEConsole, doChangeScene));
registerCmd("change_chapter", WRAP_METHOD(TwinEConsole, doChangeChapter));
registerCmd("toggle_scenery_view", WRAP_METHOD(TwinEConsole, doToggleSceneryView));
registerCmd("magic_points", WRAP_METHOD(TwinEConsole, doAddMagicPoints));
registerCmd("dumpfile", WRAP_METHOD(TwinEConsole, doDumpFile));
registerCmd("toggle_zones", WRAP_METHOD(TwinEConsole, doToggleZoneRendering));
registerCmd("toggle_tracks", WRAP_METHOD(TwinEConsole, doToggleTrackRendering));
registerCmd("toggle_godmode", WRAP_METHOD(TwinEConsole, doToggleGodMode));
registerCmd("toggle_autoagressive", WRAP_METHOD(TwinEConsole, doToggleAutoAggressive));
registerCmd("toggle_actors", WRAP_METHOD(TwinEConsole, doToggleActorRendering));
registerCmd("toggle_clips", WRAP_METHOD(TwinEConsole, doToggleClipRendering));
registerCmd("toggle_freecamera", WRAP_METHOD(TwinEConsole, doToggleFreeCamera));
registerCmd("toggle_scenerendering", WRAP_METHOD(TwinEConsole, doToggleSceneRendering));
registerCmd("set_track_obj", WRAP_METHOD(TwinEConsole, doSetTrackObject));
registerCmd("scene_actor", WRAP_METHOD(TwinEConsole, doSkipSceneActorsBut));
registerCmd("hero_pos", WRAP_METHOD(TwinEConsole, doSetHeroPosition));
registerCmd("set_life", WRAP_METHOD(TwinEConsole, doSetLife));
registerCmd("set_game_flag", WRAP_METHOD(TwinEConsole, doSetGameFlag));
registerCmd("show_game_flag", WRAP_METHOD(TwinEConsole, doPrintGameFlag));
registerCmd("set_inventory_flag", WRAP_METHOD(TwinEConsole, doSetInventoryFlag));
registerCmd("show_inventory_flag", WRAP_METHOD(TwinEConsole, doPrintInventoryFlag));
registerCmd("set_holomap_flag", WRAP_METHOD(TwinEConsole, doSetHolomapFlag));
registerCmd("set_holomap_trajectory", WRAP_METHOD(TwinEConsole, doSetHolomapTrajectory));
registerCmd("show_holomap_flag", WRAP_METHOD(TwinEConsole, doPrintHolomapFlag));
}
TwinEConsole::~TwinEConsole() {
}
void TwinEConsole::preEnter() {
_engine->_input->resetActionStates();
Super::preEnter();
}
void TwinEConsole::postEnter() {
_engine->_input->resetActionStates();
Super::postEnter();
}
#define TOGGLE_DEBUG(var, description) \
if ((var)) { \
debugPrintf("Disabling " description); \
(var) = false; \
} else { \
debugPrintf("Enabling " description); \
(var) = true; \
}
bool TwinEConsole::doToggleZoneRendering(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_showingZones, "zone rendering\n")
return true;
}
bool TwinEConsole::doToggleActorRendering(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_showingActors, "actor rendering\n")
return true;
}
bool TwinEConsole::doToggleTrackRendering(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_showingTracks, "tracks rendering\n")
return true;
}
bool TwinEConsole::doToggleGodMode(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_godMode, "god mode\n")
return true;
}
bool TwinEConsole::doToggleClipRendering(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_showingClips, "clip rendering\n")
return true;
}
bool TwinEConsole::doToggleSceneryView(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_redraw->_flagMCGA, "scenery view\n")
return true;
}
bool TwinEConsole::doToggleAutoAggressive(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_actor->_combatAuto, "auto aggressive\n")
return true;
}
bool TwinEConsole::doAddMagicPoints(int argc, const char **argv) {
if (argc < 2) {
debugPrintf("Usage: specify the magic points\n");
return true;
}
const int16 magicPoints = atoi(argv[1]);
_engine->_gameState->_magicLevelIdx = CLIP<int16>(magicPoints, 0, 4);
_engine->_gameState->setMaxMagicPoints();
return true;
}
bool TwinEConsole::doSkipSceneActorsBut(int argc, const char **argv) {
if (argc < 2) {
debugPrintf("Usage: give actor id of scene or -1 to disable\n");
return true;
}
const int16 actorIdx = atoi(argv[1]);
debugPrintf("Only load actor %d in the next scene\n", actorIdx);
_engine->_debugState->_onlyLoadActor = actorIdx;
return true;
}
bool TwinEConsole::doToggleFreeCamera(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_useFreeCamera, "free camera movement\n")
return true;
}
bool TwinEConsole::doSetTrackObject(int argc, const char **argv) {
if (argc <= 2) {
debugPrintf("Expected to get a the scene actor number and the track\n");
return true;
}
const int32 otherActorIdx = atoi(argv[1]);
const int32 offset = atoi(argv[2]);
_engine->_scene->getActor(otherActorIdx)->_offsetTrack = offset;
return true;
}
bool TwinEConsole::doToggleSceneRendering(int argc, const char **argv) {
TOGGLE_DEBUG(_engine->_debugState->_disableGridRendering, "scene rendering\n")
return true;
}
bool TwinEConsole::doSetInventoryFlag(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a inventory flag index as first parameter\n");
return true;
}
const uint8 idx = atoi(argv[1]);
if (idx >= NUM_INVENTORY_ITEMS) {
debugPrintf("given index exceeds the max allowed value of %i\n", NUM_INVENTORY_ITEMS - 1);
return true;
}
const uint8 val = argc == 3 ? atoi(argv[2]) : 0;
_engine->_gameState->_inventoryFlags[idx] = val;
return true;
}
bool TwinEConsole::doSetHolomapTrajectory(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a holomap trajectory index as parameter\n");
return true;
}
_engine->_scene->_numHolomapTraj = atoi(argv[1]);
_engine->_scene->reloadCurrentScene();
return false;
}
bool TwinEConsole::doSetHolomapFlag(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a holomap flag index as first parameter. Use -1 to set all flags\n");
return true;
}
GameState* state = _engine->_gameState;
state->setGameFlag(InventoryItems::kiHolomap, 1);
state->_inventoryFlags[InventoryItems::kiHolomap] = 1;
state->setGameFlag(GAMEFLAG_INVENTORY_DISABLED, 0);
const int idx = atoi(argv[1]);
if (idx == -1) {
for (int i = 0; i < _engine->numHoloPos(); ++i) {
_engine->_holomap->setHoloPos(i);
}
return true;
}
if (idx < 0 || idx >= _engine->numHoloPos()) {
debugPrintf("given index exceeds the max allowed value of %i\n", _engine->numHoloPos() - 1);
return true;
}
_engine->_holomap->setHoloPos(idx);
return true;
}
bool TwinEConsole::doSetGameFlag(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a game flag index as first parameter\n");
return true;
}
const uint8 idx = atoi(argv[1]);
const uint8 val = argc == 3 ? atoi(argv[2]) : 0;
_engine->_gameState->setGameFlag(idx, val);
return true;
}
bool TwinEConsole::doPrintGameFlag(int argc, const char **argv) {
if (argc <= 1) {
for (int i = 0; i < NUM_GAME_FLAGS; ++i) {
debugPrintf("[%03d] = %d\n", i, _engine->_gameState->hasGameFlag(i));
}
return true;
}
const uint8 idx = atoi(argv[1]);
debugPrintf("[%03d] = %d\n", idx, _engine->_gameState->hasGameFlag(idx));
return true;
}
bool TwinEConsole::doPrintInventoryFlag(int argc, const char **argv) {
if (argc <= 1) {
for (int i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
debugPrintf("[%03d] = %d\n", i, _engine->_gameState->_inventoryFlags[i]);
}
return true;
}
const uint8 idx = atoi(argv[1]);
if (idx < NUM_INVENTORY_ITEMS) {
debugPrintf("[%03d] = %d\n", idx, _engine->_gameState->_inventoryFlags[idx]);
}
return true;
}
bool TwinEConsole::doPrintHolomapFlag(int argc, const char **argv) {
if (argc <= 1) {
for (int i = 0; i < _engine->numHoloPos(); ++i) {
debugPrintf("[%03d] = %d\n", i, _engine->_gameState->_holomapFlags[i]);
}
return true;
}
const uint16 idx = atoi(argv[1]);
if (idx < _engine->numHoloPos()) {
debugPrintf("[%03d] = %d\n", idx, _engine->_gameState->_holomapFlags[idx]);
}
return true;
}
bool TwinEConsole::doGiveKey(int argc, const char **argv) {
int amount = 1;
if (argc >= 2) {
amount = atoi(argv[1]);
}
_engine->_gameState->addKeys(amount);
return true;
}
bool TwinEConsole::doGiveGas(int argc, const char **argv) {
int amount = 1;
if (argc >= 2) {
amount = atoi(argv[1]);
}
_engine->_gameState->addGas(amount);
return true;
}
bool TwinEConsole::doGiveKashes(int argc, const char **argv) {
int amount = 1;
if (argc >= 2) {
amount = atoi(argv[1]);
}
_engine->_gameState->addKashes(amount);
return true;
}
bool TwinEConsole::doSetHeroPosition(int argc, const char **argv) {
IVec3 &pos = _engine->_scene->_sceneHero->_posObj;
if (argc < 4) {
debugPrintf("Current hero position: %i:%i:%i\n", pos.x, pos.y, pos.z);
return true;
}
pos.x = atoi(argv[1]);
pos.y = atoi(argv[2]);
pos.z = atoi(argv[3]);
return true;
}
bool TwinEConsole::doPlayVideo(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a video filename as first parameter\n");
return true;
}
_engine->queueMovie(argv[1]);
return true;
}
bool TwinEConsole::doPlayMidi(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a midi id as first parameter\n");
return true;
}
int newMidiIndex = atoi(argv[1]);
_engine->_music->playMidiFile(newMidiIndex);
return true;
}
bool TwinEConsole::doPlayMusic(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a music track id as first parameter\n");
return true;
}
int newMusicTrackIndex = atoi(argv[1]);
_engine->_music->playMusic(newMusicTrackIndex);
return true;
}
bool TwinEConsole::doChangeScene(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a scene index as first parameter\n");
return true;
}
byte newSceneIndex = atoi(argv[1]);
if (newSceneIndex >= LBA1SceneId::SceneIdMax) {
debugPrintf("Scene index out of bounds\n");
return true;
}
_engine->_scene->_newCube = atoi(argv[1]);
_engine->_scene->_flagChgCube = ScenePositionType::kScene;
_engine->_scene->changeCube();
return true;
}
bool TwinEConsole::doChangeChapter(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get a chapter index as first parameter\n");
return true;
}
debugPrintf("Old chapter was: %i\n", _engine->_gameState->getChapter());
_engine->_gameState->setChapter(atoi(argv[1]));
return true;
}
bool TwinEConsole::doDumpFile(int argc, const char **argv) {
if (argc <= 2) {
debugPrintf("Expected to get a a hqr file and an index\n");
return true;
}
const char *hqr = argv[1];
const int index = atoi(argv[2]);
const Common::String &targetFileName = Common::String::format("dumps/%03i-%s.dump", index, hqr);
HQR::dumpEntry(hqr, index, targetFileName.c_str());
return true;
}
static const char *ItemNames[] = {
"Holomap",
"MagicBall",
"UseSabre",
"GawleysHorn",
"Tunic",
"BookOfBu",
"SendellsMedallion",
"FlaskOfClearWater",
"RedCard",
"BlueCard",
"IDCard",
"MrMiesPass",
"ProtoPack",
"Snowboard",
"Penguin",
"GasItem",
"PirateFlag",
"MagicFlute",
"SpaceGuitar",
"HairDryer",
"AncesteralKey",
"BottleOfSyrup",
"EmptyBottle",
"FerryTicket",
"Keypad",
"CoffeeCan",
"BonusList",
"CloverLeaf"
};
static_assert(ARRAYSIZE(ItemNames) == InventoryItems::MaxInventoryItems, "Array size doesn't match items");
bool TwinEConsole::doGiveItem(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get an item as first parameter\n");
for (int i = 0; i < ARRAYSIZE(ItemNames); ++i) {
debugPrintf(" - %2i: %s\n", i, ItemNames[i]);
}
return true;
}
byte itemIdx = atoi(argv[1]);
if (itemIdx >= InventoryItems::MaxInventoryItems) {
debugPrintf("Item index out of bounds\n");
return true;
}
GameState* state = _engine->_gameState;
state->setGameFlag(itemIdx, 1);
state->_inventoryFlags[itemIdx] = 1;
state->setGameFlag(GAMEFLAG_INVENTORY_DISABLED, 0);
return true;
}
bool TwinEConsole::doGiveAllItems(int argc, const char **argv) {
GameState* state = _engine->_gameState;
for (int32 i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
state->setGameFlag(i, 1);
state->_inventoryFlags[i] = 1;
}
state->setGameFlag(GAMEFLAG_INVENTORY_DISABLED, 0);
int amount = 1;
if (argc >= 2) {
amount = atoi(argv[1]);
}
state->addKeys(amount);
state->addLeafBoxes(amount);
state->addKashes(amount);
state->addLeafs(amount);
state->addMagicPoints(amount);
state->addGas(amount);
return true;
}
bool TwinEConsole::doSetLife(int argc, const char **argv) {
if (argc <= 1) {
debugPrintf("Expected to get the life points as parameter\n");
return true;
}
_engine->_scene->_sceneHero->setLife(atoi(argv[1]));
return true;
}
} // End of namespace TwinE

View File

@@ -0,0 +1,86 @@
/* 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 TWINE_CONSOLE_H
#define TWINE_CONSOLE_H
#include "gui/debugger.h"
#include "twine/scene/gamestate.h"
namespace TwinE {
class TwinEEngine;
class TwinEConsole : public GUI::Debugger {
private:
using Super = GUI::Debugger;
TwinEEngine *_engine;
bool doToggleSceneryView(int argc, const char **argv);
bool doPlayVideo(int argc, const char **argv);
bool doPlayMidi(int argc, const char **argv);
bool doPlayMusic(int argc, const char **argv);
bool doPrintGameFlag(int argc, const char **argv);
bool doPrintInventoryFlag(int argc, const char **argv);
bool doPrintHolomapFlag(int argc, const char **argv);
bool doSetHeroPosition(int argc, const char **argv);
bool doGiveItem(int argc, const char **argv);
bool doSetLife(int argc, const char **argv);
bool doGiveAllItems(int argc, const char **argv);
bool doChangeScene(int argc, const char **argv);
bool doToggleAutoAggressive(int argc, const char **argv);
bool doGiveKey(int argc, const char **argv);
bool doGiveGas(int argc, const char **argv);
bool doGiveKashes(int argc, const char **argv);
bool doToggleZoneRendering(int argc, const char **argv);
bool doToggleClipRendering(int argc, const char **argv);
bool doToggleActorRendering(int argc, const char **argv);
bool doToggleTrackRendering(int argc, const char **argv);
bool doToggleGodMode(int argc, const char **argv);
bool doToggleFreeCamera(int argc, const char **argv);
bool doToggleSceneRendering(int argc, const char **argv);
bool doSetTrackObject(int argc, const char **argv);
bool doChangeChapter(int argc, const char **argv);
bool doSkipSceneActorsBut(int argc, const char **argv);
bool doSetGameFlag(int argc, const char **argv);
bool doSetInventoryFlag(int argc, const char **argv);
bool doSetHolomapFlag(int argc, const char **argv);
bool doAddMagicPoints(int argc, const char **argv);
bool doDumpFile(int argc, const char **argv);
bool doSetHolomapTrajectory(int argc, const char **argv);
protected:
void preEnter() override;
void postEnter() override;
public:
TwinEConsole(TwinEEngine *engine);
~TwinEConsole() override;
bool exec(const char *file) {
const char *argv[] = {"", file};
return cmdExecFile(2, argv);
}
};
} // End of namespace TwinE
#endif // TWINE_CONSOLE_H

View File

@@ -0,0 +1,237 @@
/* 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 "twine/debugger/debug_state.h"
#include "common/util.h"
#include "twine/menu/interface.h"
#include "twine/menu/menu.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/renderer.h"
#include "twine/scene/grid.h"
#include "twine/scene/scene.h"
#include "twine/text.h"
#include "twine/twine.h"
namespace TwinE {
DebugState::DebugState(TwinEEngine *engine) : _engine(engine) {}
void DebugState::update() {
changeGridCamera();
}
void DebugState::drawClip(const Common::Rect &rect) {
if (!_showingClips) {
return;
}
_engine->_menu->drawRectBorders(rect);
}
void DebugState::projectBoundingBoxPoints(IVec3 *pPoint3d, IVec3 *pPoint3dProjected) {
*pPoint3dProjected = _engine->_renderer->projectPoint(*pPoint3d);
}
bool DebugState::checkZoneType(ZoneType type) const {
return (_typeZones & (1u << (uint32)type)) != 0u;
}
DebugState::ScenePositionsProjected DebugState::calculateBoxPositions(const IVec3 &mins, const IVec3 &maxs) {
ScenePositionsProjected positions;
// compute the points in 3D
positions.frontBottomLeftPoint.x = mins.x - _engine->_grid->_worldCube.x;
positions.frontBottomLeftPoint.y = mins.y - _engine->_grid->_worldCube.y;
positions.frontBottomLeftPoint.z = maxs.z - _engine->_grid->_worldCube.z;
positions.frontBottomRightPoint.x = maxs.x - _engine->_grid->_worldCube.x;
positions.frontBottomRightPoint.y = mins.y - _engine->_grid->_worldCube.y;
positions.frontBottomRightPoint.z = maxs.z - _engine->_grid->_worldCube.z;
positions.frontTopLeftPoint.x = mins.x - _engine->_grid->_worldCube.x;
positions.frontTopLeftPoint.y = maxs.y - _engine->_grid->_worldCube.y;
positions.frontTopLeftPoint.z = maxs.z - _engine->_grid->_worldCube.z;
positions.frontTopRightPoint = maxs - _engine->_grid->_worldCube;
positions.backBottomLeftPoint = mins - _engine->_grid->_worldCube;
positions.backBottomRightPoint.x = maxs.x - _engine->_grid->_worldCube.x;
positions.backBottomRightPoint.y = mins.y - _engine->_grid->_worldCube.y;
positions.backBottomRightPoint.z = mins.z - _engine->_grid->_worldCube.z;
positions.backTopLeftPoint.x = mins.x - _engine->_grid->_worldCube.x;
positions.backTopLeftPoint.y = maxs.y - _engine->_grid->_worldCube.y;
positions.backTopLeftPoint.z = mins.z - _engine->_grid->_worldCube.z;
positions.backTopRightPoint.x = maxs.x - _engine->_grid->_worldCube.x;
positions.backTopRightPoint.y = maxs.y - _engine->_grid->_worldCube.y;
positions.backTopRightPoint.z = mins.z - _engine->_grid->_worldCube.z;
// project all points
projectBoundingBoxPoints(&positions.frontBottomLeftPoint, &positions.frontBottomLeftPoint2D);
projectBoundingBoxPoints(&positions.frontBottomRightPoint, &positions.frontBottomRightPoint2D);
projectBoundingBoxPoints(&positions.frontTopLeftPoint, &positions.frontTopLeftPoint2D);
projectBoundingBoxPoints(&positions.frontTopRightPoint, &positions.frontTopRightPoint2D);
projectBoundingBoxPoints(&positions.backBottomLeftPoint, &positions.backBottomLeftPoint2D);
projectBoundingBoxPoints(&positions.backBottomRightPoint, &positions.backBottomRightPoint2D);
projectBoundingBoxPoints(&positions.backTopLeftPoint, &positions.backTopLeftPoint2D);
projectBoundingBoxPoints(&positions.backTopRightPoint, &positions.backTopRightPoint2D);
return positions;
}
bool DebugState::drawBox(const ScenePositionsProjected &positions, uint8 color) {
bool state = false;
// draw front part
state |= _engine->_interface->drawLine(positions.frontBottomLeftPoint2D.x, positions.frontBottomLeftPoint2D.y, positions.frontTopLeftPoint2D.x, positions.frontTopLeftPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.frontTopLeftPoint2D.x, positions.frontTopLeftPoint2D.y, positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, positions.frontBottomRightPoint2D.x, positions.frontBottomRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.frontBottomRightPoint2D.x, positions.frontBottomRightPoint2D.y, positions.frontBottomLeftPoint2D.x, positions.frontBottomLeftPoint2D.y, color);
// draw top part
state |= _engine->_interface->drawLine(positions.frontTopLeftPoint2D.x, positions.frontTopLeftPoint2D.y, positions.backTopLeftPoint2D.x, positions.backTopLeftPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backTopLeftPoint2D.x, positions.backTopLeftPoint2D.y, positions.backTopRightPoint2D.x, positions.backTopRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backTopRightPoint2D.x, positions.backTopRightPoint2D.y, positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, positions.frontTopLeftPoint2D.x, positions.frontTopLeftPoint2D.y, color);
// draw back part
state |= _engine->_interface->drawLine(positions.backBottomLeftPoint2D.x, positions.backBottomLeftPoint2D.y, positions.backTopLeftPoint2D.x, positions.backTopLeftPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backTopLeftPoint2D.x, positions.backTopLeftPoint2D.y, positions.backTopRightPoint2D.x, positions.backTopRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backTopRightPoint2D.x, positions.backTopRightPoint2D.y, positions.backBottomRightPoint2D.x, positions.backBottomRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backBottomRightPoint2D.x, positions.backBottomRightPoint2D.y, positions.backBottomLeftPoint2D.x, positions.backBottomLeftPoint2D.y, color);
// draw bottom part
state |= _engine->_interface->drawLine(positions.frontBottomLeftPoint2D.x, positions.frontBottomLeftPoint2D.y, positions.backBottomLeftPoint2D.x, positions.backBottomLeftPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backBottomLeftPoint2D.x, positions.backBottomLeftPoint2D.y, positions.backBottomRightPoint2D.x, positions.backBottomRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.backBottomRightPoint2D.x, positions.backBottomRightPoint2D.y, positions.frontBottomRightPoint2D.x, positions.frontBottomRightPoint2D.y, color);
state |= _engine->_interface->drawLine(positions.frontBottomRightPoint2D.x, positions.frontBottomRightPoint2D.y, positions.frontBottomLeftPoint2D.x, positions.frontBottomLeftPoint2D.y, color);
return state;
}
void DebugState::changeGridCamera() {
if (!_useFreeCamera) {
return;
}
Grid *grid = _engine->_grid;
Redraw *redraw = _engine->_redraw;
Input *input = _engine->_input;
if (input->isActionActive(TwinEActionType::DebugGridCameraPressUp)) {
grid->_startCube.z--;
redraw->_firstTime = true;
} else if (input->isActionActive(TwinEActionType::DebugGridCameraPressDown)) {
grid->_startCube.z++;
redraw->_firstTime = true;
}
if (input->isActionActive(TwinEActionType::DebugGridCameraPressLeft)) {
grid->_startCube.x--;
redraw->_firstTime = true;
} else if (input->isActionActive(TwinEActionType::DebugGridCameraPressRight)) {
grid->_startCube.x++;
redraw->_firstTime = true;
}
}
bool DebugState::displayActors() {
bool state = false;
for (int32 a = 0; a < _engine->_scene->_nbObjets; a++) {
const ActorStruct *actorPtr = _engine->_scene->getActor(a);
const IVec3 &pos = actorPtr->posObj();
const BoundingBox &bbox = actorPtr->_boundingBox;
const ScenePositionsProjected &positions = calculateBoxPositions(pos + bbox.mins, pos + bbox.maxs);
if (!drawBox(positions, COLOR_WHITE)) {
continue;
}
const int boxwidth = 75;
const int lineHeight = 14;
const Common::Rect filledRect(positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, positions.frontTopRightPoint2D.x + boxwidth, positions.frontTopRightPoint2D.y + lineHeight);
_engine->_interface->box(filledRect, COLOR_WHITE);
_engine->_menu->drawRectBorders(filledRect);
_engine->drawText(positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, Common::String::format("Actor: %i", a), true, false, boxwidth);
const int16 rleft = positions.frontTopLeftPoint2D.x;
const int16 rtop = positions.backTopLeftPoint2D.y;
const int16 rright = positions.backTopRightPoint2D.x;
const int16 rbottom = positions.frontBottomRightPoint2D.y;
Common::Rect actorRect(rleft, rtop, rright, rbottom);
actorRect.extend(filledRect);
_engine->_redraw->addPhysBox(actorRect);
state = true;
}
return state;
}
// TODO: implement the rendering points of all tracks as a dot with the id
bool DebugState::displayTracks() {
#if 0
for (int i = 0; i < _engine->_scene->sceneNumTracks; i++) {
const Vec3 *trackPoint = &_engine->_scene->sceneTracks[i];
}
#endif
return false;
}
bool DebugState::displayZones() {
bool state = false;
for (int i = 0; i < _engine->_scene->_sceneNumZones; i++) {
const ZoneStruct *zonePtr = &_engine->_scene->_sceneZones[i];
if (!checkZoneType(zonePtr->type)) {
continue;
}
const ScenePositionsProjected &positions = calculateBoxPositions(zonePtr->mins, zonePtr->maxs);
const uint8 color = 15 * 3 + (int)zonePtr->type * 16;
if (!drawBox(positions, color)) {
continue;
}
const int boxwidth = 50;
const int lineHeight = 14;
const Common::Rect filledRect(positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, positions.frontTopRightPoint2D.x + boxwidth, positions.frontTopRightPoint2D.y + lineHeight);
_engine->_interface->box(filledRect, COLOR_WHITE);
_engine->_menu->drawRectBorders(filledRect);
_engine->drawText(positions.frontTopRightPoint2D.x, positions.frontTopRightPoint2D.y, Common::String::format("ID: %i", i), true, false, boxwidth);
state = true;
}
return state;
}
void DebugState::addFrameData(uint32 frameTime, int32 waitMillis, uint32 maxDelay) {
if (!_frameDataRecording) {
return;
}
_frameData.emplace_back(frameTime, waitMillis, maxDelay);
}
void DebugState::renderDebugView() {
if (_showingZones) {
displayZones();
}
if (_showingActors) {
displayActors();
}
if (_showingTracks) {
displayTracks();
}
}
} // namespace TwinE

View File

@@ -0,0 +1,122 @@
/* 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 TWINE_DEBUG_SCENE_H
#define TWINE_DEBUG_SCENE_H
#include "common/array.h"
#include "common/rect.h"
#include "common/scummsys.h"
#include "twine/debugger/ringbuffer.h"
#include "twine/shared.h"
#include <cstdarg>
namespace TwinE {
class TwinEEngine;
class DebugState {
private:
TwinEEngine *_engine;
void projectBoundingBoxPoints(IVec3 *point3d, IVec3 *point3dProjected);
bool checkZoneType(ZoneType type) const;
bool displayZones();
bool displayActors();
bool displayTracks();
struct ScenePositionsProjected {
IVec3 frontBottomLeftPoint;
IVec3 frontBottomRightPoint;
IVec3 frontTopLeftPoint;
IVec3 frontTopRightPoint;
IVec3 backBottomLeftPoint;
IVec3 backBottomRightPoint;
IVec3 backTopLeftPoint;
IVec3 backTopRightPoint;
IVec3 frontBottomLeftPoint2D;
IVec3 frontBottomRightPoint2D;
IVec3 frontTopLeftPoint2D;
IVec3 frontTopRightPoint2D;
IVec3 backBottomLeftPoint2D;
IVec3 backBottomRightPoint2D;
IVec3 backTopLeftPoint2D;
IVec3 backTopRightPoint2D;
};
ScenePositionsProjected calculateBoxPositions(const IVec3 &mins, const IVec3 &maxs);
bool drawBox(const ScenePositionsProjected &positions, uint8 color);
/** Change scenario camera positions */
void changeGridCamera();
public:
DebugState(TwinEEngine *engine);
bool _showingZones = false;
bool _showingActors = false;
bool _showingTracks = false;
bool _showingClips = false;
bool _godMode = false;
unsigned int _typeZones = 127; // all zones on as default
int16 _onlyLoadActor = -1;
const char *_openPopup = nullptr;
bool _holomapFlagsWindow = false;
bool _gameFlagsWindow = false;
bool _menuTextWindow = false;
bool _sceneDetailsWindow = false;
bool _actorDetailsWindow = true;
bool _sceneFlagsWindow = false;
bool _paletteWindow = false;
bool _loggerWindow = false;
bool _frameTimeWindow = false;
bool _frameDataRecording = true;
bool _playFoundItemAnimation = false;
bool _useFreeCamera = false;
bool _disableGridRendering = false;
TextBankId _textBankId = TextBankId::Inventory_Intro_and_Holomap;
void renderDebugView();
void drawClip(const Common::Rect &rect);
struct FrameData {
uint32 frameTime;
int32 waitMillis;
uint32 maxDelay;
};
using FrameDataBuffer = RingBuffer<FrameData, 256>;
FrameDataBuffer _frameData;
void addFrameData(uint32 frameTime, int32 waitMillis, uint32 maxDelay);
void update();
};
} // namespace TwinE
#endif

View File

@@ -0,0 +1,953 @@
/* 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 "twine/debugger/debugtools.h"
#include "backends/imgui/components/imgui_logger.h"
#include "backends/imgui/imgui.h"
#include "backends/imgui/imgui_fonts.h"
#include "backends/imgui/imgui_utils.h"
#include "common/log.h"
#include "common/scummsys.h"
#include "common/str-enc.h"
#include "common/str.h"
#include "common/util.h"
#include "graphics/palette.h"
#include "twine/debugger/debug_state.h"
#include "twine/debugger/dt-internal.h"
#include "twine/holomap.h"
#include "twine/holomap_v1.h"
#include "twine/parser/entity.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/screens.h"
#include "twine/resources/resources.h"
#include "twine/scene/actor.h"
#include "twine/scene/gamestate.h"
#include "twine/scene/grid.h"
#include "twine/scene/scene.h"
#include "twine/shared.h"
#include "twine/twine.h"
namespace ImGuiEx {
bool InputIVec3(const char *label, TwinE::IVec3 &v, ImGuiInputTextFlags flags = 0) {
int tmp[3] = {v.x, v.y, v.z};
ImGui::InputInt3(label, tmp, flags);
if (ImGui::IsItemDeactivatedAfterEdit()) {
v.x = tmp[0];
v.y = tmp[1];
v.z = tmp[2];
return true;
}
return false;
}
bool InputAngle(const char *label, int32 *v, int step = 1, int step_fast = 100, const char *format = "%.2f", ImGuiInputTextFlags flags = 0) {
double tmp = TwinE::AngleToDegree(*v);
if (ImGui::InputDouble(label, &tmp, step, step_fast, format, flags)) {
*v = TwinE::DegreeToAngle(tmp);
return true;
}
ImGui::SetItemTooltip("Angle: %i", (int)*v);
return false;
}
bool InputBoundingBox(ImGuiID id, const char *prefixLabel, TwinE::BoundingBox &bbox) {
TwinE::BoundingBox copy = bbox;
Common::String idStr = Common::String::format("%s mins##mins%u", prefixLabel, id);
if (ImGuiEx::InputIVec3(idStr.c_str(), copy.mins)) {
if (copy.isValid()) {
bbox.mins = copy.mins;
}
return true;
}
idStr = Common::String::format("%s maxs##maxs%u", prefixLabel, id);
if (ImGuiEx::InputIVec3(idStr.c_str(), copy.maxs)) {
if (copy.isValid()) {
bbox.maxs = copy.maxs;
}
return true;
}
return false;
}
} // namespace ImGuiEx
namespace TwinE {
#define HOLOMAP_FLAGS_TITLE "Holomap flags"
#define GAME_FLAGS_TITLE "Game flags"
#define ACTOR_DETAILS_TITLE "Actor"
#define MENU_TEXT_TITLE "Menu texts"
static const char *toString(ShapeType type) {
switch (type) {
case ShapeType::kNone:
return "None";
case ShapeType::kSolid:
return "Solid";
case ShapeType::kStairsTopLeft:
return "StairsTopLeft";
case ShapeType::kStairsTopRight:
return "StairsTopRight";
case ShapeType::kStairsBottomLeft:
return "StairsBottomLeft";
case ShapeType::kStairsBottomRight:
return "StairsBottomRight";
case ShapeType::kDoubleSideStairsTop1:
return "DoubleSideStairsTop1";
case ShapeType::kDoubleSideStairsBottom1:
return "DoubleSideStairsBottom1";
case ShapeType::kDoubleSideStairsLeft1:
return "DoubleSideStairsLeft1";
case ShapeType::kDoubleSideStairsRight1:
return "DoubleSideStairsRight1";
case ShapeType::kDoubleSideStairsTop2:
return "DoubleSideStairsTop2";
case ShapeType::kDoubleSideStairsBottom2:
return "DoubleSideStairsBottom2";
case ShapeType::kDoubleSideStairsLeft2:
return "DoubleSideStairsLeft2";
case ShapeType::kDoubleSideStairsRight2:
return "DoubleSideStairsRight2";
case ShapeType::kFlatBottom1:
return "FlatBottom1";
case ShapeType::kFlatBottom2:
return "FlatBottom2";
default:
return "Unknown";
}
}
static void onLog(LogMessageType::Type type, int level, uint32 debugChannel, const char *message) {
switch (type) {
case LogMessageType::kError:
_logger->addLog("[error]%s", message);
break;
case LogMessageType::kWarning:
_logger->addLog("[warn]%s", message);
break;
case LogMessageType::kInfo:
_logger->addLog("%s", message);
break;
case LogMessageType::kDebug:
_logger->addLog("[debug]%s", message);
break;
}
}
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);
_tinyFont = ImGui::addTTFFontFromArchive("LiberationSans-Regular.ttf", 10.0f, nullptr, nullptr);
_logger = new ImGuiEx::ImGuiLogger;
Common::setLogWatcher(onLog);
}
static void holomapFlagsWindow(TwinEEngine *engine) {
if (!engine->_debugState->_holomapFlagsWindow) {
return;
}
if (ImGui::Begin(HOLOMAP_FLAGS_TITLE, &engine->_debugState->_holomapFlagsWindow)) {
if (ImGui::BeginTable("###holomapflags", 8)) {
for (int i = 0; i < engine->numHoloPos(); ++i) {
ImGui::TableNextColumn();
Common::String id = Common::String::format("[%03d]", i);
ImGuiEx::InputInt(id.c_str(), &engine->_gameState->_holomapFlags[i]);
ImGui::SetItemTooltip("%s", engine->_holomap->getLocationName(i));
}
ImGui::EndTable();
}
if (engine->isLBA1()) {
HolomapV1 *holomap = (HolomapV1*)engine->_holomap;
ImGuiEx::InputInt("current", &holomap->_current);
ImGuiEx::InputInt("otimer", &holomap->_otimer);
ImGuiEx::InputInt("dalpha", &holomap->_dalpha);
ImGuiEx::InputInt("dbeta", &holomap->_dbeta);
ImGuiEx::InputInt("calpha", &holomap->_calpha);
ImGuiEx::InputInt("cbeta", &holomap->_cbeta);
ImGuiEx::InputInt("cgamma", &holomap->_cgamma);
ImGuiEx::InputInt("oalpha", &holomap->_oalpha);
ImGuiEx::InputInt("obeta", &holomap->_obeta);
ImGui::Checkbox("automove", &holomap->_automove);
ImGui::Checkbox("flagredraw", &holomap->_flagredraw);
ImGui::Checkbox("dialstat", &holomap->_dialstat);
ImGui::Checkbox("flagpal", &holomap->_flagpal);
}
}
ImGui::End();
}
static void paletteWindow(TwinEEngine *engine) {
if (!engine->_debugState->_paletteWindow) {
return;
}
const ImVec2 available = ImGui::GetContentRegionAvail();
const float contentRegionHeight = available.y + ImGui::GetCursorPosY();
const ImVec2 windowSize(10.0f * ImGui::GetFrameHeight(), contentRegionHeight);
ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Palettes", &engine->_debugState->_paletteWindow)) {
if (engine->_screens->_flagPalettePcx) {
ImGui::Text("palettepcx is active");
} else {
ImGui::Text("ptrpal is active");
}
ImGui::SeparatorText("Front buffer palette");
const Graphics::Palette &frontBufferPalette = engine->_frontVideoBuffer.getPalette();
ImGui::PushID("frontBufferPalette");
ImGuiEx::Palette(frontBufferPalette);
ImGui::PopID();
ImGui::SeparatorText("PalettePCX");
ImGui::PushID("palettePcx");
ImGuiEx::Palette(engine->_screens->_palettePcx);
ImGui::PopID();
ImGui::SeparatorText("Palette");
ImGui::PushID("ptrPal");
ImGuiEx::Palette(engine->_screens->_ptrPal);
ImGui::PopID();
}
ImGui::End();
}
static float WaitTime(void *data, int i) {
TwinE::DebugState::FrameDataBuffer &buffer = *(TwinE::DebugState::FrameDataBuffer *)data;
return (float)buffer[i].waitMillis;
}
static float FrameTime(void *data, int i) {
TwinE::DebugState::FrameDataBuffer &buffer = *(TwinE::DebugState::FrameDataBuffer *)data;
return (float)buffer[i].frameTime;
}
static void frameTimeWindow(TwinEEngine *engine) {
if (!engine->_debugState->_frameTimeWindow) {
return;
}
if (ImGui::Begin("Frame time", &engine->_debugState->_frameTimeWindow)) {
ImGui::Checkbox("Record", &engine->_debugState->_frameDataRecording);
ImGui::PlotHistogram("Wait time", WaitTime, &engine->_debugState->_frameData, (int)engine->_debugState->_frameData.size(), 0, "Wait time in millis", -100.0f, 100.0f, ImVec2(0, 80));
ImGui::PlotHistogram("Frame time", FrameTime, &engine->_debugState->_frameData, (int)engine->_debugState->_frameData.size(), 0, "Frame time in millis", -100.0f, 100.0f, ImVec2(0, 80));
}
ImGui::End();
}
static void sceneFlagsWindow(TwinEEngine *engine) {
if (!engine->_debugState->_sceneFlagsWindow) {
return;
}
if (ImGui::Begin("Scene flags", &engine->_debugState->_sceneFlagsWindow)) {
if (ImGui::BeginTable("###sceneflags", 8)) {
for (int i = 0; i < NUM_SCENES_FLAGS; ++i) {
ImGui::TableNextColumn();
Common::String id = Common::String::format("[%03d]", i);
ImGuiEx::InputInt(id.c_str(), &engine->_scene->_listFlagCube[i]);
}
ImGui::EndTable();
}
}
ImGui::End();
}
static void gameFlagsWindow(TwinEEngine *engine) {
if (!engine->_debugState->_gameFlagsWindow) {
return;
}
if (ImGui::Begin(GAME_FLAGS_TITLE, &engine->_debugState->_gameFlagsWindow)) {
ImGui::Text("Chapter %i", engine->_gameState->getChapter());
if (ImGui::BeginTable("###gameflags", 8)) {
for (int i = 0; i < NUM_GAME_FLAGS; ++i) {
ImGui::TableNextColumn();
Common::String id = Common::String::format("[%03d]", i);
int16 val = engine->_gameState->hasGameFlag(i);
if (ImGuiEx::InputInt(id.c_str(), &val)) {
engine->_gameState->setGameFlag(i, val);
}
}
ImGui::EndTable();
}
}
ImGui::End();
}
static void menuTextsWindow(TwinEEngine *engine) {
if (!engine->_debugState->_menuTextWindow) {
return;
}
if (ImGui::Begin(MENU_TEXT_TITLE, &engine->_debugState->_menuTextWindow)) {
int id = (int)engine->_debugState->_textBankId;
if (ImGui::InputInt("Text bank", &id)) {
engine->_debugState->_textBankId = (TextBankId)id;
}
const TextBankId oldTextBankId = engine->_text->textBank();
engine->_text->initDial(engine->_debugState->_textBankId);
for (int32 i = 0; i < 1000; ++i) {
char buf[256];
if (engine->_text->getMenuText((TextId)i, buf, sizeof(buf))) {
ImGui::Text("%4i: %s\n", i, buf);
}
}
engine->_text->initDial(oldTextBankId);
}
ImGui::End();
}
static void sceneSelectionCombo(TwinEEngine *engine) {
Scene *scene = engine->_scene;
GameState *gameState = engine->_gameState;
Common::U32String originalSceneName(gameState->_sceneName, Common::kDos850);
const Common::String sceneName = originalSceneName.encode(Common::kUtf8);
if (ImGui::BeginCombo("Scene", sceneName.c_str())) {
for (int i = 0; i < engine->numHoloPos(); ++i) {
Common::U32String originalLocationName(engine->_holomap->getLocationName(i), Common::kDos850);
const Common::String locationName = originalLocationName.encode(Common::kUtf8);
Common::String name = Common::String::format("[%03d] %s", i, locationName.c_str());
if (ImGui::Selectable(name.c_str(), i == engine->_scene->_numCube)) {
scene->_numCube = i;
scene->_newCube = scene->_numCube;
engine->_redraw->_firstTime = true;
}
}
ImGui::EndCombo();
}
}
static const struct ZonesDesc {
const char *name;
ZoneType type;
const char *desc;
} ZoneDescriptions[] = {
{"Cube", ZoneType::kCube, "Change to another scene"},
{"Camera", ZoneType::kCamera, "Binds camera view"},
{"Sceneric", ZoneType::kSceneric, "For use in Life Script"},
{"Grid", ZoneType::kGrid, "Set disappearing Grid fragment"},
{"Object", ZoneType::kObject, "Give bonus"},
{"Text", ZoneType::kText, "Displays text message"},
{"Ladder", ZoneType::kLadder, "Hero can climb on it"},
{"Escalator", ZoneType::kEscalator, nullptr},
{"Hit", ZoneType::kHit, nullptr},
{"Rail", ZoneType::kRail, nullptr}};
static void sceneDetailsWindows(TwinEEngine *engine) {
if (!engine->_debugState->_sceneDetailsWindow) {
return;
}
if (ImGui::Begin("Scene", &engine->_debugState->_sceneDetailsWindow)) {
Scene *scene = engine->_scene;
GameState *gameState = engine->_gameState;
ImGui::Text("Scene: %i", scene->_numCube);
ImGui::Text("Scene name: %s", gameState->_sceneName);
sceneSelectionCombo(engine);
if (ImGui::Checkbox("Bounding boxes", &engine->_debugState->_showingActors)) {
engine->_redraw->_firstTime = true;
}
if (ImGui::Checkbox("Clipping", &engine->_debugState->_showingClips)) {
engine->_redraw->_firstTime = true;
}
if (ImGui::Checkbox("Zones", &engine->_debugState->_showingZones)) {
engine->_redraw->_firstTime = true;
}
// if (ImGui::Checkbox("Tracks", &engine->_debugState->_showingTracks)) {
// engine->_redraw->_firstTime = true;
// }
if (engine->_debugState->_showingZones) {
if (ImGui::CollapsingHeader("Show zone types")) {
for (int i = 0; i < ARRAYSIZE(ZoneDescriptions); ++i) {
if (ImGui::CheckboxFlags(ZoneDescriptions[i].name, &engine->_debugState->_typeZones, (1u << (uint32)ZoneDescriptions[i].type))) {
engine->_redraw->_firstTime = true;
}
if (ZoneDescriptions[i].desc) {
ImGui::SetItemTooltip(ZoneDescriptions[i].desc);
}
}
}
}
if (ImGui::CollapsingHeader("Zones##zonesheader")) {
for (int i = 0; i < scene->_sceneNumZones; ++i) {
ZoneStruct *zone = &scene->_sceneZones[i];
ImGui::Text("Zone idx: %i", i);
ImGui::Indent();
const ZonesDesc &zoneDesc = ZoneDescriptions[(int)zone->type];
ImGui::Text("Type: %s", zoneDesc.name);
if (zoneDesc.desc != nullptr) {
ImGui::SameLine();
ImGui::Text("%s", zoneDesc.desc);
}
ImGui::PushID(i);
ImGuiEx::InputIVec3("Mins", zone->mins);
ImGuiEx::InputIVec3("Maxs", zone->maxs);
ImGui::PopID();
ImGui::Text("Num: %i", zone->num);
ImGui::Text("Info0: %i", zone->infoData.generic.info0);
ImGui::Text("Info1: %i", zone->infoData.generic.info1);
ImGui::Text("Info2: %i", zone->infoData.generic.info2);
ImGui::Text("Info3: %i", zone->infoData.generic.info3);
ImGui::Text("Info4: %i", zone->infoData.generic.info4);
ImGui::Text("Info5: %i", zone->infoData.generic.info5);
ImGui::Text("Info6: %i", zone->infoData.generic.info6);
ImGui::Text("Info7: %i", zone->infoData.generic.info7);
ImGui::Unindent();
}
}
if (ImGui::CollapsingHeader("Tracks##tracksheader")) {
for (int i = 0; i < scene->_sceneNumTracks; ++i) {
ImGui::Text("Track %i: %i %i %i", i, scene->_sceneTracks[i].x, scene->_sceneTracks[i].y, scene->_sceneTracks[i].z);
}
}
if (ImGui::CollapsingHeader("Trajectories##trajectoriesheader")) {
const TrajectoryData &trajectories = engine->_resources->getTrajectories();
for (int i = 0; i < (int)trajectories.getTrajectories().size(); ++i) {
const Trajectory *trajectory = trajectories.getTrajectory(i);
ImGui::Text("Trajectory %i", i);
ImGui::SameLine();
Common::String buttonId = Common::String::format("Activate##activateTrajectory%i", i);
if (ImGui::Button(buttonId.c_str())) {
scene->_numHolomapTraj = i;
scene->reloadCurrentScene();
}
ImGui::Indent();
ImGui::Text("location: %i", trajectory->locationIdx);
ImGui::Text("trajectory location: %i", trajectory->trajLocationIdx);
ImGui::Text("vehicle: %i", trajectory->vehicleIdx);
ImGui::Text("pos: %i %i %i", trajectory->angle.x, trajectory->angle.y, trajectory->angle.z);
ImGui::Text("num anim frames: %i", trajectory->numAnimFrames);
ImGui::Unindent();
}
}
ImGuiEx::InputInt("Previous scene index", &scene->_oldcube);
ImGuiEx::InputInt("Need change scene index", &scene->_newCube);
ImGui::Text("Climbing flag");
ImGui::SameLine();
ImGuiEx::Boolean(scene->_flagClimbing);
ImGuiEx::InputInt("Currently followed actor", &scene->_numObjFollow);
ImGui::Checkbox("Render grid tiles", &scene->_flagRenderGrid);
ImGuiEx::InputInt("Current script value", &scene->_currentScriptValue);
ImGuiEx::InputInt("Talking actor", &scene->_talkingActor);
ImGuiEx::InputInt("Cube jingle", &scene->_cubeJingle);
ImGuiEx::InputIVec3("New hero pos", scene->_sceneStart);
ImGuiEx::InputInt("Alpha light", &scene->_alphaLight);
ImGuiEx::InputInt("Beta light", &scene->_betaLight);
ImGuiEx::InputInt("Fall Y position", &scene->_startYFalling);
ImGui::Text("Hero position type: %i", (int)scene->_flagChgCube);
}
ImGui::End();
}
static void actorDetailsWindow(int &actorIdx, TwinEEngine *engine) {
if (!engine->_debugState->_actorDetailsWindow) {
return;
}
ActorStruct *actor = engine->_scene->getActor(actorIdx);
if (actor == nullptr) {
return;
}
if (ImGui::Begin(ACTOR_DETAILS_TITLE, &engine->_debugState->_actorDetailsWindow)) {
if (actorIdx < 0 || actorIdx > engine->_scene->_nbObjets) {
actorIdx = 0;
}
Common::String currentActorLabel = Common::String::format("Actor %i", actorIdx);
if (ImGui::BeginCombo("Actor", currentActorLabel.c_str())) {
for (int i = 0; i < engine->_scene->_nbObjets; ++i) {
Common::String label = Common::String::format("Actor %i", i);
if (engine->_scene->_mecaPenguinIdx == i) {
label += " (Penguin)";
}
const bool selected = i == actorIdx;
if (ImGui::Selectable(label.c_str(), selected)) {
actorIdx = i;
}
}
ImGui::EndCombo();
}
ImGui::Separator();
ImGuiEx::InputIVec3("Pos", actor->_posObj);
ImGuiEx::InputAngle("Rotation", &actor->_beta);
ImGuiEx::InputInt("Rotation speed", &actor->_srot);
ImGuiEx::InputInt("Life", &actor->_lifePoint);
ImGuiEx::InputInt("Armor", &actor->_armor);
ImGuiEx::InputBoundingBox(actorIdx, "Bounding box", actor->_boundingBox);
if (ImGui::CollapsingHeader("Properties")) {
if (ImGui::BeginTable("Properties", 2)) {
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
ImGui::Text("Followed");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_followedActor);
ImGui::TableNextColumn();
ImGui::Text("Control mode");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_move);
ImGui::TableNextColumn();
ImGui::Text("Delay");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_delayInMillis);
ImGui::TableNextColumn();
ImGui::Text("Strength");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_hitForce);
ImGui::TableNextColumn();
ImGui::Text("Hit by");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_hitBy);
ImGui::TableNextColumn();
ImGui::Text("Bonus");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_bonusParameter);
ImGui::TableNextColumn();
ImGui::Text("ZoneSce");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_zoneSce);
ImGui::TableNextColumn();
ImGui::Text("Brick shape");
ImGui::TableNextColumn();
ImGui::Text("%s", toString(actor->brickShape()));
ImGui::TableNextColumn();
ImGui::Text("Brick causes damage");
ImGui::TableNextColumn();
ImGuiEx::Boolean(actor->brickCausesDamage());
ImGui::TableNextColumn();
ImGui::Text("Collision");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_objCol);
ImGui::TableNextColumn();
ImGui::Text("Carried by");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_carryBy);
ImGui::TableNextColumn();
ImGui::Text("Talk color");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_talkColor);
ImGui::TableNextColumn();
ImGui::Text("Body");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_body); // TODO: link to resources
ImGui::TableNextColumn();
ImGui::Text("Gen body");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_genBody);
ImGui::TableNextColumn();
ImGui::Text("Save gen body");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_saveGenBody);
ImGui::TableNextColumn();
ImGui::Text("Gen anim");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_genAnim);
ImGui::TableNextColumn();
ImGui::Text("Next gen anim");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_nextGenAnim);
ImGui::TableNextColumn();
ImGui::Text("Ptr anim action");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_ptrAnimAction);
ImGui::TableNextColumn();
ImGui::Text("Sprite");
ImGui::TableNextColumn();
ImGui::Text("%i", actor->_sprite);
ImGui::TableNextColumn();
ImGui::Text("A3DS");
ImGui::TableNextColumn();
ImGui::Text("%i %i %i", actor->A3DS.Num, actor->A3DS.Deb, actor->A3DS.Fin);
ImGui::EndTable();
}
}
if (ImGui::CollapsingHeader("Work Flags")) {
static const char *Names[] = {
"WAIT_HIT_FRAME",
"OK_HIT",
"ANIM_END",
"NEW_FRAME",
"WAS_DRAWN",
"OBJ_DEAD",
"AUTO_STOP_DOOR",
"ANIM_MASTER_ROT",
"FALLING",
"IS_TARGETABLE",
"IS_BLINKING",
"DRAW_SHADOW",
"ANIM_MASTER_GRAVITY",
"SKATING",
"OK_RENVOIE",
"LEFT_JUMP",
"RIGHT_JUMP",
"WAIT_SUPER_HIT",
"TRACK_MASTER_ROT",
"FLY_JETPACK",
"DONT_PICK_CODE_JEU",
"MANUAL_INTER_FRAME",
"WAIT_COORD",
"CHECK_FALLING"};
if (ImGui::BeginTable("##workflags", 6)) {
for (int i = 0; i < ARRAYSIZE(Names); ++i) {
ImGui::TableNextColumn();
ImGui::CheckboxFlags(Names[i], (uint32_t *)&actor->_workFlags, (1 << i));
}
ImGui::EndTable();
}
}
if (ImGui::CollapsingHeader("Flags")) {
static const char *Names[] = {
"CHECK_OBJ_COL",
"CHECK_BRICK_COL",
"CHECK_ZONE",
"SPRITE_CLIP",
"PUSHABLE",
"COL_BASSE",
"CHECK_CODE_JEU",
"CHECK_WATER_COL",
"0x000100",
"INVISIBLE",
"SPRITE_3D",
"OBJ_FALLABLE",
"NO_SHADOW",
"OBJ_BACKGROUND",
"OBJ_CARRIER",
"MINI_ZV",
"POS_INVALIDE",
"NO_CHOC",
"ANIM_3DS",
"NO_PRE_CLIP",
"OBJ_ZBUFFER",
"OBJ_IN_WATER",
};
if (ImGui::BeginTable("##staticflags", 6)) {
for (int i = 0; i < ARRAYSIZE(Names); ++i) {
ImGui::TableNextColumn();
ImGui::CheckboxFlags(Names[i], (uint32_t *)&actor->_flags, (1 << i));
}
ImGui::EndTable();
}
}
if (actor->_body != -1) {
ImGui::SeparatorText("Body");
if (actor->_entityDataPtr != nullptr) {
BodyData &bodyData = actor->_entityDataPtr->getBody(actor->_body);
ImGuiEx::InputBoundingBox((int)(uintptr)&bodyData, "Bounding box", bodyData.bbox);
} else {
ImGui::Text("No entity data");
}
}
ImGui::SeparatorText("Entity");
EntityData &entityData = actor->_entityData;
Common::Array<EntityBody> &entityBodies = entityData.getBodies();
ImGui::Text("Bodies: %i", (int)entityBodies.size());
for (EntityBody &entityBody : entityBodies) {
ImGui::Text("%s index: %i", Resources::HQR_FILE3D_FILE, entityBody.index);
ImGui::Indent();
ImGui::Text("%s index: %i", Resources::HQR_BODY_FILE, entityBody.hqrBodyIndex);
Common::String id = Common::String::format("Has bounding box##%i", entityBody.index);
ImGui::Checkbox(id.c_str(), &entityBody.actorBoundingBox.hasBoundingBox);
ImGuiEx::InputBoundingBox((int)(uintptr)&entityBody, "Bounding box", entityBody.actorBoundingBox.bbox);
ImGui::Unindent();
}
Common::Array<EntityAnim> &animations = entityData.getAnimations();
ImGui::Text("Animations: %i", (int)animations.size());
for (EntityAnim &animation : animations) {
ImGui::Text("Animation type: %i", (int)animation.animation);
ImGui::Indent();
ImGui::Text("Body animation index: %i", (int)animation.animIndex);
ImGui::Text("actions: %i", (int)animation._actions.size());
for (EntityAnim::Action &action : animation._actions) {
ImGui::BulletText("%i", (int)action.type);
}
ImGui::Unindent();
}
}
ImGui::End();
}
static void gameStateMenu(TwinEEngine *engine) {
if (ImGui::BeginMenu("Game State")) {
int keys = engine->_gameState->_nbLittleKeys;
if (ImGui::InputInt("Keys", &keys)) {
engine->_gameState->setKeys(keys);
}
int kashes = engine->_gameState->_goldPieces;
if (ImGui::InputInt("Cash", &kashes)) {
engine->_gameState->setKashes(kashes);
}
int zlitos = engine->_gameState->_zlitosPieces;
if (ImGui::InputInt("Zlitos", &zlitos)) {
engine->_gameState->setZlitos(zlitos);
}
int magicPoints = engine->_gameState->_magicPoint;
if (ImGui::InputInt("Magic points", &magicPoints)) {
engine->_gameState->setMagicPoints(magicPoints);
}
int magicLevel = engine->_gameState->_magicLevelIdx;
if (ImGui::InputInt("Magic level", &magicLevel)) {
engine->_gameState->_magicLevelIdx = CLIP<int16>(magicLevel, 0, 4);
}
int leafs = engine->_gameState->_inventoryNumLeafs;
if (ImGui::InputInt("Leafs", &leafs)) {
engine->_gameState->setLeafs(leafs);
}
int leafBoxes = engine->_gameState->_inventoryNumLeafsBox;
if (ImGui::InputInt("Leaf boxes", &leafBoxes)) {
engine->_gameState->setLeafBoxes(leafBoxes);
}
int gas = engine->_gameState->_inventoryNumGas;
if (ImGui::InputInt("Gas", &gas)) {
engine->_gameState->setGas(gas);
}
const TextBankId oldTextBankId = engine->_text->textBank();
engine->_text->initDial(TextBankId::Inventory_Intro_and_Holomap);
for (int i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
Common::String label;
if (engine->_text->getText((TextId)(100 + i))) {
Common::U32String original(engine->_text->_currDialTextEntry->string, Common::kDos850);
label = original.encode(Common::kUtf8).substr(0, 30);
} else {
label = Common::String::format("Item %i", i);
}
uint8 &value = engine->_gameState->_inventoryFlags[i];
bool hasItem = value != 0;
if (ImGui::Checkbox(label.c_str(), &hasItem)) {
value = hasItem == 0 ? 0 : 1;
}
}
engine->_text->initDial(oldTextBankId);
ImGui::EndMenu();
}
}
static void gridMenu(TwinEEngine *engine) {
if (ImGui::BeginMenu("Grid")) {
ImGui::Text("World cube %i %i %i", engine->_grid->_worldCube.x, engine->_grid->_worldCube.y, engine->_grid->_worldCube.z);
#if 0
Grid *grid = engine->_grid;
if (ImGui::Button(ICON_MS_ADD)) {
grid->_cellingGridIdx++;
if (grid->_cellingGridIdx > 133) {
grid->_cellingGridIdx = 133;
}
}
if (ImGui::Button(ICON_MS_REMOVE)) {
grid->_cellingGridIdx--;
if (grid->_cellingGridIdx < 0) {
grid->_cellingGridIdx = 0;
}
}
// Enable/disable celling grid
if (ImGui::Button("Apply ceiling grid")) {
if (grid->_useCellingGrid == -1) {
grid->_useCellingGrid = 1;
// grid->createGridMap();
grid->initCellingGrid(grid->_cellingGridIdx);
debug("Enable Celling Grid index: %d", grid->_cellingGridIdx);
engine->_scene->_needChangeScene = SCENE_CEILING_GRID_FADE_2; // tricky to make the fade
} else if (grid->_useCellingGrid == 1) {
grid->_useCellingGrid = -1;
grid->copyMapToCube();
engine->_redraw->_firstTime = true;
debug("Disable Celling Grid index: %d", grid->_cellingGridIdx);
engine->_scene->_needChangeScene = SCENE_CEILING_GRID_FADE_2; // tricky to make the fade
}
}
#endif
ImGui::EndMenu();
}
}
static void debuggerMenu(TwinEEngine *engine) {
if (ImGui::BeginMenu("Debugger")) {
ImGui::Text("Timer: %i", (int)engine->timerRef);
if (ImGui::MenuItem("Logs")) {
engine->_debugState->_loggerWindow = true;
}
if (ImGui::MenuItem("Texts")) {
engine->_debugState->_menuTextWindow = true;
}
if (ImGui::MenuItem("Holomap flags")) {
engine->_debugState->_holomapFlagsWindow = true;
}
if (ImGui::MenuItem("Game flags")) {
engine->_debugState->_gameFlagsWindow = true;
}
if (ImGui::MenuItem("Scene details")) {
engine->_debugState->_sceneDetailsWindow = true;
}
if (ImGui::MenuItem("Scene flags")) {
engine->_debugState->_sceneFlagsWindow = true;
}
if (ImGui::MenuItem("Actor details")) {
engine->_debugState->_actorDetailsWindow = true;
}
if (ImGui::MenuItem("Frame time")) {
engine->_debugState->_frameTimeWindow = true;
}
ImGui::SeparatorText("Actions");
if (ImGui::MenuItem("Center actor")) {
ActorStruct *actor = engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
actor->_posObj = engine->_grid->_worldCube;
actor->_posObj.y += 16 * SIZE_BRICK_Y;
int32 y = actor->_posObj.y - 1 - SIZE_BRICK_Y;
while (y > 0 && ShapeType::kNone == engine->_grid->worldColBrick(actor->_posObj.x, y, actor->_posObj.z)) {
y -= SIZE_BRICK_Y;
}
actor->_posObj.y = (y + SIZE_BRICK_Y) & ~(SIZE_BRICK_Y - 1);
}
if (ImGui::BeginMenu("Animations")) {
if (ImGui::MenuItem("Found item")) {
engine->_debugState->_playFoundItemAnimation = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Palettes")) {
LifeScriptContext fakeCtx(0, engine->_scene->_sceneHero);
if (ImGui::MenuItem("Show palette")) {
engine->_debugState->_paletteWindow = true;
}
if (ImGui::MenuItem("Dark palette")) {
engine->_scriptLife->lSET_DARK_PAL(engine, fakeCtx);
}
if (ImGui::MenuItem("Normal palette")) {
engine->_scriptLife->lSET_NORMAL_PAL(engine, fakeCtx);
}
#if 0
// TODO: the fade functions are blocking and break the imgui begin/end cycle
if (ImGui::MenuItem("lFADE_PAL_RED")) {
engine->_scriptLife->lFADE_PAL_RED(engine, fakeCtx);
}
if (ImGui::MenuItem("lFADE_ALARM_RED")) {
engine->_scriptLife->lFADE_ALARM_RED(engine, fakeCtx);
}
if (ImGui::MenuItem("lFADE_ALARM_PAL")) {
engine->_scriptLife->lFADE_ALARM_PAL(engine, fakeCtx);
}
if (ImGui::MenuItem("lFADE_RED_PAL")) {
engine->_scriptLife->lFADE_RED_PAL(engine, fakeCtx);
}
if (ImGui::MenuItem("lFADE_RED_ALARM")) {
engine->_scriptLife->lFADE_RED_ALARM(engine, fakeCtx);
}
if (ImGui::MenuItem("lFADE_PAL_ALARM")) {
engine->_scriptLife->lFADE_PAL_ALARM(engine, fakeCtx);
}
#endif
ImGui::EndMenu();
}
if (ImGui::MenuItem("Force Redraw")) {
engine->_redraw->_firstTime = true;
}
ImGui::SeparatorText("Options");
ImGui::Checkbox("Free camera", &engine->_debugState->_useFreeCamera);
ImGui::Checkbox("God mode", &engine->_debugState->_godMode);
sceneSelectionCombo(engine);
ImGui::EndMenu();
}
}
void onImGuiRender() {
if (!debugChannelSet(-1, kDebugImGui)) {
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse;
return;
}
static int currentActor = 0;
ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags &= ~(ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse);
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
TwinEEngine *engine = (TwinEEngine *)g_engine;
if (ImGui::BeginMainMenuBar()) {
debuggerMenu(engine);
gameStateMenu(engine);
gridMenu(engine);
ImGui::EndMainMenuBar();
}
actorDetailsWindow(currentActor, engine);
sceneDetailsWindows(engine);
menuTextsWindow(engine);
holomapFlagsWindow(engine);
gameFlagsWindow(engine);
paletteWindow(engine);
sceneFlagsWindow(engine);
frameTimeWindow(engine);
_logger->draw("Logger", &engine->_debugState->_loggerWindow);
if (engine->_debugState->_openPopup) {
ImGui::OpenPopup(engine->_debugState->_openPopup);
engine->_debugState->_openPopup = nullptr;
}
}
void onImGuiCleanup() {
Common::setLogWatcher(nullptr);
delete _logger;
_logger = nullptr;
}
} // namespace TwinE

View File

@@ -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 TWINE_DEBUGGER_DEBUGTOOLS_H
#define TWINE_DEBUGGER_DEBUGTOOLS_H
namespace TwinE {
void onImGuiInit();
void onImGuiRender();
void onImGuiCleanup();
} // namespace TwinE
#endif

View File

@@ -0,0 +1,34 @@
/* 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 TWINE_DEBUGGER_DT_INTERNAL_H
#define TWINE_DEBUGGER_DT_INTERNAL_H
#include "backends/imgui/components/imgui_logger.h"
namespace TwinE {
ImFont *_tinyFont = nullptr;
ImGuiEx::ImGuiLogger *_logger = nullptr;
} // namespace TwinE
#endif

View File

@@ -0,0 +1,215 @@
/**
* @file
*/
#pragma once
#include "common/util.h"
#include <stddef.h>
namespace TwinE {
/**
* @brief Non allocating buffer class holds a maximum of given entries and allows an endless insert
* by overrinding previous elements in the buffer
*/
template<typename TYPE, size_t SIZE = 64u>
class RingBuffer {
protected:
size_t _size;
size_t _front;
size_t _back;
TYPE _buffer[SIZE];
public:
using value_type = TYPE;
RingBuffer() : _size(0u), _front(0u), _back(SIZE - 1u) {
}
class iterator {
private:
RingBuffer *_ringBuffer;
size_t _idx;
public:
iterator(RingBuffer *ringBuffer, size_t idx) : _ringBuffer(ringBuffer), _idx(idx) {
}
inline const TYPE &operator*() const {
return _ringBuffer->_buffer[_idx % _ringBuffer->capacity()];
}
inline TYPE &operator*() {
return _ringBuffer->_buffer[_idx % _ringBuffer->capacity()];
}
inline const TYPE &operator()() const {
return _ringBuffer->_buffer[_idx % _ringBuffer->capacity()];
}
inline TYPE &operator()() {
return _ringBuffer->_buffer[_idx % _ringBuffer->capacity()];
}
iterator &operator++() {
++_idx;
return *this;
}
inline bool operator!=(const iterator &rhs) const {
return _ringBuffer != rhs._ringBuffer || _idx != rhs._idx;
}
inline bool operator==(const iterator &rhs) const {
return _ringBuffer == rhs._ringBuffer && _idx == rhs._idx;
}
inline const TYPE *operator->() const {
return &_ringBuffer->_buffer[_idx % _ringBuffer->capacity()];
}
};
iterator begin() {
return iterator(this, _front);
}
iterator end() {
return iterator(this, _front + _size);
}
iterator begin() const {
return iterator(const_cast<RingBuffer *>(this), _front);
}
iterator end() const {
return iterator(const_cast<RingBuffer *>(this), _front + _size);
}
inline size_t size() const {
return _size;
}
constexpr size_t capacity() const {
return SIZE;
}
inline bool empty() const {
return _size == 0;
}
/**
* @brief Access to the first element in the buffer
* @note This is not the same as accessing the index 0 element
*/
const TYPE &front() const {
return _buffer[_front];
}
/**
* @brief Access to the first element in the buffer
* @note This is not the same as accessing the index 0 element
*/
TYPE &front() {
return _buffer[_front];
}
/**
* @brief Access to the last element in the buffer
* @note This is not the same as accessing the index @c size-1 element
*/
const TYPE &back() const {
return _buffer[_back];
}
/**
* @brief Access to the last element in the buffer
* @note This is not the same as accessing the index @c size-1 element
*/
TYPE &back() {
return _buffer[_back];
}
/**
* @brief Clears the whole ring buffer
* @note Does not call any destructors - they are called when the buffer itself gets destroyed
*/
void clear() {
_front = 0u;
_back = SIZE - 1u;
_size = 0u;
}
/**
* @brief Pushes an element to the end of the buffer
*/
void push_back(const TYPE &x) {
_back = (_back + 1u) % SIZE;
if (_size == SIZE) {
_front = (_front + 1u) % SIZE;
} else {
++_size;
}
_buffer[_back] = x;
}
/**
* @brief Pushes an elements to the end of the buffer
* @note Performs a move operation
*/
template<typename... _Args>
void emplace_back(_Args &&...args) {
_back = (_back + 1u) % SIZE;
if (_size == SIZE) {
_front = (_front + 1u) % SIZE;
} else {
++_size;
}
_buffer[_back] = Common::move(TYPE{Common::forward<_Args>(args)...});
}
/**
* @brief Removes element from the beginning of the buffer
*/
void pop() {
if (_size == 0) {
return;
}
--_size;
_front = (_front + 1u) % SIZE;
}
/**
* @brief Erase the given amount of elements from the end of the buffer
*/
void erase_back(const size_t n) {
if (n >= _size) {
clear();
return;
}
_size -= n;
_back = (_front + _size - 1u) % SIZE;
}
/**
* @brief Erase the given amount of elements from the beginning of the buffer
*/
void erase_front(const size_t n) {
if (n >= _size) {
clear();
return;
}
_front = (_front + n) % SIZE;
_size -= n;
}
inline TYPE &operator[](size_t i) {
return _buffer[(_front + i) % SIZE];
}
inline const TYPE &operator[](size_t i) const {
return _buffer[(_front + i) % SIZE];
}
};
} // namespace TwinE