Add obstruction debug mode, with GUI toggle.

Make pathfinder debug mode off by default, with GUI toggle.

This was SVN commit r7377.
This commit is contained in:
Ykkrosh 2010-03-20 19:18:01 +00:00
parent 55adcfc595
commit a5b8ec6028
13 changed files with 256 additions and 22 deletions

View File

@ -44,6 +44,16 @@
<object size="0 16 100%-18 32" type="text" text_align="right">Display selection state</object>
<object size="100%-16 16 100% 32" type="checkbox" name="devDisplayState" style="wheatCrossBox"/>
<object size="0 32 100%-18 48" type="text" text_align="right">Pathfinder overlay</object>
<object size="100%-16 32 100% 48" type="checkbox" style="wheatCrossBox">
<action on="Press">Engine.GuiInterfaceCall("SetPathfinderDebugOverlay", this.checked);</action>
</object>
<object size="0 48 100%-18 64" type="text" text_align="right">Obstruction overlay</object>
<object size="100%-16 48 100% 64" type="checkbox" style="wheatCrossBox">
<action on="Press">Engine.GuiInterfaceCall("SetObstructionDebugOverlay", this.checked);</action>
</object>
</object>
<!-- Debug text -->

View File

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

View File

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

View File

@ -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<SOverlayLine> m_DebugOverlayLines;
// TODO: using std::map is a bit inefficient; is there a better way to store these?
std::map<u32, Circle> m_Circles;
std::map<u32, Square> 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<const CMessageRenderSubmit&> (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<u8>& 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<u8>& 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<u32, Circle>::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<u32, Square>::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]);
}

View File

@ -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
*/

View File

@ -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);
}

View File

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

View File

@ -128,6 +128,11 @@ public:
*/
virtual bool Rasterise(Grid<u8>& grid) = 0;
/**
* Toggle the rendering of debug info.
*/
virtual void SetDebugOverlay(bool enabled) = 0;
DECLARE_INTERFACE_TYPE(ObstructionManager)
};

View File

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

View File

@ -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)
};

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<ICmpTerrain> 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<ICmpTerrain> 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<std::pair<float, float> > 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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -23,7 +23,7 @@
* Helper functions related to entity selection
*/
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/system/Entity.h"
#include <vector>