aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/bladerunner/actor_walk.cpp2
-rw-r--r--engines/bladerunner/obstacles.cpp221
-rw-r--r--engines/bladerunner/obstacles.h14
-rw-r--r--engines/bladerunner/vector.h4
4 files changed, 215 insertions, 26 deletions
diff --git a/engines/bladerunner/actor_walk.cpp b/engines/bladerunner/actor_walk.cpp
index e8d90fb5b7..985c92fb8d 100644
--- a/engines/bladerunner/actor_walk.cpp
+++ b/engines/bladerunner/actor_walk.cpp
@@ -422,7 +422,7 @@ int ActorWalk::nextOnPath(int actorId, const Vector3 &from, const Vector3 &to, V
return 0;
}
Vector3 next1;
- if (_vm->_obstacles->find(from, to, &next1)) {
+ if (_vm->_obstacles->findNextWaypoint(from, to, &next1)) {
next = next1;
return 1;
}
diff --git a/engines/bladerunner/obstacles.cpp b/engines/bladerunner/obstacles.cpp
index e4deaba6fa..73b3681209 100644
--- a/engines/bladerunner/obstacles.cpp
+++ b/engines/bladerunner/obstacles.cpp
@@ -24,8 +24,10 @@
#include "bladerunner/bladerunner.h"
+#include "bladerunner/actor.h"
#include "bladerunner/savefile.h"
#include "bladerunner/scene.h" // for debug
+#include "bladerunner/set.h"
#include "bladerunner/view.h"
#include "common/debug.h"
@@ -38,7 +40,7 @@ Obstacles::Obstacles(BladeRunnerEngine *vm) {
_vm = vm;
_polygons = new Polygon[kPolygonCount];
_polygonsBackup = new Polygon[kPolygonCount];
- _vertices = new Vector2[kVertexCount];
+ _path = new Vector2[kVertexCount];
clear();
}
@@ -51,8 +53,8 @@ Obstacles::~Obstacles() {
delete[] _polygonsBackup;
_polygonsBackup = nullptr;
- delete[] _vertices;
- _vertices = nullptr;
+ delete[] _path;
+ _path = nullptr;
}
void Obstacles::clear() {
@@ -64,7 +66,7 @@ void Obstacles::clear() {
_polygons[i].vertices[j].y = 0.0f;
}
}
- _verticeCount = 0;
+ _pathSize = 0;
_backup = false;
_count = 0;
}
@@ -212,8 +214,6 @@ bool Obstacles::mergePolygons(Polygon &polyA, Polygon &polyB) {
if (linePolygonIntersection(polyLine, polyPrimaryType, polySecondary, &intersectionPoint, &polySecondaryIntersectionIndex)) {
if (WITHIN_TOLERANCE(intersectionPoint.x, polyLine.start.x) && WITHIN_TOLERANCE(intersectionPoint.y, polyLine.start.y)) {
- warning("Set: %d Scene: %d", _vm->_scene->getSetId(), _vm->_scene->getSceneId());
- warning("Report instances of this to madmoose!");
flagAddVertexToVertexList = false;
polyMerged.verticeCount--; // TODO(madmoose): How would this work?
} else {
@@ -315,9 +315,115 @@ float Obstacles::getLength(float x0, float z0, float x1, float z1) {
return fabs(x1 - x0);
}
-bool Obstacles::find(const Vector3 &from, const Vector3 &to, Vector3 *next) const {
- //TODO
- *next = to;
+bool Obstacles::findNextWaypoint(const Vector3 &from, const Vector3 &to, Vector3 *next) {
+ static int recursionLevel = 0;
+ static bool polygonVisited[kPolygonCount];
+
+ if (++recursionLevel == 1) {
+ clearPath();
+ for (int i = 0; i != kPolygonCount; ++i) {
+ polygonVisited[i] = false;
+ }
+ }
+
+ int polyIndex = -1;
+ int polyNearVertIndex;
+ float polyNearDist = 0.0f;
+ Vector2 polyNearPos;
+ int polyFarVertIndex;
+ float polyFarDist = 0.0f;
+ Vector2 polyFarPos;
+
+ for (int i = 0; i != kPolygonCount; ++i) {
+ Polygon &poly = _polygons[i];
+ if (!poly.isPresent || polygonVisited[i]) {
+ continue;
+ }
+
+ int nearVertIndex;
+ float nearDist;
+ Vector2 nearPos;
+
+ if (!findIntersectionNearest(i, from.xz(), to.xz(), &nearVertIndex, &nearDist, &nearPos)) {
+ continue;
+ }
+
+ int farVertIndex;
+ float farDist;
+ Vector2 farPos;
+
+ int hasFar = findIntersectionFarthest(i, from.xz(), to.xz(), &farVertIndex, &farDist, &farPos);
+ assert(hasFar);
+
+ if (polyIndex == -1 || nearDist < polyNearDist) {
+ polyNearDist = nearDist;
+ polyNearPos = nearPos;
+ polyFarDist = farDist;
+ polyFarPos = farPos;
+ polyIndex = i;
+ polyNearVertIndex = nearVertIndex;
+ polyFarVertIndex = farVertIndex;
+ }
+ }
+
+ if (polyIndex < 0) {
+ assert(_pathSize < kVertexCount);
+ _path[_pathSize++] = to.xz();
+ } else {
+ polygonVisited[polyIndex] = true;
+
+ if (polyNearDist == 0.0f && polyFarDist == 0.0f) {
+ assert(_pathSize < kVertexCount);
+ _path[_pathSize++] = polyNearPos;
+ } else {
+ Vector2 pathA[kMaxPathSize];
+ Vector2 pathB[kMaxPathSize];
+
+ bool pathABlocked;
+ bool pathBBlocked;
+
+ int pathASize = buildNegativePath(polyIndex, polyNearVertIndex, polyNearPos, polyFarVertIndex, polyFarPos, pathA, kMaxPathSize, &pathABlocked);
+ int pathBSize = buildPositivePath(polyIndex, polyNearVertIndex, polyNearPos, polyFarVertIndex, polyFarPos, pathB, kMaxPathSize, &pathBBlocked);
+
+ float pathATotalDistance = pathTotalDistance(pathA, pathASize, from.xz(), to.xz());
+ float pathBTotalDistance = pathTotalDistance(pathB, pathBSize, from.xz(), to.xz());
+
+ bool usePathA;
+ if (pathABlocked && !pathBBlocked) {
+ usePathA = false;
+ } else if (pathBBlocked && !pathABlocked) {
+ usePathA = true;
+ } else {
+ usePathA = pathATotalDistance <= pathBTotalDistance;
+ }
+
+ if (usePathA) {
+ assert(_pathSize + pathASize < kVertexCount);
+ for (int i = 0; i != pathASize; ++i) {
+ _path[_pathSize + i] = pathA[i];
+ }
+ _pathSize += pathASize;
+ } else {
+ assert(_pathSize + pathBSize < kVertexCount);
+ for (int i = 0; i != pathBSize; ++i) {
+ _path[_pathSize + i] = pathB[i];
+ }
+ _pathSize += pathBSize;
+ }
+ }
+ assert(_pathSize > 0);
+ Vector3 lastPathPos(_path[_pathSize - 1].x, from.y, _path[_pathSize - 1].y);
+ findNextWaypoint(lastPathPos, to, next);
+ }
+
+ if (--recursionLevel > 1) {
+ return false;
+ }
+
+ // TODO(tmf)
+ // postProcessPath(_path, _pathSize, &next);
+
+ *next = Vector3(_path[0].x, from.y, _path[0].y);
return true;
}
@@ -385,6 +491,16 @@ bool Obstacles::findIntersectionFarthest(int polygonIndex, Vector2 from, Vector2
return maxVertexIndex != -1;
}
+float Obstacles::pathTotalDistance(const Vector2 *path, int pathSize, Vector2 from, Vector2 to) const {
+ // Yes, 'to' and 'from' are ignored.
+ float totalDistance = 0.0f;
+ for (int i = 0; i != pathSize - 1; ++i) {
+ totalDistance += distance(path[i], path[i+1]);
+ }
+ return totalDistance;
+}
+
+
bool Obstacles::findPolygonVerticeByXZ(int *polygonIndex, int *verticeIndex, int *verticeCount, float x, float z) const {
*polygonIndex = -1;
*verticeIndex = -1;
@@ -431,16 +547,82 @@ bool Obstacles::findPolygonVerticeByXZWithinTolerance(float x, float z, int *pol
return false;
}
-void Obstacles::clearVertices() {
- _verticeCount = 0;
+void Obstacles::clearPath() {
+ _pathSize = 0;
}
-void Obstacles::copyVerticesReverse() {
+int Obstacles::buildNegativePath(int polyIndex, int vertStartIndex, Vector2 startPos, int vertEndIndex, Vector2 endPos, Vector2 *path, int pathCapacity, bool *pathBlocked) {
+ int pathSize = 0;
+ *pathBlocked = false;
+ Polygon *poly = &_polygons[polyIndex];
+
+ /* Add start position to path */
+ if (_vm->_scene->_set->findWalkbox(startPos.x, startPos.y) == -1) {
+ *pathBlocked = true;
+ }
+ assert(pathSize < pathCapacity);
+ path[pathSize++] = startPos;
+
+#define DEC_WRAP(x) (((x) + poly->verticeCount - 1) % poly->verticeCount)
+
+ /* Add polygon vertices in negative iteration order */
+ for (int i = vertStartIndex; i != vertEndIndex; i = DEC_WRAP(i)) {
+ Vector2 v = poly->vertices[i];
+ if (_vm->_scene->_set->findWalkbox(v.x, v.y) == -1) {
+ *pathBlocked = true;
+ }
+
+ assert(pathSize < pathCapacity);
+ path[pathSize++] = v;
+ }
+
+#undef DEC_WRAP
+
+ /* Add end position to path */
+ if (_vm->_scene->_set->findWalkbox(endPos.x, endPos.y) == -1) {
+ *pathBlocked = true;
+ }
+ assert(pathSize < pathCapacity);
+ path[pathSize++] = endPos;
+ return pathSize;
}
-void Obstacles::copyVertices() {
+int Obstacles::buildPositivePath(int polyIndex, int vertStartIndex, Vector2 startPos, int vertEndIndex, Vector2 endPos, Vector2 *path, int pathCapacity, bool *pathBlocked) {
+ int pathSize = 0;
+ *pathBlocked = false;
+ Polygon *poly = &_polygons[polyIndex];
+
+ /* Add start position to path */
+ if (_vm->_scene->_set->findWalkbox(startPos.x, startPos.y) == -1) {
+ *pathBlocked = true;
+ }
+ assert(pathSize < pathCapacity);
+ path[pathSize++] = startPos;
+
+#define INC_WRAP(x) (((x) + 1) % poly->verticeCount)
+
+ /* Add polygon vertices in positive iteration order */
+ for (int i = INC_WRAP(vertStartIndex); i != vertEndIndex; i = INC_WRAP(i)) {
+ Vector2 v = poly->vertices[i];
+ if (_vm->_scene->_set->findWalkbox(v.x, v.y) == -1) {
+ *pathBlocked = true;
+ }
+
+ assert(pathSize < pathCapacity);
+ path[pathSize++] = v;
+ }
+
+#undef INC_WRAP
+
+ /* Add end position to path */
+ if (_vm->_scene->_set->findWalkbox(endPos.x, endPos.y) == -1) {
+ *pathBlocked = true;
+ }
+ assert(pathSize < pathCapacity);
+ path[pathSize++] = endPos;
+ return pathSize;
}
void Obstacles::backup() {
@@ -492,9 +674,9 @@ void Obstacles::save(SaveFileWriteStream &f) {
}
}
for (int i = 0; i < kVertexCount; ++i) {
- f.writeVector2(_vertices[i]);
+ f.writeVector2(_path[i]);
}
- f.writeInt(_verticeCount);
+ f.writeInt(_pathSize);
}
void Obstacles::load(SaveFileReadStream &f) {
@@ -528,12 +710,13 @@ void Obstacles::load(SaveFileReadStream &f) {
}
for (int i = 0; i < kVertexCount; ++i) {
- _vertices[i] = f.readVector2();
+ _path[i] = f.readVector2();
}
- _verticeCount = f.readInt();
+ _pathSize = f.readInt();
}
void Obstacles::draw() {
+ float floor = _vm->_playerActor->getY();
for (int i = 0; i != kPolygonCount; ++i) {
if (!_polygons[i].isPresent) {
continue;
@@ -541,14 +724,14 @@ void Obstacles::draw() {
Vector3 p0 = _vm->_view->calculateScreenPosition(Vector3(
_polygons[i].vertices[_polygons[i].verticeCount - 1].x,
- 0,
+ floor,
_polygons[i].vertices[_polygons[i].verticeCount - 1].y
));
for (int j = 0; j != _polygons[i].verticeCount; ++j) {
Vector3 p1 = _vm->_view->calculateScreenPosition(Vector3(
_polygons[i].vertices[j].x,
- 0.0f,
+ floor,
_polygons[i].vertices[j].y
));
diff --git a/engines/bladerunner/obstacles.h b/engines/bladerunner/obstacles.h
index f133fe05ff..c05a453002 100644
--- a/engines/bladerunner/obstacles.h
+++ b/engines/bladerunner/obstacles.h
@@ -36,6 +36,7 @@ class Obstacles {
static const int kVertexCount = 150;
static const int kPolygonCount = 50;
static const int kPolygonVertexCount = 160;
+ static const int kMaxPathSize = 500;
enum VertexType {
BOTTOM_LEFT,
@@ -64,8 +65,8 @@ class Obstacles {
Polygon *_polygons;
Polygon *_polygonsBackup;
- Vector2 *_vertices;
- int _verticeCount;
+ Vector2 *_path;
+ int _pathSize;
int _count;
bool _backup;
@@ -83,19 +84,20 @@ public:
void add(float x0, float z0, float x1, float z1) { add(RectFloat(x0, z0, x1, z1)); }
int findEmptyPolygon() const;
static float getLength(float x0, float z0, float x1, float z1);
- bool find(const Vector3 &from, const Vector3 &to, Vector3 *next) const;
+ bool findNextWaypoint(const Vector3 &from, const Vector3 &to, Vector3 *next);
bool findIntersectionNearest(int polygonIndex, Vector2 from, Vector2 to,
int *outVertexIndex, float *outDistance, Vector2 *out) const;
bool findIntersectionFarthest(int polygonIndex, Vector2 from, Vector2 to,
int *outVertexIndex, float *outDistance, Vector2 *out) const;
+ float pathTotalDistance(const Vector2 *path, int pathSize, Vector2 from, Vector2 to) const;
bool findPolygonVerticeByXZ(int *polygonIndex, int *verticeIndex, int *verticeCount, float x, float z) const;
bool findPolygonVerticeByXZWithinTolerance(float x, float z, int *polygonIndex, int *verticeIndex) const;
- void clearVertices();
- void copyVerticesReverse();
- void copyVertices();
+ void clearPath();
+ int buildNegativePath(int polyIndex, int vertStartIndex, Vector2 startPos, int vertEndIndex, Vector2 endPos, Vector2 *path, int pathCapacity, bool *pathBlocked);
+ int buildPositivePath(int polyIndex, int vertStartIndex, Vector2 startPos, int vertEndIndex, Vector2 endPos, Vector2 *path, int pathCapacity, bool *pathBlocked);
void backup();
void restore();
diff --git a/engines/bladerunner/vector.h b/engines/bladerunner/vector.h
index f6670c23f0..d5d6365a81 100644
--- a/engines/bladerunner/vector.h
+++ b/engines/bladerunner/vector.h
@@ -70,6 +70,10 @@ public:
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x);
}
+
+ Vector2 xz() const {
+ return Vector2(x, z);
+ }
};
inline Vector3 operator+(Vector3 a, Vector3 b) {