* wired up RoutePlanner/Cartographer
* added DebugRenderer (mostly dysfunctional) * add lots of OutputDebug calls for the path finder, as macro PF_TRACE
This commit is contained in:
parent
f86268b53d
commit
8387ed29dc
|
@ -117,6 +117,8 @@ public:
|
|||
CellMetrics& operator[](const Vec2i &pos) const { return metrics[pos.y * width + pos.x]; }
|
||||
};
|
||||
|
||||
class PathFinderTextureCallback;
|
||||
|
||||
// =====================================================
|
||||
// class AnnotatedMap
|
||||
// =====================================================
|
||||
|
@ -130,6 +132,7 @@ public:
|
|||
//TODO: pretty pictures for the doco...
|
||||
class AnnotatedMap {
|
||||
friend class ClusterMap;
|
||||
friend class PathFinderTextureCallback;
|
||||
|
||||
private:
|
||||
int width, height;
|
||||
|
|
|
@ -128,8 +128,6 @@ void Cartographer::initResourceMap(ResourceMapKey key, PatchMap<1> *pMap) {
|
|||
Resource *r = world->getMap()->getSurfaceCell(*it)->getResource();
|
||||
assert(r);
|
||||
|
||||
// r->Depleted.connect(this, &Cartographer::onResourceDepleted);
|
||||
|
||||
Vec2i tl = *it * GameConstants::cellScale + OrdinalOffsets[odNorthWest] * size;
|
||||
Vec2i br(tl.x + size + 2, tl.y + size + 2);
|
||||
|
||||
|
@ -143,16 +141,14 @@ void Cartographer::initResourceMap(ResourceMapKey key, PatchMap<1> *pMap) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Cartographer::onResourceDepleted(Vec2i pos) {
|
||||
const ResourceType *rt = cellMap->getSurfaceCell(pos/GameConstants::cellScale)->getResource()->getType();
|
||||
void Cartographer::onResourceDepleted(Vec2i pos, const ResourceType *rt) {
|
||||
PF_TRACE();
|
||||
updateMapMetrics(pos, GameConstants::cellScale);
|
||||
resDirtyAreas[rt].push_back(pos);
|
||||
// Vec2i tl = pos + OrdinalOffsets[odNorthWest];
|
||||
// Vec2i br = pos + OrdinalOffsets[OrdinalDir::SOUTH_EAST] * 2;
|
||||
// resDirtyAreas[rt].push_back(pair<Vec2i,Vec2i>(tl,br));
|
||||
}
|
||||
|
||||
void Cartographer::fixupResourceMaps(const ResourceType *rt, const Vec2i &pos) {
|
||||
PF_TRACE();
|
||||
const Map &map = *world->getMap();
|
||||
Vec2i junk;
|
||||
for (set<ResourceMapKey>::iterator it = resourceMapKeys.begin(); it != resourceMapKeys.end(); ++it) {
|
||||
|
@ -178,6 +174,55 @@ void Cartographer::fixupResourceMaps(const ResourceType *rt, const Vec2i &pos) {
|
|||
}
|
||||
}
|
||||
|
||||
PatchMap<1>* Cartographer::buildSiteMap(BuildSiteMapKey key) {
|
||||
PF_TRACE();
|
||||
PatchMap<1> *sMap = siteMaps[key] = buildAdjacencyMap(key.buildingType, key.buildingPosition,
|
||||
key.workerField, key.workerSize);
|
||||
// IF_DEBUG_EDITION( debugAddBuildSiteMap(sMap); )
|
||||
return sMap;
|
||||
}
|
||||
|
||||
PatchMap<1>* Cartographer::getResourceMap(ResourceMapKey key) {
|
||||
PF_TRACE();
|
||||
return resourceMaps[key];
|
||||
}
|
||||
|
||||
PatchMap<1>* Cartographer::getStoreMap(StoreMapKey key, bool build) {
|
||||
PF_TRACE();
|
||||
StoreMaps::iterator it = storeMaps.find(key);
|
||||
if (it != storeMaps.end()) {
|
||||
return it->second;
|
||||
}
|
||||
if (build) {
|
||||
return buildStoreMap(key);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PatchMap<1>* Cartographer::getStoreMap(const Unit *store, const Unit *worker) {
|
||||
PF_TRACE();
|
||||
StoreMapKey key(store, worker->getCurrField(), worker->getType()->getSize());
|
||||
return getStoreMap(key);
|
||||
}
|
||||
|
||||
PatchMap<1>* Cartographer::getSiteMap(BuildSiteMapKey key) {
|
||||
PF_TRACE();
|
||||
SiteMaps::iterator it = siteMaps.find(key);
|
||||
if (it != siteMaps.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return buildSiteMap(key);
|
||||
|
||||
}
|
||||
|
||||
PatchMap<1>* Cartographer::getSiteMap(const UnitType *ut, const Vec2i &pos, Unit *worker) {
|
||||
PF_TRACE();
|
||||
BuildSiteMapKey key(ut, pos, worker->getCurrField(), worker->getType()->getSize());
|
||||
return getSiteMap(key);
|
||||
}
|
||||
|
||||
|
||||
void Cartographer::onStoreDestroyed(Unit *unit) {
|
||||
///@todo fixme
|
||||
// delete storeMaps[unit];
|
||||
|
@ -185,6 +230,7 @@ void Cartographer::onStoreDestroyed(Unit *unit) {
|
|||
}
|
||||
|
||||
PatchMap<1>* Cartographer::buildAdjacencyMap(const UnitType *uType, const Vec2i &pos, Field f, int size) {
|
||||
PF_TRACE();
|
||||
const Vec2i mapPos = pos + (OrdinalOffsets[odNorthWest] * size);
|
||||
const int sx = pos.x;
|
||||
const int sy = pos.y;
|
||||
|
@ -239,6 +285,7 @@ PatchMap<1>* Cartographer::buildAdjacencyMap(const UnitType *uType, const Vec2i
|
|||
)
|
||||
*/
|
||||
void Cartographer::tick() {
|
||||
PF_TRACE();
|
||||
if (clusterMap->isDirty()) {
|
||||
clusterMap->update();
|
||||
}
|
||||
|
|
|
@ -126,27 +126,7 @@ private:
|
|||
}
|
||||
|
||||
// IF_DEBUG_EDITION( void debugAddBuildSiteMap(PatchMap<1>*); )
|
||||
|
||||
PatchMap<1>* buildSiteMap(BuildSiteMapKey key) {
|
||||
PatchMap<1> *sMap = siteMaps[key] = buildAdjacencyMap(key.buildingType, key.buildingPosition,
|
||||
key.workerField, key.workerSize);
|
||||
// IF_DEBUG_EDITION( debugAddBuildSiteMap(sMap); )
|
||||
return sMap;
|
||||
}
|
||||
|
||||
// slots
|
||||
void onResourceDepleted(Vec2i pos);
|
||||
void onStoreDestroyed(Unit *unit);
|
||||
|
||||
void onUnitBorn(Unit *unit);
|
||||
void onUnitMoved(Unit *unit);
|
||||
void onUnitMorphed(Unit *unit, const UnitType *type);
|
||||
void onUnitDied(Unit *unit);
|
||||
|
||||
void maintainUnitVisibility(Unit *unit, bool add);
|
||||
|
||||
void saveResourceState(XmlNode *node);
|
||||
void loadResourceState(XmlNode *node);
|
||||
PatchMap<1>* buildSiteMap(BuildSiteMapKey key);
|
||||
|
||||
public:
|
||||
Cartographer(World *world);
|
||||
|
@ -156,52 +136,24 @@ public:
|
|||
RoutePlanner* getRoutePlanner() { return routePlanner; }
|
||||
|
||||
/** Update the annotated maps when an obstacle has been added or removed from the map.
|
||||
* Unconditionally updates the master map, updates team maps if the team can see the cells,
|
||||
* or mark as 'dirty' if they cannot currently see the change. @todo implement team maps
|
||||
* @param pos position (north-west most cell) of obstacle
|
||||
* @param size size of obstacle */
|
||||
void updateMapMetrics(const Vec2i &pos, const int size) {
|
||||
masterMap->updateMapMetrics(pos, size);
|
||||
// who can see it ? update their maps too.
|
||||
// set cells as dirty for those that can't see it
|
||||
}
|
||||
|
||||
void onResourceDepleted(Vec2i pos, const ResourceType *rt);
|
||||
void onStoreDestroyed(Unit *unit);
|
||||
|
||||
void tick();
|
||||
|
||||
PatchMap<1>* getResourceMap(ResourceMapKey key) {
|
||||
return resourceMaps[key];
|
||||
}
|
||||
PatchMap<1>* getResourceMap(ResourceMapKey key);
|
||||
|
||||
PatchMap<1>* getStoreMap(StoreMapKey key, bool build=true) {
|
||||
StoreMaps::iterator it = storeMaps.find(key);
|
||||
if (it != storeMaps.end()) {
|
||||
return it->second;
|
||||
}
|
||||
if (build) {
|
||||
return buildStoreMap(key);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
PatchMap<1>* getStoreMap(StoreMapKey key, bool build=true);
|
||||
PatchMap<1>* getStoreMap(const Unit *store, const Unit *worker);
|
||||
|
||||
PatchMap<1>* getStoreMap(const Unit *store, const Unit *worker) {
|
||||
StoreMapKey key(store, worker->getCurrField(), worker->getType()->getSize());
|
||||
return getStoreMap(key);
|
||||
}
|
||||
|
||||
PatchMap<1>* getSiteMap(BuildSiteMapKey key) {
|
||||
SiteMaps::iterator it = siteMaps.find(key);
|
||||
if (it != siteMaps.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return buildSiteMap(key);
|
||||
|
||||
}
|
||||
|
||||
PatchMap<1>* getSiteMap(const UnitType *ut, const Vec2i &pos, Unit *worker) {
|
||||
BuildSiteMapKey key(ut, pos, worker->getCurrField(), worker->getType()->getSize());
|
||||
return getSiteMap(key);
|
||||
}
|
||||
PatchMap<1>* getSiteMap(BuildSiteMapKey key);
|
||||
PatchMap<1>* getSiteMap(const UnitType *ut, const Vec2i &pos, Unit *worker);
|
||||
|
||||
void adjustGlestimalMap(Field f, TypeMap<float> &iMap, const Vec2i &pos, float range);
|
||||
void buildGlestimalMap(Field f, V2iList &positions);
|
||||
|
|
|
@ -22,7 +22,7 @@ using Shared::Util::line;
|
|||
|
||||
#define _USE_LINE_PATH_ 1
|
||||
|
||||
#if _GAE_DEBUG_EDITION_
|
||||
#if DEBUG_RENDERING_ENABLED
|
||||
# include "debug_renderer.h"
|
||||
#endif
|
||||
|
||||
|
@ -54,8 +54,6 @@ ClusterMap::ClusterMap(AnnotatedMap *aMap, Cartographer *carto)
|
|||
Edge::zeroCounters();
|
||||
Transition::zeroCounters();
|
||||
|
||||
//g_logger.setClusterCount(w * h);
|
||||
|
||||
// init Borders (and hence inter-cluster edges) & evaluate clusters (intra-cluster edges)
|
||||
for (int i = h - 1; i >= 0; --i) {
|
||||
for (int j = w - 1; j >= 0; --j) {
|
||||
|
@ -71,8 +69,8 @@ ClusterMap::~ClusterMap() {
|
|||
delete [] vertBorders;
|
||||
delete [] horizBorders;
|
||||
for (int f = 0; f < fieldCount; ++f) {
|
||||
assert(Edge::NumEdges(f) == 0);
|
||||
assert(Transition::NumTransitions(f) == 0);
|
||||
assert(Edge::NumEdges(Field(f)) == 0);
|
||||
assert(Transition::NumTransitions(Field(f)) == 0);
|
||||
if (Edge::NumEdges(Field(f)) != 0 || Transition::NumTransitions(Field(f)) != 0) {
|
||||
throw runtime_error("memory leak");
|
||||
}
|
||||
|
@ -302,17 +300,17 @@ void ClusterMap::initClusterBorder(const Vec2i &cluster, bool north) {
|
|||
inf.run = 0; // to count entrance 'width'
|
||||
for (int f = 0; f < fieldCount; ++f) {
|
||||
if (!aMap->maxClearance[f] || f == fAir) continue;
|
||||
/*
|
||||
IF_DEBUG_EDITION(
|
||||
|
||||
# if DEBUG_RENDERING_ENABLED
|
||||
if (f == fLand) {
|
||||
for (int i=0; i < cb->transitions[f].n; ++i) {
|
||||
g_debugRenderer.getCMOverlay().entranceCells.erase(
|
||||
getDebugRenderer().getCMOverlay().entranceCells.erase(
|
||||
cb->transitions[f].transitions[i]->nwPos
|
||||
);
|
||||
}
|
||||
}
|
||||
) // DEBUG_EDITION
|
||||
*/
|
||||
# endif
|
||||
|
||||
cb->transitions[f].clear();
|
||||
clear = false;
|
||||
inf.f = Field(f);
|
||||
|
@ -353,15 +351,15 @@ void ClusterMap::initClusterBorder(const Vec2i &cluster, bool north) {
|
|||
clear = false;
|
||||
}
|
||||
}// for each Field
|
||||
/*
|
||||
IF_DEBUG_EDITION(
|
||||
|
||||
# if DEBUG_RENDERING_ENABLED
|
||||
for (int i=0; i < cb->transitions[fLand].n; ++i) {
|
||||
g_debugRenderer.getCMOverlay().entranceCells.insert(
|
||||
getDebugRenderer().getCMOverlay().entranceCells.insert(
|
||||
cb->transitions[fLand].transitions[i]->nwPos
|
||||
);
|
||||
}
|
||||
) // DEBUG_EDITION
|
||||
*/
|
||||
# endif
|
||||
|
||||
} // if not sentinel
|
||||
}
|
||||
|
||||
|
@ -389,8 +387,13 @@ float ClusterMap::linePathLength(Field f, int size, const Vec2i &start, const Ve
|
|||
vector<Vec2i>::iterator it = linePath.begin();
|
||||
vector<Vec2i>::iterator nIt = it + 1;
|
||||
float cost = 0.f;
|
||||
while (nIt != linePath.end() && cost != -1.f) {
|
||||
cost += costFunc(*it++, *nIt++);
|
||||
while (nIt != linePath.end()) {
|
||||
float add = costFunc(*it++, *nIt++);
|
||||
if (add != -1.f) {
|
||||
cost += add;
|
||||
} else {
|
||||
return -1.f;
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
|
|
@ -98,19 +98,15 @@ RoutePlanner::RoutePlanner(World *world)
|
|||
, nodeStore(NULL)
|
||||
, tSearchEngine(NULL)
|
||||
, tNodeStore(NULL) {
|
||||
Logger::getInstance().add( "Initialising SearchEngine", true );
|
||||
|
||||
const int &w = world->getMap()->getW();
|
||||
const int &h = world->getMap()->getH();
|
||||
|
||||
//cout << "NodePool SearchEngine\n";
|
||||
nodeStore = new NodePool(w, h);
|
||||
GridNeighbours gNeighbours(w, h);
|
||||
nsgSearchEngine = new SearchEngine<NodePool>(gNeighbours, nodeStore, true);
|
||||
nsgSearchEngine->setInvalidKey(Vec2i(-1));
|
||||
nsgSearchEngine->getNeighbourFunc().setSearchSpace(ssCellMap);
|
||||
|
||||
//cout << "Transition SearchEngine\n";
|
||||
int numNodes = w * h / 4096 * 250; // 250 nodes for every 16 clusters
|
||||
tNodeStore = new TransitionNodeStore(numNodes);
|
||||
TransitionNeighbours tNeighbours;
|
||||
|
@ -134,8 +130,9 @@ bool RoutePlanner::isLegalMove(Unit *unit, const Vec2i &pos2) const {
|
|||
assert(world->getMap()->isInside(pos2));
|
||||
assert(unit->getPos().dist(pos2) < 1.5);
|
||||
|
||||
if (unit->getPos().dist(pos2) > 1.5) {
|
||||
throw runtime_error("Boo!!!");
|
||||
float d = unit->getPos().dist(pos2);
|
||||
if (d > 1.5 || d < 0.9f) {
|
||||
throw runtime_error("The new Pathfinder lied.");
|
||||
}
|
||||
|
||||
const Vec2i &pos1 = unit->getPos();
|
||||
|
@ -172,7 +169,30 @@ bool RoutePlanner::isLegalMove(Unit *unit, const Vec2i &pos2) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
TravelState RoutePlanner::findPathToResource(Unit *unit, const Vec2i &targetPos, const ResourceType *rt) {
|
||||
PF_TRACE();
|
||||
assert(rt && (rt->getClass() == rcTech || rt->getClass() == rcTileset));
|
||||
ResourceMapKey mapKey(rt, unit->getCurrField(), unit->getType()->getSize());
|
||||
PMap1Goal goal(world->getCartographer()->getResourceMap(mapKey));
|
||||
return findPathToGoal(unit, goal, targetPos);
|
||||
}
|
||||
|
||||
TravelState RoutePlanner::findPathToStore(Unit *unit, const Unit *store) {
|
||||
PF_TRACE();
|
||||
Vec2i target = store->getCenteredPos();
|
||||
PMap1Goal goal(world->getCartographer()->getStoreMap(store, unit));
|
||||
return findPathToGoal(unit, goal, target);
|
||||
}
|
||||
|
||||
TravelState RoutePlanner::findPathToBuildSite(Unit *unit, const UnitType *buildingType, const Vec2i &buildingPos) {
|
||||
PF_TRACE();
|
||||
PMap1Goal goal(world->getCartographer()->getSiteMap(buildingType, buildingPos, unit));
|
||||
return findPathToGoal(unit, goal, buildingPos + Vec2i(buildingType->getSize() / 2));
|
||||
}
|
||||
|
||||
|
||||
float RoutePlanner::quickSearch(Field field, int size, const Vec2i &start, const Vec2i &dest) {
|
||||
PF_TRACE();
|
||||
// setup search
|
||||
MoveCost moveCost(field, size, world->getCartographer()->getMasterMap());
|
||||
DiagonalDistance heuristic(dest);
|
||||
|
@ -186,6 +206,7 @@ float RoutePlanner::quickSearch(Field field, int size, const Vec2i &start, const
|
|||
}
|
||||
|
||||
HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &dest, TransitionGoal &goalFunc) {
|
||||
PF_TRACE();
|
||||
// get Transitions for start cluster
|
||||
Transitions transitions;
|
||||
Vec2i startCluster = ClusterMap::cellToCluster(unit->getPos());
|
||||
|
@ -270,6 +291,7 @@ HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &des
|
|||
}
|
||||
|
||||
HAAStarResult RoutePlanner::findWaypointPath(Unit *unit, const Vec2i &dest, WaypointPath &waypoints) {
|
||||
PF_TRACE();
|
||||
TransitionGoal goal;
|
||||
HAAStarResult setupResult = setupHierarchicalSearch(unit, dest, goal);
|
||||
nsgSearchEngine->getNeighbourFunc().setSearchSpace(ssCellMap);
|
||||
|
@ -297,6 +319,7 @@ HAAStarResult RoutePlanner::findWaypointPath(Unit *unit, const Vec2i &dest, Wayp
|
|||
* @return true if successful, in which case waypoint will have been popped.
|
||||
* false on failure, in which case waypoint will not be popped. */
|
||||
bool RoutePlanner::refinePath(Unit *unit) {
|
||||
PF_TRACE();
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
UnitPath &path = *unit->getPath();
|
||||
assert(!wpPath.empty());
|
||||
|
@ -333,6 +356,7 @@ bool RoutePlanner::refinePath(Unit *unit) {
|
|||
#undef max
|
||||
|
||||
void RoutePlanner::smoothPath(Unit *unit) {
|
||||
PF_TRACE();
|
||||
if (unit->getPath()->size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
@ -402,6 +426,7 @@ void RoutePlanner::smoothPath(Unit *unit) {
|
|||
}
|
||||
|
||||
TravelState RoutePlanner::doRouteCache(Unit *unit) {
|
||||
PF_TRACE();
|
||||
UnitPath &path = *unit->getPath();
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
assert(unit->getPos().dist(path.front()) < 1.5f);
|
||||
|
@ -428,10 +453,12 @@ TravelState RoutePlanner::doRouteCache(Unit *unit) {
|
|||
// IF_DEBUG_EDITION( collectPath(unit); )
|
||||
return tsMoving;
|
||||
}
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
|
||||
TravelState RoutePlanner::doQuickPathSearch(Unit *unit, const Vec2i &target) {
|
||||
PF_TRACE();
|
||||
AnnotatedMap *aMap = world->getCartographer()->getAnnotatedMap(unit);
|
||||
UnitPath &path = *unit->getPath();
|
||||
// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), target); )
|
||||
|
@ -458,6 +485,7 @@ TravelState RoutePlanner::doQuickPathSearch(Unit *unit, const Vec2i &target) {
|
|||
}
|
||||
|
||||
TravelState RoutePlanner::findAerialPath(Unit *unit, const Vec2i &targetPos) {
|
||||
PF_TRACE();
|
||||
AnnotatedMap *aMap = world->getCartographer()->getMasterMap();
|
||||
UnitPath &path = *unit->getPath();
|
||||
PosGoal goal(targetPos);
|
||||
|
@ -486,6 +514,7 @@ TravelState RoutePlanner::findAerialPath(Unit *unit, const Vec2i &targetPos) {
|
|||
}
|
||||
}
|
||||
path.incBlockCount();
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
|
||||
|
@ -495,6 +524,7 @@ TravelState RoutePlanner::findAerialPath(Unit *unit, const Vec2i &targetPos) {
|
|||
* @return ARRIVED, MOVING, BLOCKED or IMPOSSIBLE
|
||||
*/
|
||||
TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos) {
|
||||
PF_TRACE();
|
||||
UnitPath &path = *unit->getPath();
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
|
||||
|
@ -532,6 +562,9 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
|||
return tsMoving;
|
||||
}
|
||||
}
|
||||
|
||||
PF_TRACE();
|
||||
|
||||
// Hierarchical Search
|
||||
tSearchEngine->reset();
|
||||
HAAStarResult res = findWaypointPath(unit, target, wpPath);
|
||||
|
@ -544,10 +577,13 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
|||
} else if (res == hsrStartTrap) {
|
||||
if (wpPath.size() < 2) {
|
||||
CONSOLE_LOG( "START_TRAP" );
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
}
|
||||
|
||||
PF_TRACE();
|
||||
|
||||
// IF_DEBUG_EDITION( collectWaypointPath(unit); )
|
||||
//CONSOLE_LOG( "WaypointPath size : " + intToStr(wpPath.size()) )
|
||||
//TODO post process, scan wpPath, if prev.dist(pos) < 4 cull prev
|
||||
|
@ -568,6 +604,7 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
|||
aMap->clearLocalAnnotations(unit);
|
||||
path.incBlockCount();
|
||||
//CONSOLE_LOG( " blockCount = " + intToStr(path.getBlockCount()) )
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
}
|
||||
|
@ -576,6 +613,7 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
|||
// IF_DEBUG_EDITION( collectPath(unit); )
|
||||
if (path.empty()) {
|
||||
CONSOLE_LOG( "post hierarchical search failure, path empty." );
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
if (attemptMove(unit)) {
|
||||
|
@ -588,6 +626,7 @@ TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos)
|
|||
}
|
||||
|
||||
TravelState RoutePlanner::customGoalSearch(PMap1Goal &goal, Unit *unit, const Vec2i &target) {
|
||||
PF_TRACE();
|
||||
UnitPath &path = *unit->getPath();
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
const Vec2i &start = unit->getPos();
|
||||
|
@ -602,6 +641,8 @@ TravelState RoutePlanner::customGoalSearch(PMap1Goal &goal, Unit *unit, const Ve
|
|||
aMap->annotateLocal(unit);
|
||||
r = nsgSearchEngine->aStar(goal, moveCost, heuristic);
|
||||
aMap->clearLocalAnnotations(unit);
|
||||
|
||||
PF_TRACE();
|
||||
if (r == asrComplete) {
|
||||
Vec2i pos = nsgSearchEngine->getGoalPos();
|
||||
// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), pos); )
|
||||
|
@ -612,7 +653,7 @@ TravelState RoutePlanner::customGoalSearch(PMap1Goal &goal, Unit *unit, const Ve
|
|||
}
|
||||
if (!path.empty()) path.pop();
|
||||
// IF_DEBUG_EDITION( collectPath(unit); )
|
||||
if (attemptMove(unit)) {
|
||||
if (!path.empty() && attemptMove(unit)) {
|
||||
return tsMoving;
|
||||
}
|
||||
path.clear();
|
||||
|
@ -621,6 +662,7 @@ TravelState RoutePlanner::customGoalSearch(PMap1Goal &goal, Unit *unit, const Ve
|
|||
}
|
||||
|
||||
TravelState RoutePlanner::findPathToGoal(Unit *unit, PMap1Goal &goal, const Vec2i &target) {
|
||||
PF_TRACE();
|
||||
UnitPath &path = *unit->getPath();
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
|
||||
|
@ -642,9 +684,12 @@ TravelState RoutePlanner::findPathToGoal(Unit *unit, PMap1Goal &goal, const Vec2
|
|||
if (customGoalSearch(goal, unit, target) == tsMoving) {
|
||||
return tsMoving;
|
||||
} else {
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
}
|
||||
|
||||
PF_TRACE();
|
||||
// Hierarchical Search
|
||||
tSearchEngine->reset();
|
||||
if (!findWaypointPath(unit, target, wpPath)) {
|
||||
|
@ -669,6 +714,7 @@ TravelState RoutePlanner::findPathToGoal(Unit *unit, PMap1Goal &goal, const Vec2
|
|||
if (!refinePath(unit)) {
|
||||
CONSOLE_LOG( "refinePath failed! [Custom Goal Search]" )
|
||||
aMap->clearLocalAnnotations(unit);
|
||||
unit->setCurrSkill(scStop);
|
||||
return tsBlocked;
|
||||
}
|
||||
}
|
||||
|
@ -687,6 +733,7 @@ TravelState RoutePlanner::findPathToGoal(Unit *unit, PMap1Goal &goal, const Vec2
|
|||
* @param unit unit whose path is blocked
|
||||
* @return true if repair succeeded */
|
||||
bool RoutePlanner::repairPath(Unit *unit) {
|
||||
PF_TRACE();
|
||||
UnitPath &path = *unit->getPath();
|
||||
WaypointPath &wpPath = *unit->getWaypointPath();
|
||||
|
||||
|
@ -803,6 +850,7 @@ TravelState RoutePlanner::doFullLowLevelAStar(Unit *unit, const Vec2i &dest) {
|
|||
* @todo reimplement with Dijkstra search
|
||||
*/
|
||||
Vec2i RoutePlanner::computeNearestFreePos(const Unit *unit, const Vec2i &finalPos) {
|
||||
PF_TRACE();
|
||||
//unit data
|
||||
Vec2i unitPos= unit->getPos();
|
||||
int size= unit->getType()->getSize();
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "world.h"
|
||||
#include "types.h"
|
||||
|
||||
#define PF_TRACE() SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__)
|
||||
|
||||
using Shared::Graphics::Vec2i;
|
||||
using Shared::Platform::uint32;
|
||||
|
||||
|
@ -105,14 +107,14 @@ public:
|
|||
* @return cost of move, possibly infinite */
|
||||
float operator()(const Vec2i &p1, const Vec2i &p2) const {
|
||||
assert(p1.dist(p2) < 1.5 && p1 != p2);
|
||||
assert(g_map.isInside(p2));
|
||||
//assert(g_map.isInside(p2));
|
||||
if (!aMap->canOccupy(p2, size, field)) {
|
||||
return -1.f;
|
||||
}
|
||||
if (p1.x != p2.x && p1.y != p2.y) {
|
||||
Vec2i d1, d2;
|
||||
getDiags(p1, p2, size, d1, d2);
|
||||
assert(g_map.isInside(d1) && g_map.isInside(d2));
|
||||
//assert(g_map.isInside(d1) && g_map.isInside(d2));
|
||||
if (!aMap->canOccupy(d1, 1, field) || !aMap->canOccupy(d2, 1, field) ) {
|
||||
return -1.f;
|
||||
}
|
||||
|
@ -153,23 +155,11 @@ public:
|
|||
return findPathToLocation(unit, finalPos);
|
||||
}
|
||||
|
||||
TravelState findPathToResource(Unit *unit, const Vec2i &targetPos, const ResourceType *rt) {
|
||||
assert(rt->getClass() == rcTechTree || rt->getClass() == rcTileset);
|
||||
ResourceMapKey mapKey(rt, unit->getCurrField(), unit->getType()->getSize());
|
||||
PMap1Goal goal(world->getCartographer()->getResourceMap(mapKey));
|
||||
return findPathToGoal(unit, goal, targetPos);
|
||||
}
|
||||
TravelState findPathToResource(Unit *unit, const Vec2i &targetPos, const ResourceType *rt);
|
||||
|
||||
TravelState findPathToStore(Unit *unit, const Unit *store) {
|
||||
Vec2i target = store->getCenteredPos();
|
||||
PMap1Goal goal(world->getCartographer()->getStoreMap(store, unit));
|
||||
return findPathToGoal(unit, goal, target);
|
||||
}
|
||||
TravelState findPathToStore(Unit *unit, const Unit *store);
|
||||
|
||||
TravelState findPathToBuildSite(Unit *unit, const UnitType *buildingType, const Vec2i &buildingPos) {
|
||||
PMap1Goal goal(world->getCartographer()->getSiteMap(buildingType, buildingPos, unit));
|
||||
return findPathToGoal(unit, goal, unit->getTargetPos());
|
||||
}
|
||||
TravelState findPathToBuildSite(Unit *unit, const UnitType *buildingType, const Vec2i &buildingPos);
|
||||
|
||||
bool isLegalMove(Unit *unit, const Vec2i &pos) const;
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ enum PathType {
|
|||
|
||||
struct CardinalDir {
|
||||
public:
|
||||
enum Enum { NORTH, EAST, SOUTH, WEST };
|
||||
enum Enum { NORTH, EAST, SOUTH, WEST, COUNT };
|
||||
|
||||
CardinalDir() : value(NORTH) {}
|
||||
CardinalDir(Enum v) : value(v) {}
|
||||
|
|
|
@ -0,0 +1,577 @@
|
|||
// ==============================================================
|
||||
// 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
|
||||
// ==============================================================
|
||||
|
||||
#ifdef DEBUG_RENDERING_ENABLED
|
||||
|
||||
#include "debug_renderer.h"
|
||||
#include "route_planner.h"
|
||||
#include "influence_map.h"
|
||||
#include "cartographer.h"
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
using namespace Shared::Graphics;
|
||||
using namespace Shared::Graphics::Gl;
|
||||
using namespace Shared::Util;
|
||||
|
||||
namespace Glest { namespace Game {
|
||||
|
||||
// texture loading helper
|
||||
void _load_debug_tex(Texture2D* &texPtr, const char *fileName) {
|
||||
texPtr = g_renderer.newTexture2D(rsGame);
|
||||
texPtr->setMipmap(false);
|
||||
texPtr->getPixmap()->load(fileName);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class PathFinderTextureCallback
|
||||
// =====================================================
|
||||
|
||||
PathFinderTextureCallback::PathFinderTextureCallback()
|
||||
: debugField(fLand) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void PathFinderTextureCallback::reset() {
|
||||
pathSet.clear();
|
||||
openSet.clear();
|
||||
closedSet.clear();
|
||||
pathStart = Vec2i(-1);
|
||||
pathDest = Vec2i(-1);
|
||||
localAnnotations.clear();
|
||||
debugField = fLand;
|
||||
memset(PFDebugTextures, 0, sizeof(PFDebugTextures));
|
||||
}
|
||||
|
||||
void PathFinderTextureCallback::loadTextures() {
|
||||
# define _load_tex(i,f) _load_debug_tex(PFDebugTextures[i],f)
|
||||
char buff[128];
|
||||
for (int i=0; i < 8; ++i) {
|
||||
sprintf(buff, "data/core/misc_textures/g%02d.bmp", i);
|
||||
_load_tex(i, buff);
|
||||
}
|
||||
_load_tex(9, "data/core/misc_textures/path_start.bmp");
|
||||
_load_tex(10, "data/core/misc_textures/path_dest.bmp");
|
||||
//_load_tex(11, "data/core/misc_textures/path_both.bmp");
|
||||
//_load_tex(12, "data/core/misc_textures/path_return.bmp");
|
||||
//_load_tex(13, "data/core/misc_textures/path.bmp");
|
||||
|
||||
_load_tex(14, "data/core/misc_textures/path_node.bmp");
|
||||
_load_tex(15, "data/core/misc_textures/open_node.bmp");
|
||||
_load_tex(16, "data/core/misc_textures/closed_node.bmp");
|
||||
|
||||
for (int i=17; i < 17+8; ++i) {
|
||||
sprintf(buff, "data/core/misc_textures/l%02d.bmp", i-17);
|
||||
_load_tex(i, buff);
|
||||
}
|
||||
# undef _load_tex
|
||||
}
|
||||
|
||||
Texture2DGl* PathFinderTextureCallback::operator()(const Vec2i &cell) {
|
||||
int ndx = -1;
|
||||
if (pathStart == cell) ndx = 9;
|
||||
else if (pathDest == cell) ndx = 10;
|
||||
else if (pathSet.find(cell) != pathSet.end()) ndx = 14; // on path
|
||||
else if (closedSet.find(cell) != closedSet.end()) ndx = 16; // closed nodes
|
||||
else if (openSet.find(cell) != openSet.end()) ndx = 15; // open nodes
|
||||
else if (localAnnotations.find(cell) != localAnnotations.end()) // local annotation
|
||||
ndx = 17 + localAnnotations.find(cell)->second;
|
||||
else ndx = g_world.getCartographer()->getMasterMap()->metrics[cell].get(debugField); // else use cell metric for debug field
|
||||
return (Texture2DGl*)PFDebugTextures[ndx];
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class GridTextureCallback
|
||||
// =====================================================
|
||||
|
||||
void GridTextureCallback::loadTextures() {
|
||||
_load_debug_tex(tex, "data/core/misc_textures/grid.bmp");
|
||||
}
|
||||
|
||||
bool ResourceMapOverlay::operator()(const Vec2i &cell, Vec4f &colour) {
|
||||
ResourceMapKey mapKey(rt, fLand, 1);
|
||||
PatchMap<1> *pMap = g_world.getCartographer()->getResourceMap(mapKey);
|
||||
if (pMap && pMap->getInfluence(cell)) {
|
||||
colour = Vec4f(1.f, 1.f, 0.f, 0.7f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StoreMapOverlay::operator()(const Vec2i &cell, Vec4f &colour) {
|
||||
for (KeyList::iterator it = storeMaps.begin(); it != storeMaps.end(); ++it) {
|
||||
PatchMap<1> *pMap = g_world.getCartographer()->getStoreMap(*it, false);
|
||||
if (pMap && pMap->getInfluence(cell)) {
|
||||
colour = Vec4f(0.f, 1.f, 0.3f, 0.7f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class DebugRender
|
||||
// =====================================================
|
||||
|
||||
DebugRenderer::DebugRenderer() {
|
||||
// defaults, listed for ease of maintenance. [Note: these can be set from Lua now, use debugSet()]
|
||||
showVisibleQuad =
|
||||
captureVisibleQuad =
|
||||
regionHilights =
|
||||
resourceMapOverlay =
|
||||
storeMapOverlay =
|
||||
showFrustum =
|
||||
captureFrustum =
|
||||
gridTextures =
|
||||
buildSiteMaps =
|
||||
influenceMap =
|
||||
false;
|
||||
|
||||
AAStarTextures =
|
||||
HAAStarOverlay =
|
||||
true;
|
||||
}
|
||||
|
||||
const ResourceType* findResourceMapRes(const string &res) {
|
||||
const int &n = g_world.getTechTree()->getResourceTypeCount();
|
||||
for (int i=0; i < n; ++i) {
|
||||
const ResourceType *rt = g_world.getTechTree()->getResourceType(i);
|
||||
if (rt->getName() == res) {
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DebugRenderer::init() {
|
||||
|
||||
pfCallback.reset();
|
||||
pfCallback.loadTextures();
|
||||
|
||||
gtCallback.reset();
|
||||
gtCallback.loadTextures();
|
||||
|
||||
rhCallback.reset();
|
||||
vqCallback.reset();
|
||||
cmOverlay.reset();
|
||||
rmOverlay.reset();
|
||||
smOverlay.reset();
|
||||
bsOverlay.reset();
|
||||
|
||||
if (resourceMapOverlay) {
|
||||
rmOverlay.rt = findResourceMapRes(string("gold"));
|
||||
} else {
|
||||
rmOverlay.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void DebugRenderer::commandLine(string &line) {
|
||||
string key, val;
|
||||
size_t n = line.find('=');
|
||||
if ( n != string::npos ) {
|
||||
key = line.substr(0, n);
|
||||
val = line.substr(n+1);
|
||||
} else {
|
||||
key = line;
|
||||
}
|
||||
if ( key == "AStarTextures" ) {
|
||||
if ( val == "" ) { // no val supplied, toggle
|
||||
AAStarTextures = !AAStarTextures;
|
||||
} else {
|
||||
if ( val == "on" || val == "On" ) {
|
||||
AAStarTextures = true;
|
||||
} else {
|
||||
AAStarTextures = false;
|
||||
}
|
||||
}
|
||||
} else if ( key == "GridTextures" ) {
|
||||
if ( val == "" ) { // no val supplied, toggle
|
||||
gridTextures = !gridTextures;
|
||||
} else {
|
||||
if ( val == "on" || val == "On" ) {
|
||||
gridTextures = true;
|
||||
} else {
|
||||
gridTextures = false;
|
||||
}
|
||||
}
|
||||
} else if ( key == "ClusterOverlay" ) {
|
||||
if ( val == "" ) { // no val supplied, toggle
|
||||
HAAStarOverlay = !HAAStarOverlay;
|
||||
} else {
|
||||
if ( val == "on" || val == "On" ) {
|
||||
HAAStarOverlay = true;
|
||||
} else {
|
||||
HAAStarOverlay = false;
|
||||
}
|
||||
}
|
||||
} else if ( key == "CaptuereQuad" ) {
|
||||
captureVisibleQuad = true;
|
||||
} else if ( key == "RegionColouring" ) {
|
||||
if ( val == "" ) { // no val supplied, toggle
|
||||
regionHilights = !regionHilights;
|
||||
} else {
|
||||
if ( val == "on" || val == "On" ) {
|
||||
regionHilights = true;
|
||||
} else {
|
||||
regionHilights = false;
|
||||
}
|
||||
}
|
||||
} else if ( key == "DebugField" ) {
|
||||
Field f = fLand;
|
||||
if (val == "air") {
|
||||
f = fAir;
|
||||
}
|
||||
pfCallback.debugField = f;
|
||||
} else if (key == "Frustum") {
|
||||
if (val == "capture" || val == "Capture") {
|
||||
captureFrustum = true;
|
||||
} else if (val == "off" || val == "Off") {
|
||||
showFrustum = false;
|
||||
}
|
||||
} else if (key == "ResourceMap") {
|
||||
if ( val == "" ) { // no val supplied, toggle
|
||||
resourceMapOverlay = !resourceMapOverlay;
|
||||
} else {
|
||||
const ResourceType *rt = 0;
|
||||
if ( val == "on" || val == "On" ) {
|
||||
resourceMapOverlay = true;
|
||||
} else if (val == "off" || val == "Off") {
|
||||
resourceMapOverlay = false;
|
||||
} else {
|
||||
// else find resource
|
||||
if (!( rt = findResourceMapRes(val))) {
|
||||
g_console.addLine("Error: value='" + val + "' not valid.");
|
||||
resourceMapOverlay = false;
|
||||
}
|
||||
resourceMapOverlay = true;
|
||||
rmOverlay.rt = rt;
|
||||
}
|
||||
}
|
||||
} else if (key == "StoreMap") {
|
||||
n = val.find(',');
|
||||
if (n == string::npos) {
|
||||
g_console.addLine("Error: value='" + val + "' not valid");
|
||||
return;
|
||||
}
|
||||
storeMapOverlay = false;
|
||||
string idString = val.substr(0, n);
|
||||
++n;
|
||||
while (val[n] == ' ') ++n;
|
||||
string szString = val.substr(n);
|
||||
int id, sz;
|
||||
try {
|
||||
id = strToInt(idString);
|
||||
sz = strToInt(szString);
|
||||
} catch (runtime_error &e) {
|
||||
g_console.addLine("Error: value='" + val + "' not valid: expected id, size (two integers)");
|
||||
return;
|
||||
}
|
||||
Unit *store = g_world.findUnitById(id);
|
||||
if (!store) {
|
||||
g_console.addLine("Error: unit id " + idString + " not found");
|
||||
return;
|
||||
}
|
||||
StoreMapKey smkey(store, fLand, sz);
|
||||
PatchMap<1> *pMap = g_world.getCartographer()->getStoreMap(smkey, false);
|
||||
if (pMap) {
|
||||
smOverlay.storeMaps.push_back(smkey);
|
||||
storeMapOverlay = true;
|
||||
} else {
|
||||
g_console.addLine("Error: no StoreMap found for unit " + idString
|
||||
+ " in fLand with size " + szString);
|
||||
}
|
||||
} else if (key == "AssertClusterMap") {
|
||||
g_world.getCartographer()->getClusterMap()->assertValid();
|
||||
} else if (key == "TransitionEdges") {
|
||||
if (val == "clear") {
|
||||
clusterEdgesNorth.clear();
|
||||
clusterEdgesWest.clear();
|
||||
} else {
|
||||
n = val.find(',');
|
||||
if (n == string::npos) {
|
||||
g_console.addLine("Error: value=" + val + "not valid");
|
||||
return;
|
||||
}
|
||||
string xs = val.substr(0, n);
|
||||
val = val.substr(n + 1);
|
||||
int x = atoi(xs.c_str());
|
||||
n = val.find(':');
|
||||
if (n == string::npos) {
|
||||
g_console.addLine("Error: value=" + val + "not valid");
|
||||
return;
|
||||
}
|
||||
string ys = val.substr(0, n);
|
||||
val = val.substr(n + 1);
|
||||
int y = atoi(ys.c_str());
|
||||
if (val == "north") {
|
||||
clusterEdgesNorth.insert(Vec2i(x, y));
|
||||
} else if ( val == "west") {
|
||||
clusterEdgesWest.insert(Vec2i(x, y));
|
||||
} else if ( val == "south") {
|
||||
clusterEdgesNorth.insert(Vec2i(x, y + 1));
|
||||
} else if ( val == "east") {
|
||||
clusterEdgesWest.insert(Vec2i(x + 1, y));
|
||||
} else if ( val == "all") {
|
||||
clusterEdgesNorth.insert(Vec2i(x, y));
|
||||
clusterEdgesNorth.insert(Vec2i(x, y + 1));
|
||||
clusterEdgesWest.insert(Vec2i(x, y));
|
||||
clusterEdgesWest.insert(Vec2i(x + 1, y));
|
||||
} else {
|
||||
g_console.addLine("Error: value=" + val + "not valid");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugRenderer::renderCellTextured(const Texture2DGl *tex, const Vec3f &norm, const Vec3f &v0,
|
||||
const Vec3f &v1, const Vec3f &v2, const Vec3f &v3) {
|
||||
glBindTexture( GL_TEXTURE_2D, tex->getHandle() );
|
||||
glBegin( GL_TRIANGLE_FAN );
|
||||
glTexCoord2f( 0.f, 1.f );
|
||||
glNormal3fv( norm.ptr() );
|
||||
glVertex3fv( v0.ptr() );
|
||||
|
||||
glTexCoord2f( 1.f, 1.f );
|
||||
glNormal3fv( norm.ptr() );
|
||||
glVertex3fv( v1.ptr() );
|
||||
|
||||
glTexCoord2f( 1.f, 0.f );
|
||||
glNormal3fv( norm.ptr() );
|
||||
glVertex3fv( v2.ptr() );
|
||||
|
||||
glTexCoord2f( 0.f, 0.f );
|
||||
glNormal3fv( norm.ptr() );
|
||||
glVertex3fv( v3.ptr() );
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
void DebugRenderer::renderCellOverlay(const Vec4f colour, const Vec3f &norm,
|
||||
const Vec3f &v0, const Vec3f &v1, const Vec3f &v2, const Vec3f &v3) {
|
||||
glBegin ( GL_TRIANGLE_FAN );
|
||||
glNormal3fv(norm.ptr());
|
||||
glColor4fv( colour.ptr() );
|
||||
glVertex3fv(v0.ptr());
|
||||
glNormal3fv(norm.ptr());
|
||||
glColor4fv( colour.ptr() );
|
||||
glVertex3fv(v1.ptr());
|
||||
glNormal3fv(norm.ptr());
|
||||
glColor4fv( colour.ptr() );
|
||||
glVertex3fv(v2.ptr());
|
||||
glNormal3fv(norm.ptr());
|
||||
glColor4fv( colour.ptr() );
|
||||
glVertex3fv(v3.ptr());
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
void DebugRenderer::renderArrow(
|
||||
const Vec3f &pos1, const Vec3f &_pos2, const Vec3f &color, float width) {
|
||||
const int tesselation = 3;
|
||||
const float arrowEndSize = 0.5f;
|
||||
|
||||
Vec3f dir = Vec3f(_pos2 - pos1);
|
||||
float len = dir.length();
|
||||
float alphaFactor = 0.3f;
|
||||
|
||||
dir.normalize();
|
||||
Vec3f pos2 = _pos2 - dir;
|
||||
Vec3f normal = dir.cross(Vec3f(0, 1, 0));
|
||||
|
||||
Vec3f pos2Left = pos2 + normal * (width - 0.05f) - dir * arrowEndSize * width;
|
||||
Vec3f pos2Right = pos2 - normal * (width - 0.05f) - dir * arrowEndSize * width;
|
||||
Vec3f pos1Left = pos1 + normal * (width + 0.02f);
|
||||
Vec3f pos1Right = pos1 - normal * (width + 0.02f);
|
||||
|
||||
//arrow body
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for(int i=0; i<=tesselation; ++i){
|
||||
float t= static_cast<float>(i)/tesselation;
|
||||
Vec3f a= pos1Left.lerp(t, pos2Left);
|
||||
Vec3f b= pos1Right.lerp(t, pos2Right);
|
||||
Vec4f c= Vec4f(color, t*0.25f*alphaFactor);
|
||||
|
||||
glColor4fv(c.ptr());
|
||||
glVertex3fv(a.ptr());
|
||||
glVertex3fv(b.ptr());
|
||||
}
|
||||
glEnd();
|
||||
|
||||
//arrow end
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3fv((pos2Left + normal*(arrowEndSize-0.1f)).ptr());
|
||||
glVertex3fv((pos2Right - normal*(arrowEndSize-0.1f)).ptr());
|
||||
glVertex3fv((pos2 + dir*(arrowEndSize-0.1f)).ptr());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DebugRenderer::renderPathOverlay() {
|
||||
//return;
|
||||
Vec3f one, two;
|
||||
if ( waypoints.size() < 2 ) return;
|
||||
|
||||
assertGl();
|
||||
glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glDisable( GL_ALPHA_TEST );
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glLineWidth(2.f);
|
||||
glActiveTexture( GL_TEXTURE0 );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
|
||||
list<Vec3f>::iterator it = waypoints.begin();
|
||||
one = *it;
|
||||
++it;
|
||||
two = *it;
|
||||
while ( true ) {
|
||||
renderArrow(one,two,Vec3f(1.0f, 1.0f, 0.f), 0.15f);
|
||||
one = two;
|
||||
++it;
|
||||
if ( it == waypoints.end() ) break;
|
||||
two = *it;
|
||||
}
|
||||
//Restore
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void DebugRenderer::renderIntraClusterEdges(const Vec2i &cluster, CardinalDir dir) {
|
||||
ClusterMap *cm = g_world.getCartographer()->getClusterMap();
|
||||
const Map *map = g_world.getMap();
|
||||
|
||||
if (cluster.x < 0 || cluster.x >= cm->getWidth()
|
||||
|| cluster.y < 0 || cluster.y >= cm->getHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Transitions transitions;
|
||||
if (dir != CardinalDir::COUNT) {
|
||||
TransitionCollection &tc = cm->getBorder(cluster, dir)->transitions[fLand];
|
||||
for (int i=0; i < tc.n; ++i) {
|
||||
transitions.push_back(tc.transitions[i]);
|
||||
}
|
||||
} else {
|
||||
cm->getTransitions(cluster, fLand, transitions);
|
||||
}
|
||||
assertGl();
|
||||
glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glDisable( GL_ALPHA_TEST );
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glLineWidth(2.f);
|
||||
glActiveTexture( GL_TEXTURE0 );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
|
||||
for (Transitions::iterator ti = transitions.begin(); ti != transitions.end(); ++ti) {
|
||||
const Transition* &t = *ti;
|
||||
float h = map->getCell(t->nwPos)->getHeight();
|
||||
Vec3f t1Pos(t->nwPos.x + 0.5f, h + 0.1f, t->nwPos.y + 0.5f);
|
||||
for (Edges::const_iterator ei = t->edges.begin(); ei != t->edges.end(); ++ei) {
|
||||
Edge * const &e = *ei;
|
||||
//if (e->cost(1) != numeric_limits<float>::infinity()) {
|
||||
const Transition* t2 = e->transition();
|
||||
h = map->getCell(t2->nwPos)->getHeight();
|
||||
Vec3f t2Pos(t2->nwPos.x + 0.5f, h + 0.1f, t2->nwPos.y + 0.5f);
|
||||
renderArrow(t1Pos, t2Pos, Vec3f(1.f, 0.f, 1.f), 0.2f);
|
||||
//}
|
||||
}
|
||||
}
|
||||
//Restore
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void DebugRenderer::renderFrustum() const {
|
||||
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 );
|
||||
|
||||
glPointSize(5);
|
||||
glColor3f(1.f, 0.2f, 0.2f);
|
||||
glBegin(GL_POINTS);
|
||||
for (int i=0; i < 8; ++i) glVertex3fv(frstmPoints[i].ptr());
|
||||
glEnd();
|
||||
|
||||
glLineWidth(2);
|
||||
glColor3f(0.1f, 0.5f, 0.1f); // near
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (int i=0; i < 4; ++i) glVertex3fv(frstmPoints[i].ptr());
|
||||
glEnd();
|
||||
|
||||
glColor3f(0.1f, 0.1f, 0.5f); // far
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (int i=4; i < 8; ++i) glVertex3fv(frstmPoints[i].ptr());
|
||||
glEnd();
|
||||
|
||||
glColor3f(0.1f, 0.5f, 0.5f);
|
||||
glBegin(GL_LINES);
|
||||
for (int i=0; i < 4; ++i) {
|
||||
glVertex3fv(frstmPoints[i].ptr()); // near
|
||||
glVertex3fv(frstmPoints[i+4].ptr()); // far
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void DebugRenderer::setInfluenceMap(TypeMap<float> *iMap, Vec3f colour, float max) {
|
||||
imOverlay.iMap = iMap;
|
||||
imOverlay.baseColour = colour;
|
||||
imOverlay.max = max;
|
||||
influenceMap = true;
|
||||
}
|
||||
|
||||
void DebugRenderer::renderEffects(Quad2i &quad) {
|
||||
if (regionHilights && !rhCallback.empty()) {
|
||||
renderCellOverlay(quad, rhCallback);
|
||||
}
|
||||
if (showVisibleQuad) {
|
||||
renderCellOverlay(quad, vqCallback);
|
||||
}
|
||||
if (HAAStarOverlay) {
|
||||
renderCellOverlay(quad, cmOverlay);
|
||||
renderPathOverlay();
|
||||
set<Vec2i>::iterator it;
|
||||
for (it = clusterEdgesWest.begin(); it != clusterEdgesWest.end(); ++it) {
|
||||
renderIntraClusterEdges(*it, CardinalDir::WEST);
|
||||
}
|
||||
for (it = clusterEdgesNorth.begin(); it != clusterEdgesNorth.end(); ++it) {
|
||||
renderIntraClusterEdges(*it, CardinalDir::NORTH);
|
||||
}
|
||||
}
|
||||
if (resourceMapOverlay && rmOverlay.rt) {
|
||||
renderCellOverlay(quad, rmOverlay);
|
||||
}
|
||||
if (storeMapOverlay && !smOverlay.storeMaps.empty()) {
|
||||
renderCellOverlay(quad, smOverlay);
|
||||
}
|
||||
if (buildSiteMaps && !bsOverlay.cells.empty()) {
|
||||
renderCellOverlay(quad, bsOverlay);
|
||||
}
|
||||
//if (showFrustum) {
|
||||
// renderFrustum();
|
||||
//}
|
||||
if (influenceMap) {
|
||||
renderCellOverlay(quad, imOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
DebugRenderer& getDebugRenderer() {
|
||||
static DebugRenderer debugRenderer;
|
||||
return debugRenderer;
|
||||
}
|
||||
|
||||
}} // end namespace Glest::Debug
|
||||
|
||||
#endif // _GAE_DEBUG_EDITION_
|
|
@ -0,0 +1,403 @@
|
|||
// ==============================================================
|
||||
// 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
|
|
@ -305,6 +305,8 @@ void Renderer::initGame(const Game *game){
|
|||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
IF_DEBUG_EDITION( getDebugRenderer().init(); )
|
||||
|
||||
//texture init
|
||||
modelManager[rsGame]->init();
|
||||
textureManager[rsGame]->init();
|
||||
|
@ -1176,7 +1178,11 @@ void Renderer::renderMessageBox(const GraphicMessageBox *messageBox){
|
|||
// ==================== complex rendering ====================
|
||||
|
||||
void Renderer::renderSurface(){
|
||||
|
||||
IF_DEBUG_EDITION(
|
||||
if (getDebugRenderer().willRenderSurface()) {
|
||||
getDebugRenderer().renderSurface(visibleQuad / Map::cellScale);
|
||||
} else {
|
||||
)
|
||||
int lastTex=-1;
|
||||
int currTex;
|
||||
const World *world= game->getWorld();
|
||||
|
@ -1276,6 +1282,11 @@ void Renderer::renderSurface(){
|
|||
//assert
|
||||
glGetError(); //remove when first mtex problem solved
|
||||
assertGl();
|
||||
|
||||
IF_DEBUG_EDITION(
|
||||
} // end else, if not renderering debug textures instead of regular terrain
|
||||
getDebugRenderer().renderEffects(visibleQuad / Map::cellScale);
|
||||
)
|
||||
}
|
||||
|
||||
void Renderer::renderObjects(const int renderFps, const int worldFrameCount) {
|
||||
|
|
|
@ -31,29 +31,14 @@
|
|||
#include "model.h"
|
||||
#include "graphics_interface.h"
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
#ifdef DEBUG_RENDERING_ENABLED
|
||||
# define IF_DEBUG_EDITION(x) x
|
||||
# include "debug_renderer.h"
|
||||
#else
|
||||
# define IF_DEBUG_EDITION(x)
|
||||
#endif
|
||||
|
||||
using Shared::Graphics::Texture;
|
||||
using Shared::Graphics::Texture2D;
|
||||
using Shared::Graphics::Texture3D;
|
||||
using Shared::Graphics::ModelRenderer;
|
||||
using Shared::Graphics::TextRenderer2D;
|
||||
using Shared::Graphics::ParticleRenderer;
|
||||
using Shared::Graphics::ParticleManager;
|
||||
using Shared::Graphics::ModelManager;
|
||||
using Shared::Graphics::TextureManager;
|
||||
using Shared::Graphics::FontManager;
|
||||
using Shared::Graphics::Font2D;
|
||||
using Shared::Graphics::Matrix4f;
|
||||
using Shared::Graphics::Vec2i;
|
||||
using Shared::Graphics::Quad2i;
|
||||
using Shared::Graphics::Vec3f;
|
||||
using Shared::Graphics::Model;
|
||||
using Shared::Graphics::ParticleSystem;
|
||||
using Shared::Graphics::Pixmap2D;
|
||||
using Shared::Graphics::Camera;
|
||||
using Shared::Graphics::MeshCallback;
|
||||
using Shared::Graphics::Mesh;
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
using namespace Shared::Graphics;
|
||||
|
||||
|
@ -79,7 +64,6 @@ class MainMenu;
|
|||
class Console;
|
||||
class MenuBackground;
|
||||
class ChatManager;
|
||||
class Texture;
|
||||
class Object;
|
||||
|
||||
// ===========================================================
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
void incBlockCount() {++blockCount;} /**< increment block counter */
|
||||
void push(Vec2i &pos) {push_front(pos);} /**< push onto front of path */
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
// old style, to work with original PathFinder
|
||||
Vec2i peek() {return back();} /**< peek at the next position */
|
||||
void pop() {this->pop_back();} /**< pop the next position off the path */
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "object.h"
|
||||
#include "faction.h"
|
||||
#include "network_manager.h"
|
||||
#include "cartographer.h"
|
||||
#include "route_planner.h"
|
||||
#include "leak_dumper.h"
|
||||
|
||||
using namespace Shared::Graphics;
|
||||
|
@ -49,7 +51,8 @@ void UnitUpdater::init(Game *game){
|
|||
this->map= world->getMap();
|
||||
this->console= game->getConsole();
|
||||
this->scriptManager= game->getScriptManager();
|
||||
pathFinder.init(map);
|
||||
routePlanner = world->getRoutePlanner();
|
||||
//pathFinder.init(map);
|
||||
}
|
||||
|
||||
|
||||
|
@ -189,12 +192,13 @@ void UnitUpdater::updateMove(Unit *unit){
|
|||
|
||||
Vec2i pos= command->getUnit()!=NULL? command->getUnit()->getCenteredPos(): command->getPos();
|
||||
|
||||
switch(pathFinder.findPath(unit, pos)){
|
||||
switch (routePlanner->findPath(unit, pos)) {
|
||||
case PathFinder::tsOnTheWay:
|
||||
unit->setCurrSkill(mct->getMoveSkillType());
|
||||
break;
|
||||
|
||||
case PathFinder::tsBlocked:
|
||||
unit->setCurrSkill(scStop);
|
||||
if(unit->getPath()->isBlocked()){
|
||||
unit->finishCommand();
|
||||
}
|
||||
|
@ -238,7 +242,7 @@ void UnitUpdater::updateAttack(Unit *unit){
|
|||
}
|
||||
|
||||
//if unit arrives destPos order has ended
|
||||
switch (pathFinder.findPath(unit, pos)){
|
||||
switch (routePlanner->findPath(unit, pos)){
|
||||
case PathFinder::tsOnTheWay:
|
||||
unit->setCurrSkill(act->getMoveSkillType());
|
||||
break;
|
||||
|
@ -283,7 +287,7 @@ void UnitUpdater::updateBuild(Unit *unit){
|
|||
//if not building
|
||||
const UnitType *ut= command->getUnitType();
|
||||
|
||||
switch (pathFinder.findPath(unit, command->getPos()-Vec2i(1))){
|
||||
switch (routePlanner->findPathToBuildSite(unit, ut, command->getPos())) {
|
||||
case PathFinder::tsOnTheWay:
|
||||
unit->setCurrSkill(bct->getMoveSkillType());
|
||||
break;
|
||||
|
@ -305,6 +309,7 @@ void UnitUpdater::updateBuild(Unit *unit){
|
|||
unit->setCurrSkill(bct->getBuildSkillType());
|
||||
unit->setTarget(builtUnit);
|
||||
map->prepareTerrain(builtUnit);
|
||||
world->getCartographer()->updateMapMetrics(builtUnit->getPos(), builtUnit->getType()->getSight());
|
||||
command->setUnit(builtUnit);
|
||||
|
||||
//play start sound
|
||||
|
@ -378,18 +383,19 @@ void UnitUpdater::updateHarvest(Unit *unit){
|
|||
Resource *r= map->getSurfaceCell(Map::toSurfCoords(command->getPos()))->getResource();
|
||||
if(r!=NULL && hct->canHarvest(r->getType())){
|
||||
//if can harvest dest. pos
|
||||
if(unit->getPos().dist(command->getPos())<harvestDistance &&
|
||||
if(/*unit->getPos().dist(command->getPos())<harvestDistance &&*/
|
||||
map->isResourceNear(unit->getPos(), unit->getType()->getSize(), r->getType(), targetPos)) {
|
||||
//if it finds resources it starts harvesting
|
||||
unit->setCurrSkill(hct->getHarvestSkillType());
|
||||
unit->setTargetPos(targetPos);
|
||||
command->setPos(targetPos);
|
||||
unit->setLoadCount(0);
|
||||
unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType());
|
||||
}
|
||||
else{
|
||||
//if not continue walking
|
||||
switch(pathFinder.findPath(unit, command->getPos())){
|
||||
case PathFinder::tsOnTheWay:
|
||||
switch (routePlanner->findPathToResource(unit, command->getPos(), r->getType())) {
|
||||
case tsMoving:
|
||||
unit->setCurrSkill(hct->getMoveSkillType());
|
||||
break;
|
||||
default:
|
||||
|
@ -409,7 +415,7 @@ void UnitUpdater::updateHarvest(Unit *unit){
|
|||
//if loaded, return to store
|
||||
Unit *store= world->nearestStore(unit->getPos(), unit->getFaction()->getIndex(), unit->getLoadType());
|
||||
if(store!=NULL){
|
||||
switch(pathFinder.findPath(unit, store->getCenteredPos())){
|
||||
switch(routePlanner->findPathToStore(unit, store)){
|
||||
case PathFinder::tsOnTheWay:
|
||||
unit->setCurrSkill(hct->getMoveLoadedSkillType());
|
||||
break;
|
||||
|
@ -448,42 +454,13 @@ void UnitUpdater::updateHarvest(Unit *unit){
|
|||
SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()));
|
||||
Resource *r= sc->getResource();
|
||||
|
||||
/*
|
||||
if (r != NULL) {
|
||||
//if there is a resource, continue working, until loaded
|
||||
unit->update2();
|
||||
if(unit->getProgress2()>=hct->getHitsPerUnit()){
|
||||
unit->setProgress2(0);
|
||||
unit->setLoadCount(unit->getLoadCount()+1);
|
||||
|
||||
//if resource exausted, then delete it and stop
|
||||
if(r->decAmount(1)){
|
||||
sc->deleteResource();
|
||||
unit->setCurrSkill(hct->getStopLoadedSkillType());
|
||||
}
|
||||
|
||||
if(unit->getLoadCount()==hct->getMaxLoad()){
|
||||
unit->setCurrSkill(hct->getStopLoadedSkillType());
|
||||
unit->getPath()->clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else{
|
||||
//if there is no resource, just stop
|
||||
unit->setCurrSkill(hct->getStopLoadedSkillType());
|
||||
}
|
||||
*/
|
||||
|
||||
if (r != NULL) {
|
||||
// Fix from Silnarm to disable cheating - START
|
||||
if (!hct->canHarvest(r->getType()) || r->getType() != unit->getLoadType()) {
|
||||
// hct has changed to a different harvest command.
|
||||
unit->setCurrSkill(hct->getStopLoadedSkillType()); // this is actually the wrong animation
|
||||
unit->getPath()->clear();
|
||||
return;
|
||||
}
|
||||
// Fix from Silnarm to disable cheating - END
|
||||
|
||||
// if there is a resource, continue working, until loaded
|
||||
unit->update2();
|
||||
|
@ -494,7 +471,9 @@ void UnitUpdater::updateHarvest(Unit *unit){
|
|||
|
||||
//if resource exausted, then delete it and stop
|
||||
if (r->decAmount(1)) {
|
||||
const ResourceType *rt = r->getType();
|
||||
sc->deleteResource();
|
||||
world->getCartographer()->onResourceDepleted(unit->getTargetPos(), rt);
|
||||
unit->setCurrSkill(hct->getStopLoadedSkillType());
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +511,7 @@ void UnitUpdater::updateRepair(Unit *unit){
|
|||
unit->setCurrSkill(rct->getRepairSkillType());
|
||||
}
|
||||
else{
|
||||
switch(pathFinder.findPath(unit, command->getPos())){
|
||||
switch(routePlanner->findPath(unit, command->getPos())){
|
||||
case PathFinder::tsOnTheWay:
|
||||
unit->setCurrSkill(rct->getMoveSkillType());
|
||||
break;
|
||||
|
@ -656,12 +635,17 @@ void UnitUpdater::updateMorph(Unit *unit){
|
|||
unit->update2();
|
||||
if(unit->getProgress2()>mct->getProduced()->getProductionTime()){
|
||||
|
||||
bool needMapUpdate = unit->getType()->isMobile() != mct->getMorphUnit()->isMobile();
|
||||
|
||||
//finish the command
|
||||
if(unit->morph(mct)){
|
||||
unit->finishCommand();
|
||||
if(gui->isSelected(unit)){
|
||||
gui->onSelectionChanged();
|
||||
}
|
||||
if (needMapUpdate) {
|
||||
world->getCartographer()->updateMapMetrics(unit->getPos(), unit->getType()->getSize());
|
||||
}
|
||||
scriptManager->onUnitCreated(unit);
|
||||
}
|
||||
else{
|
||||
|
@ -730,6 +714,9 @@ void UnitUpdater::damage(Unit *attacker, const AttackSkillType* ast, Unit *attac
|
|||
if(attacked->decHp(static_cast<int>(damage))){
|
||||
world->getStats()->kill(attacker->getFactionIndex(), attacked->getFactionIndex());
|
||||
attacker->incKills();
|
||||
if (!attacked->getType()->isMobile()) {
|
||||
world->getCartographer()->updateMapMetrics(attacked->getPos(), attacked->getType()->getSize());
|
||||
}
|
||||
scriptManager->onUnitDied(attacked);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Glest{ namespace Game{
|
|||
class Unit;
|
||||
class Map;
|
||||
class ScriptManager;
|
||||
class RoutePlanner;
|
||||
|
||||
// =====================================================
|
||||
// class UnitUpdater
|
||||
|
@ -53,7 +54,8 @@ private:
|
|||
World *world;
|
||||
Console *console;
|
||||
ScriptManager *scriptManager;
|
||||
PathFinder pathFinder;
|
||||
//PathFinder pathFinder;
|
||||
RoutePlanner *routePlanner;
|
||||
Game *game;
|
||||
RandomGen random;
|
||||
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
#include "sound_renderer.h"
|
||||
#include "game_settings.h"
|
||||
#include "cache_manager.h"
|
||||
#include "route_planner.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "leak_dumper.h"
|
||||
|
||||
using namespace Shared::Graphics;
|
||||
|
@ -48,6 +51,9 @@ World::World(){
|
|||
fogOfWarSmoothing= config.getBool("FogOfWarSmoothing");
|
||||
fogOfWarSmoothingFrameSkip= config.getInt("FogOfWarSmoothingFrameSkip");
|
||||
|
||||
routePlanner = 0;
|
||||
cartographer = 0;
|
||||
|
||||
frameCount= 0;
|
||||
//nextUnitId= 0;
|
||||
|
||||
|
@ -61,6 +67,10 @@ World::~World() {
|
|||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
delete techTree;
|
||||
techTree = NULL;
|
||||
delete routePlanner;
|
||||
routePlanner = 0;
|
||||
delete cartographer;
|
||||
cartographer = 0;
|
||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
}
|
||||
|
||||
|
@ -98,8 +108,6 @@ void World::init(Game *game, bool createUnits){
|
|||
this->game = game;
|
||||
scriptManager= game->getScriptManager();
|
||||
|
||||
unitUpdater.init(game);
|
||||
|
||||
GameSettings *gs = game->getGameSettings();
|
||||
if(fogOfWarOverride == false) {
|
||||
fogOfWar = gs->getFogOfWar();
|
||||
|
@ -110,6 +118,12 @@ void World::init(Game *game, bool createUnits){
|
|||
initMap();
|
||||
initSplattedTextures();
|
||||
|
||||
// must be done after initMap()
|
||||
routePlanner = new RoutePlanner(this);
|
||||
cartographer = new Cartographer(this);
|
||||
|
||||
unitUpdater.init(game);
|
||||
|
||||
//minimap must be init after sum computation
|
||||
initMinimap();
|
||||
if(createUnits){
|
||||
|
@ -276,6 +290,7 @@ void World::tick(){
|
|||
}
|
||||
}
|
||||
}
|
||||
cartographer->tick();
|
||||
}
|
||||
|
||||
Unit* World::findUnitById(int id){
|
||||
|
@ -692,8 +707,8 @@ void World::initUnits(){
|
|||
}
|
||||
if (unit->getType()->hasSkillClass(scBeBuilt)) {
|
||||
map.flatternTerrain(unit);
|
||||
cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize());
|
||||
}
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -666,7 +666,7 @@ char Window::getKey(SDL_keysym keysym,bool skipSpecialKeys) {
|
|||
}
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %u] c = [%d]\n",__FILE__,__FUNCTION__,__LINE__,c);
|
||||
return c;
|
||||
return (c & 0xFF);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue