polytope.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "math/mMath.h"
  24. #include "collision/collision.h"
  25. #include "collision/polytope.h"
  26. //----------------------------------------------------------------------------
  27. Polytope::Polytope()
  28. {
  29. VECTOR_SET_ASSOCIATION(mEdgeList);
  30. VECTOR_SET_ASSOCIATION(mFaceList);
  31. VECTOR_SET_ASSOCIATION(mVertexList);
  32. VECTOR_SET_ASSOCIATION(mVolumeList);
  33. mVertexList.reserve(100);
  34. mFaceList.reserve(200);
  35. mEdgeList.reserve(100);
  36. mVolumeList.reserve(20);
  37. sideCount = 0;
  38. }
  39. //----------------------------------------------------------------------------
  40. // Box should be axis aligned in the transform space provided.
  41. void Polytope::buildBox(const MatrixF& transform,const Box3F& box)
  42. {
  43. // Box is assumed to be axis aligned in the source space.
  44. // Transform into geometry space
  45. Point3F xvec,yvec,zvec,min;
  46. transform.getColumn(0,&xvec);
  47. xvec *= box.len_x();
  48. transform.getColumn(1,&yvec);
  49. yvec *= box.len_y();
  50. transform.getColumn(2,&zvec);
  51. zvec *= box.len_z();
  52. transform.mulP(box.minExtents,&min);
  53. // Initial vertices
  54. mVertexList.setSize(8);
  55. mVertexList[0].point = min;
  56. mVertexList[1].point = min + yvec;
  57. mVertexList[2].point = min + xvec + yvec;
  58. mVertexList[3].point = min + xvec;
  59. mVertexList[4].point = mVertexList[0].point + zvec;
  60. mVertexList[5].point = mVertexList[1].point + zvec;
  61. mVertexList[6].point = mVertexList[2].point + zvec;
  62. mVertexList[7].point = mVertexList[3].point + zvec;
  63. S32 i;
  64. for (i = 0; i < 8; i++)
  65. mVertexList[i].side = 0;
  66. // Initial faces
  67. mFaceList.setSize(6);
  68. for (S32 f = 0; f < 6; f++) {
  69. Face& face = mFaceList[f];
  70. face.original = true;
  71. face.vertex = 0;
  72. }
  73. mFaceList[0].plane.set(mVertexList[0].point,xvec);
  74. mFaceList[0].plane.invert();
  75. mFaceList[1].plane.set(mVertexList[2].point,yvec);
  76. mFaceList[2].plane.set(mVertexList[2].point,xvec);
  77. mFaceList[3].plane.set(mVertexList[0].point,yvec);
  78. mFaceList[3].plane.invert();
  79. mFaceList[4].plane.set(mVertexList[0].point,zvec);
  80. mFaceList[4].plane.invert();
  81. mFaceList[5].plane.set(mVertexList[4].point,zvec);
  82. // Initial edges
  83. mEdgeList.setSize(12);
  84. Edge* edge = mEdgeList.begin();
  85. S32 nextEdge = 0;
  86. for (i = 0; i < 4; i++) {
  87. S32 n = (i == 3)? 0: i + 1;
  88. S32 p = (i == 0)? 3: i - 1;
  89. edge->vertex[0] = i;
  90. edge->vertex[1] = n;
  91. edge->face[0] = i;
  92. edge->face[1] = 4;
  93. edge->next = ++nextEdge;
  94. edge++;
  95. edge->vertex[0] = 4 + i;
  96. edge->vertex[1] = 4 + n;
  97. edge->face[0] = i;
  98. edge->face[1] = 5;
  99. edge->next = ++nextEdge;
  100. edge++;
  101. edge->vertex[0] = i;
  102. edge->vertex[1] = 4 + i;
  103. edge->face[0] = i;
  104. edge->face[1] = p;
  105. edge->next = ++nextEdge;
  106. edge++;
  107. }
  108. edge[-1].next = -1;
  109. // Volume
  110. mVolumeList.setSize(1);
  111. Volume& volume = mVolumeList.last();
  112. volume.edgeList = 0;
  113. volume.material = -1;
  114. volume.object = 0;
  115. sideCount = 0;
  116. }
  117. //----------------------------------------------------------------------------
  118. void Polytope::intersect(SimObject* object,const BSPNode* root)
  119. {
  120. AssertFatal(mVolumeList.size() > 0,"Polytope::intersect: Missing initial volume");
  121. // Always clips the first volume against the BSP
  122. VolumeStack stack;
  123. stack.reserve(50);
  124. stack.increment();
  125. stack.last().edgeList = mVolumeList[0].edgeList;
  126. stack.last().node = root;
  127. while (!stack.empty()) {
  128. StackElement volume = stack.last();
  129. stack.pop_back();
  130. // If it's a solid node, export the volume
  131. const BSPNode* node = volume.node;
  132. if (!node->backNode && !node->frontNode) {
  133. mVolumeList.increment();
  134. Volume& vol = mVolumeList.last();
  135. vol.object = object;
  136. vol.material = node->material;
  137. vol.edgeList = volume.edgeList;
  138. continue;
  139. }
  140. // New front and back faces
  141. mFaceList.increment(2);
  142. Face& frontFace = mFaceList.last();
  143. Face& backFace = *(&frontFace - 1);
  144. backFace.original = frontFace.original = false;
  145. backFace.vertex = frontFace.vertex = 0;
  146. backFace.plane = frontFace.plane = node->plane;
  147. backFace.plane.invert();
  148. // New front and back volumes
  149. StackElement frontVolume,backVolume;
  150. frontVolume.edgeList = backVolume.edgeList = -1;
  151. const PlaneF& plane = node->plane;
  152. S32 startVertex = mVertexList.size();
  153. // Test & clip all the edges
  154. S32 sideBase = ++sideCount << 1;
  155. for (S32 i = volume.edgeList; i >= 0; i = mEdgeList[i].next) {
  156. // Copy into tmp first to avoid problems with the array.
  157. Edge edge = mEdgeList[i];
  158. Vertex& v0 = mVertexList[edge.vertex[0]];
  159. if (v0.side < sideBase)
  160. v0.side = sideBase + ((plane.distToPlane(v0.point) >= 0)? 0: 1);
  161. Vertex& v1 = mVertexList[edge.vertex[1]];
  162. if (v1.side < sideBase)
  163. v1.side = sideBase + ((plane.distToPlane(v1.point) >= 0)? 0: 1);
  164. if (v0.side != v1.side) {
  165. S32 s = v0.side - sideBase;
  166. intersect(plane,v0.point,v1.point);
  167. // Split the edge into each volume
  168. mEdgeList.increment(2);
  169. Edge& ev0 = mEdgeList.last();
  170. ev0.next = frontVolume.edgeList;
  171. frontVolume.edgeList = mEdgeList.size() - 1;
  172. Edge& ev1 = *(&ev0 - 1);
  173. ev1.next = backVolume.edgeList;
  174. backVolume.edgeList = frontVolume.edgeList - 1;
  175. ev0.vertex[0] = edge.vertex[s];
  176. ev1.vertex[0] = edge.vertex[s ^ 1];
  177. ev0.vertex[1] = ev1.vertex[1] = mVertexList.size() - 1;
  178. ev0.face[0] = ev1.face[0] = edge.face[0];
  179. ev0.face[1] = ev1.face[1] = edge.face[1];
  180. // Add new edges on the plane, one to each volume
  181. for (S32 f = 0; f < 2; f++) {
  182. Face& face = mFaceList[edge.face[f]];
  183. if (face.vertex < startVertex)
  184. face.vertex = mVertexList.size() - 1;
  185. else {
  186. mEdgeList.increment(2);
  187. Edge& ep0 = mEdgeList.last();
  188. ep0.next = frontVolume.edgeList;
  189. frontVolume.edgeList = mEdgeList.size() - 1;
  190. Edge& ep1 = *(&ep0 - 1);
  191. ep1.next = backVolume.edgeList;
  192. backVolume.edgeList = frontVolume.edgeList - 1;
  193. ep1.vertex[0] = ep0.vertex[0] = face.vertex;
  194. ep1.vertex[1] = ep0.vertex[1] = mVertexList.size() - 1;
  195. ep1.face[0] = ep0.face[0] = edge.face[f];
  196. ep1.face[1] = mFaceList.size() - 1;
  197. ep0.face[1] = ep1.face[1] - 1;
  198. }
  199. }
  200. }
  201. else
  202. if (v0.side == sideBase) {
  203. mEdgeList.push_back(edge);
  204. Edge& ne = mEdgeList.last();
  205. ne.next = frontVolume.edgeList;
  206. frontVolume.edgeList = mEdgeList.size() - 1;
  207. }
  208. else {
  209. mEdgeList.push_back(edge);
  210. Edge& ne = mEdgeList.last();
  211. ne.next = backVolume.edgeList;
  212. backVolume.edgeList = mEdgeList.size() - 1;
  213. }
  214. }
  215. // Push the front and back nodes
  216. if (node->frontNode && frontVolume.edgeList >= 0) {
  217. frontVolume.node = node->frontNode;
  218. stack.push_back(frontVolume);
  219. }
  220. if (node->backNode && backVolume.edgeList >= 0) {
  221. backVolume.node = node->backNode;
  222. stack.push_back(backVolume);
  223. }
  224. }
  225. }
  226. //----------------------------------------------------------------------------
  227. bool Polytope::intersect(const PlaneF& plane,const Point3F& sp,const Point3F& ep)
  228. {
  229. // If den == 0 then the line and plane are parallel.
  230. F32 den;
  231. Point3F dt = ep - sp;
  232. if ((den = plane.x * dt.x + plane.y * dt.y + plane.z * dt.z) == 0)
  233. return false;
  234. mVertexList.increment();
  235. Vertex& v = mVertexList.last();
  236. F32 s = -(plane.x * sp.x + plane.y * sp.y + plane.z * sp.z + plane.d) / den;
  237. v.point.x = sp.x + dt.x * s;
  238. v.point.y = sp.y + dt.y * s;
  239. v.point.z = sp.z + dt.z * s;
  240. v.side = 0;
  241. return true;
  242. }
  243. //----------------------------------------------------------------------------
  244. void Polytope::extrudeFace(S32 faceIdx,const VectorF& vec,Polytope* out)
  245. {
  246. // Assumes the face belongs to the first volume.
  247. out->mVertexList.clear();
  248. out->mFaceList.clear();
  249. out->mEdgeList.clear();
  250. out->mVolumeList.clear();
  251. sideCount++;
  252. // Front & end faces
  253. Face nface;
  254. nface.original = true;
  255. nface.vertex = 0;
  256. nface.plane = mFaceList[faceIdx].plane;
  257. out->mFaceList.setSize(2);
  258. out->mFaceList[0] = out->mFaceList[1] = nface;
  259. out->mFaceList[0].plane.invert();
  260. for (S32 e = mVolumeList[0].edgeList; e >= 0; e = mEdgeList[e].next) {
  261. Edge& edge = mEdgeList[e];
  262. if (edge.face[0] == faceIdx || edge.face[1] == faceIdx) {
  263. // Build face for this edge
  264. // Should think about calulating the plane
  265. S32 fi = out->mFaceList.size();
  266. out->mFaceList.push_back(nface);
  267. // Reserve 4 entries to make sure the ve[] pointers
  268. // into the list don't get invalidated.
  269. out->mEdgeList.reserve(out->mEdgeList.size() + 4);
  270. Edge* ve[2];
  271. // Build edges for each vertex
  272. for (S32 v = 0; v < 2; v++) {
  273. if (mVertexList[edge.vertex[v]].side < sideCount) {
  274. mVertexList[edge.vertex[v]].side = sideCount + out->mEdgeList.size();
  275. out->mVertexList.increment(2);
  276. out->mVertexList.end()[-1] =
  277. out->mVertexList.end()[-2] =
  278. mVertexList[edge.vertex[v]];
  279. out->mVertexList.last().point += vec;
  280. out->mEdgeList.increment();
  281. Edge& ne = out->mEdgeList.last();
  282. ne.next = out->mEdgeList.size();
  283. ne.vertex[1] = out->mVertexList.size() - 1;
  284. ne.vertex[0] = ne.vertex[1] - 1;
  285. ne.face[0] = ne.face[1] = -1;
  286. ve[v] = &ne;
  287. }
  288. else {
  289. S32 ei = mVertexList[edge.vertex[v]].side - sideCount;
  290. ve[v] = &out->mEdgeList[ei];
  291. }
  292. // Edge should share this face
  293. if (ve[v]->face[0] == -1)
  294. ve[v]->face[0] = fi;
  295. else
  296. ve[v]->face[1] = fi;
  297. }
  298. // Build parallel edges
  299. out->mEdgeList.increment(2);
  300. for (S32 i = 0; i < 2; i++ ) {
  301. Edge& ne = out->mEdgeList.end()[i - 2];
  302. ne.next = out->mEdgeList.size() - 1 + i;
  303. ne.vertex[0] = ve[0]->vertex[i];
  304. ne.vertex[1] = ve[1]->vertex[i];
  305. ne.face[0] = i;
  306. ne.face[1] = fi;
  307. }
  308. }
  309. }
  310. out->mEdgeList.last().next = -1;
  311. out->mVolumeList.increment();
  312. Volume& nv = out->mVolumeList.last();
  313. nv.edgeList = 0;
  314. nv.object = 0;
  315. nv.material = -1;
  316. }
  317. //----------------------------------------------------------------------------
  318. bool Polytope::findCollision(const VectorF& vec,Polytope::Collision *best)
  319. {
  320. if (mVolumeList.size() <= 1)
  321. return false;
  322. if (!best->object)
  323. best->distance = 1.0E30f;
  324. S32 bestVertex = -1;
  325. Polytope::Volume* bestVolume = NULL;
  326. sideCount++;
  327. // Find the closest point
  328. for (Volume* vol = mVolumeList.begin() + 1;
  329. vol < mVolumeList.end(); vol++) {
  330. for (S32 e = vol->edgeList; e >= 0; e = mEdgeList[e].next) {
  331. Edge& edge = mEdgeList[e];
  332. if (mFaceList[edge.face[0]].original &&
  333. mFaceList[edge.face[1]].original)
  334. continue;
  335. for (S32 v = 0; v < 2; v++) {
  336. S32 vi = edge.vertex[v];
  337. Vertex& vr = mVertexList[vi];
  338. if (vr.side != sideCount) {
  339. vr.side = sideCount;
  340. F32 dist = mDot(vr.point,vec);
  341. if (dist < best->distance) {
  342. best->distance = dist;
  343. bestVertex = vi;
  344. bestVolume = vol;
  345. }
  346. }
  347. }
  348. }
  349. }
  350. if (bestVertex == -1)
  351. return false;
  352. // Fill in the return value
  353. best->point = mVertexList[bestVertex].point;
  354. best->object = bestVolume->object;
  355. best->material = bestVolume->material;
  356. // Pick the best face
  357. F32 bestFaceDot = 1;
  358. for (S32 e = bestVolume->edgeList; e >= 0; e = mEdgeList[e].next) {
  359. Edge& edge = mEdgeList[e];
  360. if (edge.vertex[0] == bestVertex || edge.vertex[1] == bestVertex) {
  361. for (S32 f = 0; f < 2; f++) {
  362. Face& tf = mFaceList[edge.face[f]];
  363. F32 fd = mDot(tf.plane,vec);
  364. if (fd < bestFaceDot) {
  365. bestFaceDot = fd;
  366. best->plane = tf.plane;
  367. }
  368. }
  369. }
  370. }
  371. return true;
  372. }