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 @@
+
+
+
+
+
+
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