diff --git a/source/glest_game/ai/annotated_map.h b/source/glest_game/ai/annotated_map.h index 3a6dec73..f3054dbb 100644 --- a/source/glest_game/ai/annotated_map.h +++ b/source/glest_game/ai/annotated_map.h @@ -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; diff --git a/source/glest_game/ai/cartographer.cpp b/source/glest_game/ai/cartographer.cpp index 59eac03b..ea217d64 100644 --- a/source/glest_game/ai/cartographer.cpp +++ b/source/glest_game/ai/cartographer.cpp @@ -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(tl,br)); } void Cartographer::fixupResourceMaps(const ResourceType *rt, const Vec2i &pos) { + PF_TRACE(); const Map &map = *world->getMap(); Vec2i junk; for (set::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(); } diff --git a/source/glest_game/ai/cartographer.h b/source/glest_game/ai/cartographer.h index 392e1a22..2b9d4b45 100644 --- a/source/glest_game/ai/cartographer.h +++ b/source/glest_game/ai/cartographer.h @@ -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(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>* getStoreMap(StoreMapKey key, bool build=true); + PatchMap<1>* getStoreMap(const Unit *store, const Unit *worker); + + PatchMap<1>* getSiteMap(BuildSiteMapKey key); + PatchMap<1>* getSiteMap(const UnitType *ut, const Vec2i &pos, Unit *worker); void adjustGlestimalMap(Field f, TypeMap &iMap, const Vec2i &pos, float range); void buildGlestimalMap(Field f, V2iList &positions); diff --git a/source/glest_game/ai/cluster_map.cpp b/source/glest_game/ai/cluster_map.cpp index 0bf6b349..186c27a3 100644 --- a/source/glest_game/ai/cluster_map.cpp +++ b/source/glest_game/ai/cluster_map.cpp @@ -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::iterator it = linePath.begin(); vector::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; } diff --git a/source/glest_game/ai/route_planner.cpp b/source/glest_game/ai/route_planner.cpp index b7b19aec..909b278c 100644 --- a/source/glest_game/ai/route_planner.cpp +++ b/source/glest_game/ai/route_planner.cpp @@ -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(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(); diff --git a/source/glest_game/ai/route_planner.h b/source/glest_game/ai/route_planner.h index 0dd28ad3..a0001a8e 100644 --- a/source/glest_game/ai/route_planner.h +++ b/source/glest_game/ai/route_planner.h @@ -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; diff --git a/source/glest_game/game/game_constants.h b/source/glest_game/game/game_constants.h index b9a8e2d7..a91a799c 100644 --- a/source/glest_game/game/game_constants.h +++ b/source/glest_game/game/game_constants.h @@ -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) {} diff --git a/source/glest_game/graphics/debug_renderer.cpp b/source/glest_game/graphics/debug_renderer.cpp new file mode 100644 index 00000000..8d30cf9e --- /dev/null +++ b/source/glest_game/graphics/debug_renderer.cpp @@ -0,0 +1,577 @@ +// ============================================================== +// This file is part of The Glest Advanced Engine +// +// Copyright (C) 2009 James McCulloch +// +// 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(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::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::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 *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::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_ diff --git a/source/glest_game/graphics/debug_renderer.h b/source/glest_game/graphics/debug_renderer.h new file mode 100644 index 00000000..34e387fd --- /dev/null +++ b/source/glest_game/graphics/debug_renderer.h @@ -0,0 +1,403 @@ +// ============================================================== +// This file is part of The Glest Advanced Engine +// +// Copyright (C) 2009 James McCulloch +// +// 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(Program::getInstance()->getState())->getWorld()) +#define g_console (*static_cast(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 pathSet, openSet, closedSet; + Vec2i pathStart, pathDest; + map 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 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 *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 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 entranceCells; + set 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 KeyList; + KeyList storeMaps; + + void reset() { storeMaps.clear(); } + + bool operator()(const Vec2i &cell, Vec4f &colour); +}; + +class BuildSiteMapOverlay { +public: + set 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 clusterEdgesWest; + set 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 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 *iMap, Vec3f colour, float max); + + PathFinderTextureCallback& getPFCallback() { return pfCallback; } + ClusterMapOverlay& getCMOverlay() { return cmOverlay; } + +private: + /***/ + template + 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 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 diff --git a/source/glest_game/graphics/renderer.cpp b/source/glest_game/graphics/renderer.cpp index 94a4ec67..cba40a5c 100644 --- a/source/glest_game/graphics/renderer.cpp +++ b/source/glest_game/graphics/renderer.cpp @@ -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) { diff --git a/source/glest_game/graphics/renderer.h b/source/glest_game/graphics/renderer.h index aebc7a82..827d6e3a 100644 --- a/source/glest_game/graphics/renderer.h +++ b/source/glest_game/graphics/renderer.h @@ -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; // =========================================================== diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index 4d1d9228..5bb15bcd 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -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 */ diff --git a/source/glest_game/world/unit_updater.cpp b/source/glest_game/world/unit_updater.cpp index 4031dabc..e1ccd561 100644 --- a/source/glest_game/world/unit_updater.cpp +++ b/source/glest_game/world/unit_updater.cpp @@ -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,22 +383,23 @@ 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())getPos().dist(command->getPos())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: - unit->setCurrSkill(hct->getMoveSkillType()); - break; - default: - break; + switch (routePlanner->findPathToResource(unit, command->getPos(), r->getType())) { + case tsMoving: + unit->setCurrSkill(hct->getMoveSkillType()); + break; + default: + break; } } } @@ -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(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); } } diff --git a/source/glest_game/world/unit_updater.h b/source/glest_game/world/unit_updater.h index 1035b323..ea364042 100644 --- a/source/glest_game/world/unit_updater.h +++ b/source/glest_game/world/unit_updater.h @@ -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; diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index f59222a2..97a5839b 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -22,7 +22,10 @@ #include "sound_renderer.h" #include "game_settings.h" #include "cache_manager.h" +#include "route_planner.h" + #include + #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){ @@ -690,10 +705,10 @@ void World::initUnits(){ else{ throw runtime_error("Unit cant be placed, this error is caused because there is no enough place to put the units near its start location, make a better map: "+unit->getType()->getName() + " Faction: "+intToStr(i)); } - if(unit->getType()->hasSkillClass(scBeBuilt)){ - map.flatternTerrain(unit); + 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()); } } diff --git a/source/shared_lib/sources/platform/sdl/window.cpp b/source/shared_lib/sources/platform/sdl/window.cpp index c027a3c6..114f9ce4 100644 --- a/source/shared_lib/sources/platform/sdl/window.cpp +++ b/source/shared_lib/sources/platform/sdl/window.cpp @@ -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; }