mirror of
https://github.com/glest/glest-source.git
synced 2025-02-26 12:43:06 +01:00
196 lines
7.8 KiB
C++
196 lines
7.8 KiB
C++
// ==============================================================
|
|
// This file is part of Glest (www.glest.org)
|
|
//
|
|
// 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
|
|
// ==============================================================
|
|
//
|
|
// File: node_pool.h
|
|
//
|
|
|
|
#ifndef _GLEST_GAME_PATHFINDER_NODE_POOL_H_
|
|
#define _GLEST_GAME_PATHFINDER_NODE_POOL_H_
|
|
|
|
#include "vec.h"
|
|
#include "game_constants.h"
|
|
|
|
#include "heap.h"
|
|
#include "types.h"
|
|
|
|
#include <algorithm>
|
|
#include <set>
|
|
#include <list>
|
|
//#include <limits>
|
|
|
|
namespace Glest { namespace Game {
|
|
|
|
using Shared::Util::MinHeap;
|
|
using Shared::Graphics::Vec2i;
|
|
using namespace Shared::Platform;
|
|
|
|
#pragma pack(push, 4)
|
|
struct PosOff { /**< A bit packed position (Vec2i) and offset (direction) pair */
|
|
PosOff() : x(0), y(0), ox(0), oy(0) {} /**< Construct a PosOff [0,0] */
|
|
PosOff(Vec2i pos) : ox(0),oy(0) { *this = pos; } /**< Construct a PosOff [pos.x, pos.y] */
|
|
PosOff(int x, int y) : x(x) ,y(y) ,ox(0), oy(0) {} /**< Construct a PosOff [x,y] */
|
|
PosOff& operator=(Vec2i pos) { /**< Assign from Vec2i */
|
|
assert(pos.x <= 8191 && pos.y <= 8191);
|
|
x = pos.x; y = pos.y; return *this;
|
|
}
|
|
bool operator==(PosOff &p) const
|
|
{ return x == p.x && y == p.y; } /**< compare position components only */
|
|
Vec2i getPos() const { return Vec2i(x, y); } /**< this packed pos as Vec2i */
|
|
Vec2i getPrev() const { return Vec2i(x + ox, y + oy); } /**< return pos + offset */
|
|
Vec2i getOffset() const { return Vec2i(ox, oy); } /**< return offset */
|
|
bool hasOffset() const { return ox || oy; } /**< has an offset */
|
|
bool valid() const { return x >= 0 && y >= 0; } /**< is this position valid */
|
|
|
|
int32 x : 14; /**< x coordinate */
|
|
int32 y : 14; /**< y coordinate */
|
|
int32 ox : 2; /**< x offset */
|
|
int32 oy : 2; /**< y offset */
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
// =====================================================
|
|
// struct AStarNode
|
|
// =====================================================
|
|
#pragma pack(push, 2)
|
|
struct AStarNode { /**< A node structure for A* with NodePool */
|
|
PosOff posOff; /**< position of this node, and direction of best path to it */
|
|
float heuristic; /**< estimate of distance to goal */
|
|
float distToHere; /**< cost from origin to this node */
|
|
|
|
float est() const { return distToHere + heuristic;} /**< estimate, costToHere + heuristic */
|
|
Vec2i pos() const { return posOff.getPos(); } /**< position of this node */
|
|
Vec2i prev() const { return posOff.getPrev(); } /**< best path to this node is from */
|
|
bool hasPrev() const{ return posOff.hasOffset(); } /**< has valid previous 'pointer' */
|
|
|
|
int32 heap_ndx;
|
|
void setHeapIndex(int ndx) { heap_ndx = ndx; }
|
|
int getHeapIndex() const { return heap_ndx; }
|
|
|
|
bool operator<(const AStarNode &that) const {
|
|
const float diff = est() - that.est();
|
|
if (diff < 0.f) return true;
|
|
if (diff > 0.f) return false;
|
|
// tie, prefer closer to goal...
|
|
const float h_diff = heuristic - that.heuristic;
|
|
if (h_diff < 0.f) return true;
|
|
if (h_diff > 0.f) return false;
|
|
// still tied... just distinguish them somehow...
|
|
return pos() < that.pos();
|
|
}
|
|
}; // == 128 bits (16 bytes)
|
|
#pragma pack(pop)
|
|
|
|
// ========================================================
|
|
// class NodePool
|
|
// ========================================================
|
|
class NodePool { /**< A NodeStorage class (template interface) for A* */
|
|
private:
|
|
static const int size = 512; /**< total number of AStarNodes in each pool */
|
|
AStarNode *stock; /**< The block of nodes */
|
|
int counter; /**< current counter */
|
|
|
|
// =====================================================
|
|
// struct MarkerArray
|
|
// =====================================================
|
|
/** An Marker & Pointer Array supporting two mark types, open and closed. */
|
|
///@todo replace pointers with indices, interleave mark and index arrays
|
|
struct MarkerArray {
|
|
private:
|
|
int stride; /**< stride of array */
|
|
unsigned int counter; /**< the counter */
|
|
unsigned int *marker; /**< the mark array */
|
|
AStarNode **pArray; /**< the pointer array */
|
|
public:
|
|
MarkerArray(int w, int h) : stride(w), counter(0) {
|
|
marker = new unsigned int[w * h];
|
|
memset(marker, 0, w * h * sizeof(unsigned int));
|
|
pArray = new AStarNode*[w * h];
|
|
memset(pArray, 0, w * h * sizeof(AStarNode*));
|
|
}
|
|
~MarkerArray() { delete [] marker; delete [] pArray; }
|
|
inline void newSearch() { counter += 2; }
|
|
inline void setOpen(const Vec2i &pos) { marker[pos.y * stride + pos.x] = counter; }
|
|
inline void setClosed(const Vec2i &pos) { marker[pos.y * stride + pos.x] = counter + 1; }
|
|
inline bool isOpen(const Vec2i &pos) { return marker[pos.y * stride + pos.x] == counter; }
|
|
inline bool isClosed(const Vec2i &pos) { return marker[pos.y * stride + pos.x] == counter + 1; }
|
|
inline bool isListed(const Vec2i &pos) { return marker[pos.y * stride + pos.x] >= counter; } /**< @deprecated not needed? */
|
|
inline void setNeither(const Vec2i &pos){ marker[pos.y * stride + pos.x] = 0; } /**< @deprecated not needed? */
|
|
|
|
inline void set(const Vec2i &pos, AStarNode *ptr) { pArray[pos.y * stride + pos.x] = ptr; } /**< set the pointer for pos to ptr */
|
|
inline AStarNode* get(const Vec2i &pos) { return pArray[pos.y * stride + pos.x]; } /**< get the pointer for pos */
|
|
};
|
|
|
|
private:
|
|
AStarNode *leastH; /**< The 'best' node seen so far this search */
|
|
int numNodes; /**< number of nodes used so far this search */
|
|
int tmpMaxNodes; /**< a temporary maximum number of nodes to use */
|
|
|
|
MarkerArray markerArray; /**< An array the size of the map, indicating node status (unvisited, open, closed) */
|
|
MinHeap<AStarNode> openHeap; /**< the open list, binary heap with index aware nodes */
|
|
|
|
public:
|
|
NodePool(int w, int h);
|
|
~NodePool();
|
|
|
|
// NodeStorage template interface
|
|
//
|
|
void setMaxNodes(const int max);
|
|
void reset();
|
|
|
|
bool isOpen(const Vec2i &pos) { return markerArray.isOpen(pos); } /**< test if a position is open */
|
|
bool isClosed(const Vec2i &pos) { return markerArray.isClosed(pos); } /**< test if a position is closed */
|
|
bool isListed(const Vec2i &pos) { return markerArray.isListed(pos); } /**< @deprecated needed for canPathOut() */
|
|
|
|
bool setOpen(const Vec2i &pos, const Vec2i &prev, float h, float d);
|
|
void updateOpen(const Vec2i &pos, const Vec2i &prev, const float cost);
|
|
|
|
/** get the best candidate from the open list, and close it.
|
|
* @return the lowest estimate node from the open list, or -1,-1 if open list empty */
|
|
Vec2i getBestCandidate() {
|
|
if (openHeap.empty()) {
|
|
return Vec2i(-1);
|
|
}
|
|
AStarNode *ptr = openHeap.extract();
|
|
markerArray.setClosed(ptr->pos());
|
|
return ptr->pos();
|
|
}
|
|
/** get the best heuristic node seen this search */
|
|
Vec2i getBestSeen() { return leastH->pos(); }
|
|
/** get the heuristic of the node at pos [known to be visited] */
|
|
float getHeuristicAt(const Vec2i &pos) { return markerArray.get(pos)->heuristic; }
|
|
/** get the cost to the node at pos [known to be visited] */
|
|
float getCostTo(const Vec2i &pos) { return markerArray.get(pos)->distToHere; }
|
|
/** get the estimate for the node at pos [known to be visited] */
|
|
float getEstimateFor(const Vec2i &pos) { return markerArray.get(pos)->est(); }
|
|
/** get the best path to the node at pos [known to be closed] */
|
|
Vec2i getBestTo(const Vec2i &pos) {
|
|
AStarNode *ptr = markerArray.get(pos);
|
|
assert(ptr);
|
|
return ptr->hasPrev() ? ptr->prev() : Vec2i(-1);
|
|
}
|
|
|
|
private:
|
|
void addOpenNode(AStarNode *node);
|
|
AStarNode* newNode() { return ( counter < size ? &stock[counter++] : NULL ); }
|
|
|
|
#if _GAE_DEBUG_EDITION_
|
|
public:
|
|
// interface to support debugging textures
|
|
list<Vec2i>* getOpenNodes();
|
|
list<Vec2i>* getClosedNodes();
|
|
list<Vec2i> listedNodes;
|
|
#endif
|
|
};
|
|
|
|
}}
|
|
|
|
#endif
|