MegaGlest/source/glest_game/graphics/debug_renderer.h

404 lines
11 KiB
C++

// ==============================================================
// This file is part of The Glest Advanced Engine
//
// Copyright (C) 2009 James McCulloch <silnarm at gmail>
//
// You can redistribute this code 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
// ==============================================================
#ifndef DEBUG_RENDERING_ENABLED
# error debug_renderer.h included without DEBUG_RENDERING_ENABLED defined
#endif
#ifndef _GLEST_GAME_DEBUG_RENDERER_
#define _GLEST_GAME_DEBUG_RENDERER_
#include "vec.h"
#include "math_util.h"
#include "pixmap.h"
#include "texture.h"
#include "graphics_factory_gl.h"
#include "route_planner.h"
#include "influence_map.h"
#include "cartographer.h"
#include "cluster_map.h"
#include "game.h"
#define g_renderer (Renderer::getInstance())
#define g_world (*static_cast<Game*>(Program::getInstance()->getState())->getWorld())
#define g_console (*static_cast<Game*>(Program::getInstance()->getState())->getConsole())
using namespace Shared::Graphics;
using namespace Shared::Graphics::Gl;
using namespace Shared::Util;
namespace Glest { namespace Game {
class PathFinderTextureCallback {
public:
set<Vec2i> pathSet, openSet, closedSet;
Vec2i pathStart, pathDest;
map<Vec2i,uint32> localAnnotations;
Field debugField;
Texture2D *PFDebugTextures[26];
PathFinderTextureCallback();
void reset();
void loadTextures();
Texture2DGl* operator()(const Vec2i &cell);
};
class GridTextureCallback {
public:
Texture2D *tex;
void reset() { tex = 0; }
void loadTextures();
GridTextureCallback() : tex(0) {}
Texture2DGl* operator()(const Vec2i &cell) {
return (Texture2DGl*)tex;
}
};
enum HighlightColour { hcBlue, hcGreen, hcCount };
class CellHighlightOverlay {
public:
typedef map<Vec2i, HighlightColour> CellColours;
CellColours cells;
Vec4f highlightColours[hcCount];
CellHighlightOverlay() {
highlightColours[hcBlue] = Vec4f(0.f, 0.f, 1.f, 0.6f);
highlightColours[hcGreen] = Vec4f(0.f, 1.f, 0.f, 0.6f);
}
void reset() {
cells.clear();
}
bool empty() const { return cells.empty(); }
bool operator()(const Vec2i &cell, Vec4f &colour) {
CellColours::iterator it = cells.find(cell);
if (it != cells.end()) {
colour = highlightColours[it->second];
return true;
}
return false;
}
};
class InfluenceMapOverlay {
public:
TypeMap<float> *iMap;
Vec3f baseColour;
float max;
bool operator()(const Vec2i &cell, Vec4f &colour) {
const float influence = iMap->getInfluence(cell);
if (influence != 0.f) {
colour = Vec4f(baseColour, clamp(influence / max, 0.f, 1.f));
return true;
}
return false;
}
};
class VisibleAreaOverlay {
public:
set<Vec2i> quadSet;
Vec4f colour;
void reset() {
colour = Vec4f(0.f, 1.f, 0.f, 0.5f);
quadSet.clear();
}
bool operator()(const Vec2i &cell, Vec4f &colour) {
if (quadSet.find(cell) == quadSet.end()) {
return false;
}
colour = this->colour;
return true;
}
};
class TeamSightOverlay {
public:
bool operator()(const Vec2i &cell, Vec4f &colour);
};
class ClusterMapOverlay {
public:
set<Vec2i> entranceCells;
set<Vec2i> pathCells;
void reset() {
entranceCells.clear();
pathCells.clear();
}
bool operator()(const Vec2i &cell, Vec4f &colour) {
const int &clusterSize = GameConstants::clusterSize;
if ( cell.x % clusterSize == clusterSize - 1
|| cell.y % clusterSize == clusterSize - 1 ) {
if ( entranceCells.find(cell) != entranceCells.end() ) {
colour = Vec4f(0.f, 1.f, 0.f, 0.7f); // entrance
} else {
colour = Vec4f(1.f, 0.f, 0.f, 0.7f); // border
}
} else if ( pathCells.find(cell) != pathCells.end() ) { // intra-cluster edge
colour = Vec4f(0.f, 0.f, 1.f, 0.7f);
} else {
return false; // nothing interesting
}
return true;
}
};
class ResourceMapOverlay {
public:
const ResourceType *rt;
ResourceMapOverlay() : rt(0) {}
void reset() { rt = 0; }
bool operator()(const Vec2i &cell, Vec4f &colour);
};
class StoreMapOverlay {
public:
typedef vector<StoreMapKey> KeyList;
KeyList storeMaps;
void reset() { storeMaps.clear(); }
bool operator()(const Vec2i &cell, Vec4f &colour);
};
class BuildSiteMapOverlay {
public:
set<Vec2i> cells;
void reset() { cells.clear(); }
bool operator()(const Vec2i &cell, Vec4f &colour) {
if (cells.find(cell) != cells.end()) {
colour = Vec4f(0.f, 1.f, 0.3f, 0.7f);
return true;
}
return false;
}
};
// =====================================================
// class DebugRender
//
/// Helper class compiled with _GAE_DEBUG_EDITION_ only
// =====================================================
class DebugRenderer {
private:
set<Vec2i> clusterEdgesWest;
set<Vec2i> clusterEdgesNorth;
Vec3f frstmPoints[8];
PathFinderTextureCallback pfCallback;
GridTextureCallback gtCallback;
CellHighlightOverlay rhCallback;
VisibleAreaOverlay vqCallback;
ClusterMapOverlay cmOverlay;
ResourceMapOverlay rmOverlay;
StoreMapOverlay smOverlay;
BuildSiteMapOverlay bsOverlay;
InfluenceMapOverlay imOverlay;
public:
DebugRenderer();
void init();
void commandLine(string &line);
bool gridTextures, // show cell grid
AAStarTextures, // AA* search space and results of last low-level search
HAAStarOverlay, // HAA* search space and results of last hierarchical search
showVisibleQuad, // set to show visualisation of last captured scene cull
captureVisibleQuad, // set to trigger a capture of the next scene cull
captureFrustum, // set to trigger a capture of the view frustum
showFrustum, // set to show visualisation of captured view frustum
regionHilights, // show hilighted cells, are, and can further be, used for various things
resourceMapOverlay, // show resource goal map overlay
storeMapOverlay, // show store goal map overlay
buildSiteMaps, // show building site goal maps
influenceMap; // visualise an inluence map, [TypeMap<float> only]
void addCellHighlight(const Vec2i &pos, HighlightColour c = hcBlue) {
rhCallback.cells[pos] = c;
}
void clearCellHilights() {
rhCallback.cells.clear();
}
void addBuildSiteCell(const Vec2i &pos) {
bsOverlay.cells.insert(pos);
}
void setInfluenceMap(TypeMap<float> *iMap, Vec3f colour, float max);
PathFinderTextureCallback& getPFCallback() { return pfCallback; }
ClusterMapOverlay& getCMOverlay() { return cmOverlay; }
private:
/***/
template<typename TextureCallback>
void renderCellTextures(Quad2i &quad, TextureCallback callback) {
const Map *map = g_world.getMap();
const Rect2i mapBounds(0, 0, map->getSurfaceW() - 1, map->getSurfaceH() - 1);
float coordStep = g_world.getTileset()->getSurfaceAtlas()->getCoordStep();
assertGl();
glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT);
glEnable(GL_BLEND);
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_ALPHA_TEST);
glActiveTexture( GL_TEXTURE0 );
PosQuadIterator pqi(map, quad);
while (pqi.next()) {
const Vec2i &pos = pqi.getPos();
int cx, cy;
cx = pos.x * 2;
cy = pos.y * 2;
if (mapBounds.isInside(pos)) {
SurfaceCell *tc00 = map->getSurfaceCell(pos.x, pos.y), *tc10 = map->getSurfaceCell(pos.x+1, pos.y),
*tc01 = map->getSurfaceCell(pos.x, pos.y+1), *tc11 = map->getSurfaceCell(pos.x+1, pos.y+1);
Vec3f tl = tc00->getVertex (), tr = tc10->getVertex (),
bl = tc01->getVertex (), br = tc11->getVertex ();
Vec3f tc = tl + (tr - tl) / 2, ml = tl + (bl - tl) / 2,
mr = tr + (br - tr) / 2, mc = ml + (mr - ml) / 2, bc = bl + (br - bl) / 2;
Vec2i cPos(cx, cy);
const Texture2DGl *tex = callback(cPos);
renderCellTextured(tex, tc00->getNormal(), tl, tc, mc, ml);
cPos = Vec2i(cx + 1, cy);
tex = callback(cPos);
renderCellTextured(tex, tc00->getNormal(), tc, tr, mr, mc);
cPos = Vec2i(cx, cy + 1 );
tex = callback(cPos);
renderCellTextured(tex, tc00->getNormal(), ml, mc, bc, bl);
cPos = Vec2i(cx + 1, cy + 1);
tex = callback(cPos);
renderCellTextured(tex, tc00->getNormal(), mc, mr, br, bc);
}
}
//Restore
glPopAttrib();
//assert
glGetError(); //remove when first mtex problem solved
assertGl();
} // renderCellTextures ()
/***/
template< typename ColourCallback >
void renderCellOverlay(Quad2i &quad, ColourCallback callback) {
const Map *map = g_world.getMap();
const Rect2i mapBounds(0, 0, map->getSurfaceW() - 1, map->getSurfaceH() - 1);
float coordStep = g_world.getTileset()->getSurfaceAtlas()->getCoordStep();
Vec4f colour;
assertGl();
glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT );
glEnable( GL_BLEND );
glEnable( GL_COLOR_MATERIAL );
glDisable( GL_ALPHA_TEST );
glActiveTexture( GL_TEXTURE0 );
glDisable( GL_TEXTURE_2D );
PosQuadIterator pqi(map, quad);
while(pqi.next()){
const Vec2i &pos= pqi.getPos();
int cx, cy;
cx = pos.x * 2;
cy = pos.y * 2;
if ( mapBounds.isInside( pos ) ) {
SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y), *tc10= map->getSurfaceCell(pos.x+1, pos.y),
*tc01= map->getSurfaceCell(pos.x, pos.y+1), *tc11= map->getSurfaceCell(pos.x+1, pos.y+1);
Vec3f tl = tc00->getVertex(), tr = tc10->getVertex(),
bl = tc01->getVertex(), br = tc11->getVertex();
tl.y += 0.1f; tr.y += 0.1f; bl.y += 0.1f; br.y += 0.1f;
Vec3f tc = tl + (tr - tl) / 2, ml = tl + (bl - tl) / 2, mr = tr + (br - tr) / 2,
mc = ml + (mr - ml) / 2, bc = bl + (br - bl) / 2;
if (callback(Vec2i(cx,cy), colour)) {
renderCellOverlay(colour, tc00->getNormal(), tl, tc, mc, ml);
}
if (callback(Vec2i(cx+1, cy), colour)) {
renderCellOverlay(colour, tc00->getNormal(), tc, tr, mr, mc);
}
if (callback(Vec2i(cx, cy + 1), colour)) {
renderCellOverlay(colour, tc00->getNormal(), ml, mc, bc, bl);
}
if (callback(Vec2i(cx + 1, cy + 1), colour)) {
renderCellOverlay(colour, tc00->getNormal(), mc, mr, br, bc);
}
}
}
//Restore
glPopAttrib();
assertGl();
}
/***/
void renderCellTextured(const Texture2DGl *tex, const Vec3f &norm, const Vec3f &v0,
const Vec3f &v1, const Vec3f &v2, const Vec3f &v3);
/***/
void renderCellOverlay(const Vec4f colour, const Vec3f &norm, const Vec3f &v0,
const Vec3f &v1, const Vec3f &v2, const Vec3f &v3);
/***/
void renderArrow(const Vec3f &pos1, const Vec3f &pos2, const Vec3f &color, float width);
/***/
void renderPathOverlay();
/***/
void renderIntraClusterEdges(const Vec2i &cluster, CardinalDir dir = CardinalDir::COUNT);
/***/
void renderFrustum() const;
list<Vec3f> waypoints;
public:
void clearWaypoints() { waypoints.clear(); }
void addWaypoint(Vec3f v) { waypoints.push_back(v); }
bool willRenderSurface() const { return AAStarTextures || gridTextures; }
void renderSurface(Quad2i &quad) {
if (AAStarTextures) {
if (gridTextures) gridTextures = false;
renderCellTextures(quad, pfCallback);
} else if (gridTextures) {
renderCellTextures(quad, gtCallback);
}
}
void renderEffects(Quad2i &quad);
};
DebugRenderer& getDebugRenderer();
}}
#endif