From a5b8ec602891cef9658cb8d2e05964449038f304 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Sat, 20 Mar 2010 19:18:01 +0000 Subject: [PATCH] Add obstruction debug mode, with GUI toggle. Make pathfinder debug mode off by default, with GUI toggle. This was SVN commit r7377. --- .../mods/public/gui/session_new/session.xml | 10 +++ .../simulation/components/GuiInterface.js | 16 +++- source/gui/scripting/ScriptFunctions.cpp | 1 + .../components/CCmpObstructionManager.cpp | 71 +++++++++++++++- .../simulation2/components/CCmpPathfinder.cpp | 18 +++- .../simulation2/components/CCmpSelectable.cpp | 21 +---- .../components/ICmpObstructionManager.cpp | 1 + .../components/ICmpObstructionManager.h | 5 ++ .../simulation2/components/ICmpPathfinder.cpp | 1 + .../simulation2/components/ICmpPathfinder.h | 5 ++ source/simulation2/helpers/Render.cpp | 82 +++++++++++++++++++ source/simulation2/helpers/Render.h | 45 ++++++++++ source/simulation2/helpers/Selection.h | 2 +- 13 files changed, 256 insertions(+), 22 deletions(-) create mode 100644 source/simulation2/helpers/Render.cpp create mode 100644 source/simulation2/helpers/Render.h diff --git a/binaries/data/mods/public/gui/session_new/session.xml b/binaries/data/mods/public/gui/session_new/session.xml index a0af1dedd1..3e4bfc497c 100644 --- a/binaries/data/mods/public/gui/session_new/session.xml +++ b/binaries/data/mods/public/gui/session_new/session.xml @@ -44,6 +44,16 @@ Display selection state + + Pathfinder overlay + + Engine.GuiInterfaceCall("SetPathfinderDebugOverlay", this.checked); + + + Obstruction overlay + + Engine.GuiInterfaceCall("SetObstructionDebugOverlay", this.checked); + diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index 786c6aaf30..445679c6a8 100644 --- a/binaries/data/mods/public/simulation/components/GuiInterface.js +++ b/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -204,6 +204,18 @@ GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd) return false; }; +GuiInterface.prototype.SetPathfinderDebugOverlay = function(player, enabled) +{ + var cmpPathfinder = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder); + cmpPathfinder.SetDebugOverlay(enabled); +}; + +GuiInterface.prototype.SetObstructionDebugOverlay = function(player, enabled) +{ + var cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); + cmpObstructionManager.SetDebugOverlay(enabled); +}; + // List the GuiInterface functions that can be safely called by GUI scripts. // (GUI scripts are non-deterministic and untrusted, so these functions must be // appropriately careful. They are called with a first argument "player", which is @@ -214,7 +226,9 @@ var exposedFunctions = { "GetEntityState": 1, "GetTemplateData": 1, "SetSelectionHighlight": 1, - "SetBuildingPlacementPreview": 1 + "SetBuildingPlacementPreview": 1, + "SetPathfinderDebugOverlay": 1, + "SetObstructionDebugOverlay": 1 }; GuiInterface.prototype.ScriptCall = function(player, name, args) diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 89e57dd937..e4a12c728c 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -22,6 +22,7 @@ #include "graphics/Camera.h" #include "graphics/GameView.h" #include "gui/GUIManager.h" +#include "maths/FixedVector3D.h" #include "ps/CLogger.h" #include "ps/Game.h" #include "ps/Overlay.h" diff --git a/source/simulation2/components/CCmpObstructionManager.cpp b/source/simulation2/components/CCmpObstructionManager.cpp index 86dcc0bbc6..2a1aa9e7dc 100644 --- a/source/simulation2/components/CCmpObstructionManager.cpp +++ b/source/simulation2/components/CCmpObstructionManager.cpp @@ -21,13 +21,15 @@ #include "ICmpObstructionManager.h" #include "simulation2/MessageTypes.h" +#include "simulation2/helpers/Render.h" +#include "graphics/Overlay.h" #include "graphics/Terrain.h" #include "maths/FixedVector2D.h" #include "maths/MathUtil.h" #include "ps/Overlay.h" #include "ps/Profile.h" -#include "renderer/TerrainOverlay.h" +#include "renderer/Scene.h" // Externally, tags are opaque non-zero positive integers. // Internally, they are tagged (by shape) indexes into shape lists. @@ -59,12 +61,17 @@ struct Square class CCmpObstructionManager : public ICmpObstructionManager { public: - static void ClassInit(CComponentManager& UNUSED(componentManager)) + static void ClassInit(CComponentManager& componentManager) { + componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays } DEFAULT_COMPONENT_ALLOCATOR(ObstructionManager) + bool m_DebugOverlayEnabled; + bool m_DebugOverlayDirty; + std::vector m_DebugOverlayLines; + // TODO: using std::map is a bit inefficient; is there a better way to store these? std::map m_Circles; std::map m_Squares; @@ -73,6 +80,9 @@ public: virtual void Init(const CSimContext& context, const CParamNode& UNUSED(paramNode)) { + m_DebugOverlayEnabled = false; + m_DebugOverlayDirty = true; + m_CircleNext = 1; m_SquareNext = 1; @@ -97,6 +107,19 @@ public: // TODO } + virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global)) + { + switch (msg.GetType()) + { + case MT_RenderSubmit: + { + const CMessageRenderSubmit& msgData = static_cast (msg); + RenderSubmit(context, msgData.collector); + break; + } + } + } + virtual tag_t AddCircle(entity_pos_t x, entity_pos_t z, entity_pos_t r) { Circle c = { x, z, r }; @@ -154,6 +177,16 @@ public: virtual bool Rasterise(Grid& grid); + virtual void SetDebugOverlay(bool enabled) + { + m_DebugOverlayEnabled = enabled; + m_DebugOverlayDirty = true; + if (!enabled) + m_DebugOverlayLines.clear(); + } + + void RenderSubmit(const CSimContext& context, SceneCollector& collector); + private: // To support lazy updates of grid rasterisations of obstruction data, // we maintain a DirtyID here and increment it whenever obstructions change; @@ -167,6 +200,7 @@ private: void MakeDirty() { ++m_DirtyID; + m_DebugOverlayDirty = true; } /** @@ -320,3 +354,36 @@ bool CCmpObstructionManager::Rasterise(Grid& grid) return true; } + +void CCmpObstructionManager::RenderSubmit(const CSimContext& context, SceneCollector& collector) +{ + if (!m_DebugOverlayEnabled) + return; + + CColor defaultColour(0, 0, 1, 1); + + // If the shapes have changed, then regenerate all the overlays + if (m_DebugOverlayDirty) + { + m_DebugOverlayLines.clear(); + + for (std::map::iterator it = m_Circles.begin(); it != m_Circles.end(); ++it) + { + m_DebugOverlayLines.push_back(SOverlayLine()); + m_DebugOverlayLines.back().m_Color = defaultColour; + SimRender::ConstructCircleOnGround(context, it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.r.ToFloat(), m_DebugOverlayLines.back()); + } + + for (std::map::iterator it = m_Squares.begin(); it != m_Squares.end(); ++it) + { + m_DebugOverlayLines.push_back(SOverlayLine()); + m_DebugOverlayLines.back().m_Color = defaultColour; + SimRender::ConstructSquareOnGround(context, it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.w.ToFloat(), it->second.h.ToFloat(), it->second.a.ToFloat(), m_DebugOverlayLines.back()); + } + + m_DebugOverlayDirty = false; + } + + for (size_t i = 0; i < m_DebugOverlayLines.size(); ++i) + collector.Submit(&m_DebugOverlayLines[i]); +} diff --git a/source/simulation2/components/CCmpPathfinder.cpp b/source/simulation2/components/CCmpPathfinder.cpp index f49c88370a..8fa2791e28 100644 --- a/source/simulation2/components/CCmpPathfinder.cpp +++ b/source/simulation2/components/CCmpPathfinder.cpp @@ -91,7 +91,7 @@ public: m_MapSize = 0; m_Grid = NULL; - m_DebugOverlay = new PathfinderOverlay(*this); + m_DebugOverlay = NULL; m_DebugGrid = NULL; m_DebugPath = NULL; } @@ -124,6 +124,9 @@ public: virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal& goal) { + if (!m_DebugOverlay) + return; + delete m_DebugGrid; m_DebugGrid = NULL; delete m_DebugPath; @@ -131,6 +134,19 @@ public: ComputePath(x0, z0, goal, *m_DebugPath); } + virtual void SetDebugOverlay(bool enabled) + { + if (enabled && !m_DebugOverlay) + { + m_DebugOverlay = new PathfinderOverlay(*this); + } + else if (!enabled && m_DebugOverlay) + { + delete m_DebugOverlay; + m_DebugOverlay = NULL; + } + } + /** * Returns the tile containing the given position */ diff --git a/source/simulation2/components/CCmpSelectable.cpp b/source/simulation2/components/CCmpSelectable.cpp index c5f1333d6f..778b45deb3 100644 --- a/source/simulation2/components/CCmpSelectable.cpp +++ b/source/simulation2/components/CCmpSelectable.cpp @@ -22,6 +22,7 @@ #include "ICmpPosition.h" #include "simulation2/MessageTypes.h" +#include "simulation2/helpers/Render.h" #include "graphics/Overlay.h" #include "maths/MathUtil.h" @@ -29,8 +30,6 @@ #include "maths/Vector3D.h" #include "renderer/Scene.h" -const size_t SELECTION_CIRCLE_POINTS = 16; - class CCmpSelectable : public ICmpSelectable { public: @@ -119,31 +118,19 @@ public: CMatrix3D transform = cmpPosition->GetInterpolatedTransform(frameOffset); CVector3D pos = transform.GetTranslation(); + // TODO: this is an unnecessarily inefficient way to get X and Z coordinates; + // ought to have a GetInterpolated2DPosition instead // TODO: should use ICmpFootprint to find the shape float radius = 2.f; - - m_Overlay.m_Coords.clear(); - m_Overlay.m_Coords.reserve((SELECTION_CIRCLE_POINTS + 1) * 3); - - for (size_t i = 0; i <= SELECTION_CIRCLE_POINTS; ++i) // use '<=' so it's a closed loop - { - float a = i * 2 * M_PI / SELECTION_CIRCLE_POINTS; - float x = pos.X + radius * sin(a); - float z = pos.Z + radius * cos(a); - float y = pos.Y + 0.25f; // TODO: clamp to ground instead - m_Overlay.m_Coords.push_back(x); - m_Overlay.m_Coords.push_back(y); - m_Overlay.m_Coords.push_back(z); - } + SimRender::ConstructCircleOnGround(context, pos.X, pos.Z, radius, m_Overlay); } void RenderSubmit(SceneCollector& collector) { // (This is only called if a > 0) - // TODO: maybe should do some frustum culling collector.Submit(&m_Overlay); } diff --git a/source/simulation2/components/ICmpObstructionManager.cpp b/source/simulation2/components/ICmpObstructionManager.cpp index b189966c44..5045ea3aba 100644 --- a/source/simulation2/components/ICmpObstructionManager.cpp +++ b/source/simulation2/components/ICmpObstructionManager.cpp @@ -22,4 +22,5 @@ #include "simulation2/system/InterfaceScripted.h" BEGIN_INTERFACE_WRAPPER(ObstructionManager) +DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpObstructionManager, SetDebugOverlay, bool) END_INTERFACE_WRAPPER(ObstructionManager) diff --git a/source/simulation2/components/ICmpObstructionManager.h b/source/simulation2/components/ICmpObstructionManager.h index 2fdcf794bc..99b0d5d25a 100644 --- a/source/simulation2/components/ICmpObstructionManager.h +++ b/source/simulation2/components/ICmpObstructionManager.h @@ -128,6 +128,11 @@ public: */ virtual bool Rasterise(Grid& grid) = 0; + /** + * Toggle the rendering of debug info. + */ + virtual void SetDebugOverlay(bool enabled) = 0; + DECLARE_INTERFACE_TYPE(ObstructionManager) }; diff --git a/source/simulation2/components/ICmpPathfinder.cpp b/source/simulation2/components/ICmpPathfinder.cpp index 292c89a3ee..41d0fb04e6 100644 --- a/source/simulation2/components/ICmpPathfinder.cpp +++ b/source/simulation2/components/ICmpPathfinder.cpp @@ -22,4 +22,5 @@ #include "simulation2/system/InterfaceScripted.h" BEGIN_INTERFACE_WRAPPER(Pathfinder) +DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpPathfinder, SetDebugOverlay, bool) END_INTERFACE_WRAPPER(Pathfinder) diff --git a/source/simulation2/components/ICmpPathfinder.h b/source/simulation2/components/ICmpPathfinder.h index eb7bc2807f..e0e0d14aaf 100644 --- a/source/simulation2/components/ICmpPathfinder.h +++ b/source/simulation2/components/ICmpPathfinder.h @@ -80,6 +80,11 @@ public: */ virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal& goal) = 0; + /** + * Toggle the storage and rendering of debug info. + */ + virtual void SetDebugOverlay(bool enabled) = 0; + DECLARE_INTERFACE_TYPE(Pathfinder) }; diff --git a/source/simulation2/helpers/Render.cpp b/source/simulation2/helpers/Render.cpp new file mode 100644 index 0000000000..f00755a11c --- /dev/null +++ b/source/simulation2/helpers/Render.cpp @@ -0,0 +1,82 @@ +/* Copyright (C) 2010 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Render.h" + +#include "simulation2/Simulation2.h" +#include "simulation2/components/ICmpTerrain.h" +#include "graphics/Overlay.h" + +static const size_t RENDER_CIRCLE_POINTS = 16; +static const float RENDER_HEIGHT_DELTA = 0.25f; // distance above terrain + +void SimRender::ConstructCircleOnGround(const CSimContext& context, float x, float z, float radius, SOverlayLine& overlay) +{ + overlay.m_Coords.clear(); + + CmpPtr cmpTerrain(context, SYSTEM_ENTITY); + if (cmpTerrain.null()) + return; + + overlay.m_Coords.reserve((RENDER_CIRCLE_POINTS + 1) * 3); + + for (size_t i = 0; i <= RENDER_CIRCLE_POINTS; ++i) // use '<=' so it's a closed loop + { + float a = i * 2 * M_PI / RENDER_CIRCLE_POINTS; + float px = x + radius * sin(a); + float pz = z + radius * cos(a); + float py = cmpTerrain->GetGroundLevel(px, pz) + RENDER_HEIGHT_DELTA; + overlay.m_Coords.push_back(px); + overlay.m_Coords.push_back(py); + overlay.m_Coords.push_back(pz); + } +} + +void SimRender::ConstructSquareOnGround(const CSimContext& context, float x, float z, float w, float h, float a, SOverlayLine& overlay) +{ + overlay.m_Coords.clear(); + + CmpPtr cmpTerrain(context, SYSTEM_ENTITY); + if (cmpTerrain.null()) + return; + + // TODO: might be nicer to split this into little pieces so it copes better with uneven terrain + + overlay.m_Coords.reserve(5 * 3); + + float c = cos(a); + float s = sin(a); + + std::vector > coords; + coords.push_back(std::make_pair(x - w/2*c + h/2*s, z + w/2*s + h/2*c)); + coords.push_back(std::make_pair(x - w/2*c - h/2*s, z + w/2*s - h/2*c)); + coords.push_back(std::make_pair(x + w/2*c - h/2*s, z - w/2*s - h/2*c)); + coords.push_back(std::make_pair(x + w/2*c + h/2*s, z - w/2*s + h/2*c)); + coords.push_back(std::make_pair(x - w/2*c + h/2*s, z + w/2*s + h/2*c)); + + for (size_t i = 0; i < coords.size(); ++i) + { + float px = coords[i].first; + float pz = coords[i].second; + float py = cmpTerrain->GetGroundLevel(px, pz) + RENDER_HEIGHT_DELTA; + overlay.m_Coords.push_back(px); + overlay.m_Coords.push_back(py); + overlay.m_Coords.push_back(pz); + } +} diff --git a/source/simulation2/helpers/Render.h b/source/simulation2/helpers/Render.h new file mode 100644 index 0000000000..1a8e4cc192 --- /dev/null +++ b/source/simulation2/helpers/Render.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2010 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#ifndef INCLUDED_HELPER_RENDER +#define INCLUDED_HELPER_RENDER + +/** + * @file + * Helper functions related to rendering + */ + +class CSimContext; +struct SOverlayLine; + +namespace SimRender +{ + +/** + * Updates @p overlay so that it represents the given circle, flattened on the terrain. + */ +void ConstructCircleOnGround(const CSimContext& context, float x, float z, float radius, SOverlayLine& overlay); + +/** + * Updates @p overlay so that it represents the given square, flattened on the terrain. + * @p x and @p z are position of center, @p w and @p h are size of rectangle, @p a is clockwise angle. + */ +void ConstructSquareOnGround(const CSimContext& context, float x, float z, float w, float h, float a, SOverlayLine& overlay); + +} // namespace + +#endif // INCLUDED_HELPER_RENDER diff --git a/source/simulation2/helpers/Selection.h b/source/simulation2/helpers/Selection.h index 14726a6cbe..82447f284c 100644 --- a/source/simulation2/helpers/Selection.h +++ b/source/simulation2/helpers/Selection.h @@ -23,7 +23,7 @@ * Helper functions related to entity selection */ -#include "simulation2/components/ICmpPosition.h" +#include "simulation2/system/Entity.h" #include