/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "common/std/queue.h" #include "common/std/vector.h" #include "common/std/algorithm.h" #include "common/std/functional.h" #include "common/std/xutility.h" // Not all platforms define INFINITY #ifndef INFINITY #define INFINITY ((float)(1e+300 * 1e+300)) // This must overflow #endif namespace AGS3 { // TODO: this could be cleaned up/simplified ... // further optimizations possible: // - forward refinement should use binary search class Navigation { public: Navigation(); void Resize(int width, int height); enum NavResult { // unreachable NAV_UNREACHABLE, // straight line exists NAV_STRAIGHT, // path used NAV_PATH }; // ncpath = navpoint-compressed path // opath = path composed of individual grid elements NavResult NavigateRefined(int sx, int sy, int ex, int ey, std::vector &opath, std::vector &ncpath); NavResult Navigate(int sx, int sy, int ex, int ey, std::vector &opath); bool TraceLine(int srcx, int srcy, int targx, int targy, int &lastValidX, int &lastValidY) const; bool TraceLine(int srcx, int srcy, int targx, int targy, std::vector *rpath = nullptr) const; inline void SetMapRow(int y, const unsigned char *row) { map[y] = row; } static int PackSquare(int x, int y); static void UnpackSquare(int sq, int &x, int &y); private: // priority queue entry struct Entry { float cost; int index; inline Entry() {} inline Entry(float ncost, int nindex) : cost(ncost) , index(nindex) { } inline bool operator <(const Entry &b) const { return cost < b.cost; } inline bool operator >(const Entry &b) const { return cost > b.cost; } }; int mapWidth; int mapHeight; std::vector map; typedef unsigned short tFrameId; typedef int tPrev; struct NodeInfo { // quantized min distance from origin unsigned short dist; // frame id (counter to detect new search) tFrameId frameId; // previous node index (packed, relative to current node) tPrev prev; inline NodeInfo() : dist(0) , frameId(0) , prev(-1) { } }; static const float DIST_SCALE_PACK; static const float DIST_SCALE_UNPACK; std::vector mapNodes; tFrameId frameId; std::priority_queue, Common::Greater > pq; // temporary buffers: mutable std::vector fpath; std::vector ncpathIndex; std::vector rayPath, orayPath; // temps for routing towards unreachable areas int cnode; int closest; // orthogonal only (this should correspond to what AGS is doing) bool nodiag; bool navLock; void IncFrameId(); // outside map test inline bool Outside(int x, int y) const; // stronger inside test bool Passable(int x, int y) const; // plain access, unchecked inline bool Walkable(int x, int y) const; void AddPruned(int *buf, int &bcount, int x, int y) const; bool HasForcedNeighbor(int x, int y, int dx, int dy) const; int FindJump(int x, int y, int dx, int dy, int ex, int ey); int FindOrthoJump(int x, int y, int dx, int dy, int ex, int ey); // neighbor reachable (nodiag only) bool Reachable(int x0, int y0, int x1, int y1) const; static inline int sign(int n) { return n < 0 ? -1 : (n > 0 ? 1 : 0); } static inline int iabs(int n) { return n < 0 ? -n : n; } static inline int iclamp(int v, int min, int max) { return v < min ? min : (v > max ? max : v); } static inline int ClosestDist(int dx, int dy) { return dx * dx + dy * dy; // Manhattan? //return iabs(dx) + iabs(dy); } }; inline int Navigation::PackSquare(int x, int y) { return (y << 16) + x; } inline void Navigation::UnpackSquare(int sq, int &x, int &y) { y = sq >> 16; x = sq & ((1 << 16) - 1); } inline bool Navigation::Outside(int x, int y) const { return (unsigned)x >= (unsigned)mapWidth || (unsigned)y >= (unsigned)mapHeight; } inline bool Navigation::Walkable(int x, int y) const { // invert condition because of AGS return map[y][x] != 0; } } // namespace AGS3