ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

floor.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/resources/floor.h"
00024 
00025 #include "engines/stark/formats/xrc.h"
00026 
00027 #include "engines/stark/resources/floorface.h"
00028 #include "engines/stark/resources/floorfield.h"
00029 
00030 #include "engines/stark/services/stateprovider.h"
00031 
00032 #include "common/math.h"
00033 
00034 namespace Stark {
00035 namespace Resources {
00036 
00037 Floor::Floor(Object *parent, byte subType, uint16 index, const Common::String &name) :
00038         Object(parent, subType, index, name),
00039         _facesCount(0) {
00040     _type = TYPE;
00041 }
00042 
00043 Floor::~Floor() {
00044 }
00045 
00046 Math::Vector3d Floor::getVertex(uint32 index) const {
00047     return _vertices[index];
00048 }
00049 
00050 int32 Floor::findFaceContainingPoint(const Math::Vector3d &point) const {
00051     for (uint32 i = 0; i < _faces.size(); i++) {
00052         if (_faces[i]->hasVertices() && _faces[i]->isPointInside(point)) {
00053             return i;
00054         }
00055     }
00056 
00057     return -1;
00058 }
00059 
00060 void Floor::computePointHeightInFace(Math::Vector3d &point, uint32 faceIndex) const {
00061     _faces[faceIndex]->computePointHeight(point);
00062 }
00063 
00064 int32 Floor::findFaceHitByRay(const Math::Ray &ray, Math::Vector3d &intersection) const {
00065     for (uint32 i = 0; i < _faces.size(); i++) {
00066         // TODO: Check the ray's intersection with an AABB first if this ends up being slow
00067         if (_faces[i]->intersectRay(ray, intersection)) {
00068             if (_faces[i]->isEnabled()) {
00069                 return i;
00070             } else {
00071                 return -1; // Disabled faces block the ray
00072             }
00073         }
00074     }
00075 
00076     return -1;
00077 }
00078 
00079 int32 Floor::findFaceClosestToRay(const Math::Ray &ray, Math::Vector3d &center) const {
00080     float minDistance = FLT_MAX;
00081     int32 minFace = -1;
00082 
00083     // For some reason, face 0 is not being considered
00084     for (uint32 i = 1; i < _faces.size(); i++) {
00085         if (_faces[i]->isEnabled() && _faces[i]->hasVertices()) {
00086             float distance = _faces[i]->distanceToRay(ray);
00087             if (distance < minDistance) {
00088                 minFace = i;
00089                 minDistance = distance;
00090             }
00091         }
00092     }
00093 
00094     if (minFace >= 0) {
00095         center = _faces[minFace]->getCenter();
00096     }
00097 
00098     return minFace;
00099 }
00100 
00101 float Floor::getDistanceFromCamera(uint32 faceIndex) const {
00102     FloorFace *face = _faces[faceIndex];
00103     return face->getDistanceFromCamera();
00104 }
00105 
00106 FloorFace *Floor::getFace(uint32 index) const {
00107     return _faces[index];
00108 }
00109 
00110 bool Floor::isSegmentInside(const Math::Line3d &segment) const {
00111     // The segment is inside the floor if at least one of its extremities is,
00112     // and it does not cross any floor border / disabled floor faces
00113 
00114     int32 beginFace = findFaceContainingPoint(segment.begin());
00115     if (beginFace < 0) {
00116         // The segment begin point is not on the floor
00117         return false;
00118     }
00119 
00120     if (!_faces[beginFace]->isEnabled()) {
00121         // The segment begin point is not enabled
00122         return false;
00123     }
00124 
00125     for (uint i = 0; i < _edges.size(); i++) {
00126         const FloorEdge &edge = _edges[i];
00127         if ((edge.isFloorBorder() || !edge.isEnabled()) && edge.intersectsSegment(this, segment)) {
00128             return false;
00129         }
00130     }
00131 
00132     return true;
00133 }
00134 
00135 void Floor::readData(Formats::XRCReadStream *stream) {
00136     _facesCount = stream->readUint32LE();
00137     uint32 vertexCount = stream->readUint32LE();
00138 
00139     for (uint i = 0; i < vertexCount; i++) {
00140         Math::Vector3d v = stream->readVector3();
00141         _vertices.push_back(v);
00142     }
00143 }
00144 
00145 void Floor::onAllLoaded() {
00146     Object::onAllLoaded();
00147 
00148     _faces = listChildren<FloorFace>();
00149 
00150     buildEdgeList();
00151 }
00152 
00153 void Floor::saveLoad(ResourceSerializer *serializer) {
00154     for (uint i = 0; i < _edges.size(); i++) {
00155         _edges[i].saveLoad(serializer);
00156     }
00157 }
00158 
00159 void Floor::buildEdgeList() {
00160     _edges.clear();
00161 
00162     // Add the triangle edges from all our faces
00163     for (uint i = 0; i < _faces.size(); i++) {
00164         if (_faces[i]->hasVertices()) {
00165             addFaceEdgeToList(i, 2, 0);
00166             addFaceEdgeToList(i, 0, 1);
00167             addFaceEdgeToList(i, 1, 2);
00168         }
00169     }
00170 
00171     // Add the edges to their faces
00172     for (uint i = 0; i < _edges.size(); i++) {
00173         int32 faceIndex1 = _edges[i].getFaceIndex1();
00174         int32 faceIndex2 = _edges[i].getFaceIndex2();
00175 
00176         if (faceIndex1 >= 0) {
00177             _faces[faceIndex1]->addEdge(&_edges[i]);
00178         }
00179 
00180         if (faceIndex2 >= 0) {
00181             _faces[faceIndex2]->addEdge(&_edges[i]);
00182         }
00183     }
00184 
00185     // Build a list of neighbours for each edge
00186     for (uint i = 0; i < _edges.size(); i++) {
00187         _edges[i].buildNeighbours(this);
00188         _edges[i].computeMiddle(this);
00189     }
00190 }
00191 
00192 void Floor::addFaceEdgeToList(uint32 faceIndex, uint32 index1, uint32 index2) {
00193     uint32 vertexIndex1 = _faces[faceIndex]->getVertexIndex(index1);
00194     uint32 vertexIndex2 = _faces[faceIndex]->getVertexIndex(index2);
00195     uint32 startIndex = MIN(vertexIndex1, vertexIndex2);
00196     uint32 endIndex = MAX(vertexIndex1, vertexIndex2);
00197 
00198     // Check if we already have an edge with the same vertices
00199     for (uint i = 0; i < _edges.size(); i++) {
00200         if (_edges[i].hasVertices(startIndex, endIndex)) {
00201             _edges[i].setOtherFace(faceIndex);
00202             return;
00203         }
00204     }
00205 
00206     _edges.push_back(FloorEdge(startIndex, endIndex, faceIndex));
00207 }
00208 
00209 void Floor::enableFloorField(FloorField *floorfield, bool enable) {
00210     for (uint i = 0; i < _faces.size(); i++) {
00211         if (floorfield->hasFace(i)) {
00212             _faces[i]->enable(enable);
00213         }
00214     }
00215 }
00216 
00217 void Floor::printData() {
00218     debug("face count: %d", _facesCount);
00219 
00220     Common::Debug debug = streamDbg();
00221     for (uint i = 0; i < _vertices.size(); i++) {
00222         debug << i << ": " << _vertices[i] << "\n";
00223     }
00224 }
00225 
00226 FloorEdge::FloorEdge(uint16 vertexIndex1, uint16 vertexIndex2, uint32 faceIndex1) :
00227         _vertexIndex1(vertexIndex1),
00228         _vertexIndex2(vertexIndex2),
00229         _faceIndex1(faceIndex1),
00230         _faceIndex2(-1),
00231         _enabled(true) {
00232 }
00233 
00234 bool FloorEdge::hasVertices(uint16 vertexIndex1, uint16 vertexIndex2) const {
00235     return _vertexIndex1 == vertexIndex1 && _vertexIndex2 == vertexIndex2;
00236 }
00237 
00238 void FloorEdge::setOtherFace(uint32 faceIndex) {
00239     _faceIndex2 = faceIndex;
00240 }
00241 
00242 Common::Array<FloorEdge *> FloorEdge::getNeighbours() const {
00243     return _neighbours;
00244 }
00245 
00246 float FloorEdge::costTo(const FloorEdge *other) const {
00247     return _middle.getDistanceTo(other->_middle);
00248 }
00249 
00250 Math::Vector3d FloorEdge::getPosition() const {
00251     return _middle;
00252 }
00253 
00254 void FloorEdge::buildNeighbours(const Floor *floor) {
00255     _neighbours.clear();
00256 
00257     if (_faceIndex1 >= 0) {
00258         addNeighboursFromFace(floor->getFace(_faceIndex1));
00259     }
00260 
00261     if (_faceIndex2 >= 0) {
00262         addNeighboursFromFace(floor->getFace(_faceIndex2));
00263     }
00264 }
00265 
00266 void FloorEdge::addNeighboursFromFace(const FloorFace *face) {
00267     Common::Array<FloorEdge *> faceEdges = face->getEdges();
00268     for (uint i = 0; i < faceEdges.size(); i++) {
00269         if (faceEdges[i] != this) {
00270             _neighbours.push_back(faceEdges[i]);
00271         }
00272     }
00273 }
00274 
00275 void FloorEdge::computeMiddle(const Floor *floor) {
00276     Math::Vector3d vertex1 = floor->getVertex(_vertexIndex1);
00277     Math::Vector3d vertex2 = floor->getVertex(_vertexIndex2);
00278     _middle = (vertex1 + vertex2) / 2.0;
00279 }
00280 
00281 int32 FloorEdge::getFaceIndex1() const {
00282     return _faceIndex1;
00283 }
00284 
00285 int32 FloorEdge::getFaceIndex2() const {
00286     return _faceIndex2;
00287 }
00288 
00289 bool FloorEdge::isFloorBorder() const {
00290     return _faceIndex2 == -1;
00291 }
00292 
00293 bool FloorEdge::intersectLine2d(const Math::Line3d &s1, const Math::Line3d &s2) {
00294     const Math::Vector3d &s1begin = s1.begin();
00295     const Math::Vector3d &s1end = s1.end();
00296     const Math::Vector3d &s2begin = s2.begin();
00297     const Math::Vector3d &s2end = s2.end();
00298 
00299     float denom = ((s2end.y() - s2begin.y()) * (s1end.x() - s1begin.x())) -
00300                   ((s2end.x() - s2begin.x()) * (s1end.y() - s1begin.y()));
00301 
00302     float nume_a = ((s2end.x() - s2begin.x()) * (s1begin.y() - s2begin.y())) -
00303                    ((s2end.y() - s2begin.y()) * (s1begin.x() - s2begin.x()));
00304 
00305     float nume_b = ((s1end.x() - s1begin.x()) * (s1begin.y() - s2begin.y())) -
00306                    ((s1end.y() - s1begin.y()) * (s1begin.x() - s2begin.x()));
00307 
00308     if (denom == 0.0f) {
00309         return false; // Segments are collinear
00310     }
00311 
00312     float ua = nume_a / denom;
00313     float ub = nume_b / denom;
00314 
00315     // Non inclusive bounds check, one of the vertices of one segment being inside
00316     // the other segment is not considered to be an intersection.
00317     // This is the only difference with Line3d::intersectLine2d.
00318     return ua > 0 && ua < 1 && ub > 0 && ub < 1;
00319 }
00320 
00321 bool FloorEdge::intersectsSegment(const Floor *floor, const Math::Line3d &segment) const {
00322     Math::Vector3d vertex1 = floor->getVertex(_vertexIndex1);
00323     Math::Vector3d vertex2 = floor->getVertex(_vertexIndex2);
00324     Math::Line3d edgeSegment = Math::Line3d(vertex1, vertex2);
00325 
00326     return intersectLine2d(edgeSegment, segment);
00327 }
00328 
00329 void FloorEdge::enable(bool e) {
00330     _enabled = e;
00331 }
00332 
00333 bool FloorEdge::isEnabled() const {
00334     return _enabled;
00335 }
00336 
00337 void FloorEdge::saveLoad(ResourceSerializer *serializer) {
00338     serializer->syncAsUint32LE(_enabled);
00339 }
00340 
00341 } // End of namespace Resources
00342 } // End of namespace Stark


Generated on Sat Dec 14 2019 05:00:44 for ResidualVM by doxygen 1.7.1
curved edge   curved edge