00001 #ifndef basic_area_NavMesh_hpp 00002 #define basic_area_NavMesh_hpp 00003 00004 #include "BasicPre.hpp" 00005 #include "util/vecmath/Point2.hpp" 00006 #include "util/vecmath/Point3.hpp" 00007 #include "util/bounds/BoundingBox.hpp" 00008 #include "sim/react/AreaEdge.hpp" 00009 00010 00011 namespace se_basic { 00012 00013 /* 00014 bool doLinesIntersectXZ(const se_core::Point3& a0 00015 , const se_core::Point3& a1 00016 , const se_core::Point3& b0 00017 , const se_core::Point3& b1 00018 , se_core::Point2* out); 00019 */ 00020 00021 bool doLinesIntersectXZ(const se_core::Point3& a0 00022 , const se_core::Point3& a1 00023 , const se_core::Point3& b0 00024 , const se_core::Point3& b1); 00025 00026 00027 struct Triangle { 00028 short id_; 00029 short controlPoints_[3]; 00030 short linkTo_[3]; 00031 short linkType_[3]; 00032 short type_; 00033 }; 00034 00035 00036 struct Wall { 00037 short left_; 00038 short right_; 00039 }; 00040 00041 00042 struct Exit { 00043 short triangle_; 00044 short side_; 00045 }; 00046 00047 00048 class _SeBasicExport Path { 00049 public: 00055 Path(int triangleCount, unsigned char* paths = 0) 00056 : triangleCount_(triangleCount) , paths_(paths) { 00057 if(!paths_) { 00058 // 4 values per char so size * size / 4 00059 paths_ = new unsigned char[ dataSize() ]; 00060 } 00061 } 00062 00063 00065 ~Path() {} 00066 00067 00079 void set(short from, short to, int neighbourIndex) { 00080 int index = (from * triangleCount_ + to) >> 2; 00081 int shift = ((from * triangleCount_ + to) & 0x3) * 2; 00082 00083 // Reset existing value 00084 paths_[ index ] &= ~(0x3 << shift); 00085 00086 // Set new value 00087 // assert(neighbourIndex & 0x3 == neighbourIndex) 00088 paths_[ index ] ^= (neighbourIndex << shift); 00089 } 00090 00091 00097 int path(short from, short to) const { 00098 int index = (from * triangleCount_ + to) >> 2; 00099 int shift = ((from * triangleCount_ + to) & 0x3) * 2; 00100 00101 int ret = (paths_[ index ] >> shift) & 0x3; 00102 return ret; 00103 } 00104 00105 00110 int dataSize() { 00111 return (triangleCount_ * triangleCount_ + 3) >> 2; 00112 } 00113 00114 00122 unsigned char* data() { 00123 return paths_; 00124 } 00125 00126 void lineIntersect(const se_core::Point2& p0 00127 , const se_core::Point2& p1 00128 , const se_core::Point2& p2 00129 , const se_core::Point2& p3 00130 , se_core::Point2& out) { 00131 // this function computes the intersection of the sent lines 00132 // and returns the intersection point, note that the function assumes 00133 // the lines intersect. the function can handle vertical as well 00134 // as horizontal lines. note the function isn't very clever, it simply 00135 //applies the math, but we don't need speed since this is a 00136 //pre-processing step 00137 00138 // b1 and b2 unused 00139 float a1, c1, // constants of linear equations 00140 a2, c2, 00141 det_inv, // the inverse of the determinant of the coefficie matrix 00142 m1, m2; // the slopes of each line 00143 00144 // compute slopes, note the cludge for infinity, however, this will 00145 // be close enough 00146 00147 if ((p1.x_ - p0.x_) != 0) 00148 m1 = (p1.y_ - p0.y_) / (p1.x_ - p0.x_); 00149 else 00150 m1 = (float)1e+10; // close enough to infinity 00151 00152 if ((p3.x_ - p2.x_) != 0) 00153 m2 = (p3.y_ - p2.y_) / (p3.x_ - p2.x_); 00154 else 00155 m2 = (float)1e+10; // close enough to infinity 00156 00157 // compute constants 00158 a1 = m1; 00159 a2 = m2; 00160 00161 c1 = (p0.y_ - m1 * p0.x_); 00162 c2 = (p2.y_ - m2 * p2.x_); 00163 00164 // compute the inverse of the determinate 00165 det_inv = 1 / (a2 - a1); 00166 00167 // use Kramers rule to compute xi and yi 00168 out.x_ = ((c1 - c2) * det_inv); 00169 //out.y_ = ((a2 * c1 - a1 * c2) * det_inv); 00170 out.y_ = m1 * ( (c2 - c1) / (m1 - m2) ) + c1; 00171 } // end Intersect_Lines 00172 00173 00174 00175 00176 private: 00177 int triangleCount_; 00178 unsigned char* paths_; 00179 }; 00180 00181 00182 class _SeBasicExport NavMesh { 00183 public: 00184 NavMesh(short controlPointCount, short triangleCount) 00185 : controlPointCount_(controlPointCount) 00186 , triangleCount_(triangleCount) 00187 , exitCount_(0), exits_(0), doDestroy_(true) { 00188 controlPoints_ = new se_core::Point3[ controlPointCount_ ]; 00189 walls_ = new Wall[ controlPointCount_ ]; 00190 triangles_ = new Triangle[ triangleCount_ ]; 00191 paths_ = new Path(triangleCount_); 00192 } 00193 00194 00195 NavMesh(const void* data) : doDestroy_(false) { 00196 union { 00197 const void* v; 00198 //void* v; 00199 unsigned char* ch; 00200 short *sh; 00201 se_core::Point3* cp; 00202 Triangle* tri; 00203 Wall* wall; 00204 Exit* exit; 00205 } offset; 00206 00207 offset.v = data; 00208 00209 controlPointCount_ = *(offset.sh++); 00210 triangleCount_ = *(offset.sh++); 00211 exitCount_ = *(offset.sh++); 00212 00213 controlPoints_ = offset.cp; 00214 offset.cp += controlPointCount_; 00215 00216 walls_ = offset.wall; 00217 offset.wall += controlPointCount_; 00218 00219 triangles_ = offset.tri; 00220 offset.tri += triangleCount_; 00221 00222 exits_ = offset.exit; 00223 offset.exit += exitCount_; 00224 00225 paths_ = new Path(triangleCount_, offset.ch); 00226 offset.ch += paths_->dataSize(); 00227 } 00228 00229 00230 ~NavMesh() { 00231 delete paths_; 00232 if(doDestroy_) { 00233 delete[] triangles_; 00234 delete[] walls_; 00235 delete[] controlPoints_; 00236 } 00237 } 00238 00239 00240 void walls(se_core::AreaEdge& areaEdge) const; 00241 int isInLineOfSight(const se_core::Pos& from, const se_core::Pos& to) const; 00242 int isInLineOfSight(const se_core::Point3& from, short fromIndex, const se_core::Point3& to, short toIndex) const; 00243 int farthestLineOfSightXZ(int fromIndex, const se_core::Point3& from, const se_core::Point3& to, short toIndex, se_core::Point2& dest) const; 00244 bray_t slideAngle(const se_core::Point3& from, short fromIndex, const se_core::Point3& to) const; 00245 bray_t wallAngle(const se_core::Point3& from, short fromIndex, const se_core::Point3& to) const; 00246 bool doesTouchVoid(const se_core::Point3& p, short pIndex, const coor_t radius) const; 00247 00253 short path(short from, short to) const { 00254 int neighbourIndex = paths_->path(from, to); 00255 short via = triangles_[ from ].linkTo_[ neighbourIndex ]; 00256 return via; 00257 } 00258 00259 00260 void center(short tri, se_core::Point3& out) const { 00261 const se_core::Point3& c1 = controlPoints_[ triangles_[tri].controlPoints_[0] ]; 00262 const se_core::Point3& c2 = controlPoints_[ triangles_[tri].controlPoints_[1] ]; 00263 const se_core::Point3& c3 = controlPoints_[ triangles_[tri].controlPoints_[2] ]; 00264 00265 out.x_ = (c1.x_ + c2.x_ + c3.x_) / 3.0f; 00266 out.y_ = (c1.y_ + c2.y_ + c3.y_) / 3.0f; 00267 out.z_ = (c1.z_ + c2.z_ + c3.z_) / 3.0f; 00268 } 00269 00270 00271 short type(short triangle) { 00272 return triangles_[ triangle ].type_; 00273 } 00274 00275 void barycentric(const se_core::Point2& q, const se_core::Point3& c1, const se_core::Point3& c2, const se_core::Point3& c3, se_core::Tuple3& out) const { 00276 coor_t b0 = (c2.x_ - c1.x_) * (c3.z_ - c1.z_) - (c3.x_ - c1.x_) * (c2.z_ - c1.z_); 00277 out.x_ = ((c2.x_ - q.x_) * (c3.z_ - q.y_) - (c3.x_ - q.x_) * (c2.z_ - q.y_)) / b0; 00278 out.y_ = ((c3.x_ - q.x_) * (c1.z_ - q.y_) - (c1.x_ - q.x_) * (c3.z_ - q.y_)) / b0; 00279 out.z_ = 1 - out.x_ - out.y_; 00280 //out.z = ((c1.x_ - q.x_) * (c2.z_ - q.y_) - (c2.x_ - q.x_) * (c1.z_ - q.y_)) / b0; 00281 } 00282 00283 00284 void barycentric(short tri, const se_core::Point2& q, se_core::Tuple3& out) const { 00285 const se_core::Point3& c1 = controlPoints_[ triangles_[tri].controlPoints_[0] ]; 00286 const se_core::Point3& c2 = controlPoints_[ triangles_[tri].controlPoints_[1] ]; 00287 const se_core::Point3& c3 = controlPoints_[ triangles_[tri].controlPoints_[2] ]; 00288 00289 coor_t b0 = (c2.x_ - c1.x_) * (c3.z_ - c1.z_) - (c3.x_ - c1.x_) * (c2.z_ - c1.z_); 00290 out.x_ = ((c2.x_ - q.x_) * (c3.z_ - q.y_) - (c3.x_ - q.x_) * (c2.z_ - q.y_)) / b0; 00291 out.y_ = ((c3.x_ - q.x_) * (c1.z_ - q.y_) - (c1.x_ - q.x_) * (c3.z_ - q.y_)) / b0; 00292 //out.z = ((c1.x_ - q.x_) * (c2.z_ - q.y_) - (c2.x_ - q.x_) * (c1.z_ - q.y_)) / b0; 00293 out.z_ = 1 - out.x_ - out.y_; 00294 } 00295 00296 00297 coor_t height(short tri, const se_core::Tuple3& barycentric) const { 00298 const se_core::Point3& c1 = controlPoints_[ triangles_[tri].controlPoints_[0] ]; 00299 const se_core::Point3& c2 = controlPoints_[ triangles_[tri].controlPoints_[1] ]; 00300 const se_core::Point3& c3 = controlPoints_[ triangles_[tri].controlPoints_[2] ]; 00301 00302 coor_t h = barycentric.x_ * c1.y_ 00303 + barycentric.y_ * c2.y_ 00304 + barycentric.z_ * c3.y_; 00305 00306 return h; 00307 } 00308 00309 00310 bool isInsideTriangle(se_core::Tuple3& barycentric) const { 00311 return (barycentric.x_ >= 0 && barycentric.y_ >= 0 && barycentric.z_ >= 0); 00312 } 00313 00314 00316 bool isInsideTriangle(se_core::Point2& q, se_core::Point3& c1, se_core::Point3& c2, se_core::Point3& c3) const { 00317 se_core::Tuple3 b; 00318 barycentric(q, c1, c2, c3, b); 00319 return isInsideTriangle(b); 00320 } 00321 00322 00324 bool isInsideTriangle(se_core::Point2& q, se_core::Point3* corners) const { 00325 using namespace se_core; 00326 00327 static int index1[] = { 1, 2, 0 }; 00328 static int index2[] = { 2, 0, 1 }; 00329 00330 for(int i = 0; i < 3; ++i) { 00331 Point3& c0 = corners[ i ]; 00332 Point3& c1 = corners[ index1[ i ] ]; 00333 Point3& c2 = corners[ index2[ i ] ]; 00334 00335 Vector2 n(-(c1.z_ - c0.z_), c1.x_ - c0.x_); 00336 Vector2 F(c2.x_ - c0.x_, c2.z_ - c0.z_); 00337 Vector2 G(q.x_ - c0.x_, q.y_ - c0.z_); 00338 00339 if(n.dot(F) * n.dot(G) < 0) 00340 return false; 00341 } 00342 return true; 00343 } 00344 00345 00348 short find(const se_core::Point2& q) const { 00349 // TODO: Should organize triangles in a tree or grid structure 00350 se_core::Tuple3 b; 00351 for(int i = 0; i < triangleCount_; ++i) { 00352 barycentric(i, q, b); 00353 if(isInsideTriangle(b)) { 00354 return i; 00355 } 00356 } 00357 //LogDetail(q.x_ << ", " << q.y_); 00358 return -1; 00359 } 00360 00361 00364 short find(short from, const se_core::Point2& q) const { 00365 Assert(from >= 0); 00366 short count = 0; 00367 00368 se_core::Tuple3 b; 00369 00370 short tri = from; 00371 barycentric(tri, q, b); 00372 while(!isInsideTriangle(b)) { 00373 if(++count > 20) { 00374 return find(q); 00375 } 00376 short n = 0; 00377 coor_t smallest = b.x_; 00378 00379 if(b.y_ < smallest) { 00380 n = 1; 00381 smallest = b.y_; 00382 } 00383 if(b.z_ < smallest) { 00384 n = 2; 00385 smallest = b.z_; 00386 } 00387 00388 //LogDetail(tri << ": " << n << " (" << b.x_ << ", " << b.y_ << ", " << b.z_ << ") "); 00389 //for(int c = 0; c < 3; ++c) { 00390 // int i = triangles_[ tri ].controlPoints_[ c ]; 00391 //LogDetail(" " << i << ": " << controlPoints_[ i ].x_ << ", " << controlPoints_[ i ].z_ ); 00392 //} 00393 00394 //LogDetail(" Link: " << triangles_[tri].linkTo_[0] << ", " << triangles_[tri].linkTo_[1] << ", " << triangles_[tri].linkTo_[2]); 00395 tri = triangles_[tri].linkTo_[n]; 00396 if(tri < 0) { 00397 return -1; 00398 } 00399 barycentric(tri, q, b); 00400 } 00401 return tri; 00402 } 00403 00404 short findExit(const se_core::BoundingBox& bounds, se_core::Point3& out) const; 00405 coor_t findNearest(const se_core::Point3& p, se_core::Point3& out) const; 00406 00407 protected: 00408 bool doDestroy_; 00409 short controlPointCount_; 00410 short triangleCount_; 00411 short exitCount_; 00412 00413 se_core::Point3* controlPoints_; 00414 Triangle* triangles_; 00415 Path* paths_; 00416 Wall* walls_; 00417 Exit* exits_; 00418 }; 00419 00420 } 00421 00422 00423 #endif
Home Page | SagaEngine trunk (updated nightly) reference generated Sun Dec 2 20:06:02 2007 by Doxygen version 1.3.9.1.