clippedPolyList.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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 "collision/clippedPolyList.h"
  24. #include "math/mMath.h"
  25. #include "console/console.h"
  26. #include "platform/profiler.h"
  27. #include "core/tAlgorithm.h"
  28. bool ClippedPolyList::allowClipping = true;
  29. //----------------------------------------------------------------------------
  30. ClippedPolyList::ClippedPolyList()
  31. : mNormal( Point3F::Zero ),
  32. mNormalTolCosineRadians( 0.0f )
  33. {
  34. VECTOR_SET_ASSOCIATION(mPolyList);
  35. VECTOR_SET_ASSOCIATION(mVertexList);
  36. VECTOR_SET_ASSOCIATION(mIndexList);
  37. VECTOR_SET_ASSOCIATION(mPolyPlaneList);
  38. VECTOR_SET_ASSOCIATION(mPlaneList);
  39. VECTOR_SET_ASSOCIATION(mNormalList);
  40. mIndexList.reserve(IndexListReserveSize);
  41. }
  42. ClippedPolyList::~ClippedPolyList()
  43. {
  44. }
  45. //----------------------------------------------------------------------------
  46. void ClippedPolyList::clear()
  47. {
  48. // Only clears internal data
  49. mPolyList.clear();
  50. mVertexList.clear();
  51. mIndexList.clear();
  52. mPolyPlaneList.clear();
  53. mNormalList.clear();
  54. }
  55. bool ClippedPolyList::isEmpty() const
  56. {
  57. return mPolyList.size() == 0;
  58. }
  59. //----------------------------------------------------------------------------
  60. U32 ClippedPolyList::addPoint(const Point3F& p)
  61. {
  62. mVertexList.increment();
  63. Vertex& v = mVertexList.last();
  64. v.point.x = p.x * mScale.x;
  65. v.point.y = p.y * mScale.y;
  66. v.point.z = p.z * mScale.z;
  67. mMatrix.mulP(v.point);
  68. // Build the plane mask
  69. register U32 mask = 1;
  70. register S32 count = mPlaneList.size();
  71. register PlaneF * plane = mPlaneList.address();
  72. v.mask = 0;
  73. while(--count >= 0) {
  74. if (plane++->distToPlane(v.point) > 0)
  75. v.mask |= mask;
  76. mask <<= 1;
  77. }
  78. return mVertexList.size() - 1;
  79. }
  80. U32 ClippedPolyList::addPlane(const PlaneF& plane)
  81. {
  82. mPolyPlaneList.increment();
  83. mPlaneTransformer.transform(plane, mPolyPlaneList.last());
  84. return mPolyPlaneList.size() - 1;
  85. }
  86. //----------------------------------------------------------------------------
  87. void ClippedPolyList::begin(BaseMatInstance* material,U32 surfaceKey)
  88. {
  89. mPolyList.increment();
  90. Poly& poly = mPolyList.last();
  91. poly.object = mCurrObject;
  92. poly.material = material;
  93. poly.vertexStart = mIndexList.size();
  94. poly.surfaceKey = surfaceKey;
  95. poly.polyFlags = 0;
  96. if(ClippedPolyList::allowClipping)
  97. poly.polyFlags = CLIPPEDPOLYLIST_FLAG_ALLOWCLIPPING;
  98. }
  99. //----------------------------------------------------------------------------
  100. void ClippedPolyList::plane(U32 v1,U32 v2,U32 v3)
  101. {
  102. mPolyList.last().plane.set(mVertexList[v1].point,
  103. mVertexList[v2].point,mVertexList[v3].point);
  104. }
  105. void ClippedPolyList::plane(const PlaneF& p)
  106. {
  107. mPlaneTransformer.transform(p, mPolyList.last().plane);
  108. }
  109. void ClippedPolyList::plane(const U32 index)
  110. {
  111. AssertFatal(index < mPolyPlaneList.size(), "Out of bounds index!");
  112. mPolyList.last().plane = mPolyPlaneList[index];
  113. }
  114. const PlaneF& ClippedPolyList::getIndexedPlane(const U32 index)
  115. {
  116. AssertFatal(index < mPolyPlaneList.size(), "Out of bounds index!");
  117. return mPolyPlaneList[index];
  118. }
  119. //----------------------------------------------------------------------------
  120. void ClippedPolyList::vertex(U32 vi)
  121. {
  122. mIndexList.push_back(vi);
  123. }
  124. //----------------------------------------------------------------------------
  125. void ClippedPolyList::end()
  126. {
  127. PROFILE_SCOPE( ClippedPolyList_Clip );
  128. Poly& poly = mPolyList.last();
  129. // Reject polygons facing away from our normal.
  130. if ( mDot( poly.plane, mNormal ) < mNormalTolCosineRadians )
  131. {
  132. mIndexList.setSize(poly.vertexStart);
  133. mPolyList.decrement();
  134. return;
  135. }
  136. // Build initial inside/outside plane masks
  137. U32 indexStart = poly.vertexStart;
  138. U32 vertexCount = mIndexList.size() - indexStart;
  139. U32 frontMask = 0,backMask = 0;
  140. U32 i;
  141. for (i = indexStart; i < mIndexList.size(); i++)
  142. {
  143. U32 mask = mVertexList[mIndexList[i]].mask;
  144. frontMask |= mask;
  145. backMask |= ~mask;
  146. }
  147. // Trivial accept if all the vertices are on the backsides of
  148. // all the planes.
  149. if (!frontMask)
  150. {
  151. poly.vertexCount = vertexCount;
  152. return;
  153. }
  154. // Trivial reject if any plane not crossed has all it's points
  155. // on the front.
  156. U32 crossMask = frontMask & backMask;
  157. if (~crossMask & frontMask)
  158. {
  159. mIndexList.setSize(poly.vertexStart);
  160. mPolyList.decrement();
  161. return;
  162. }
  163. // Potentially, this will add up to mPlaneList.size() * (indexStart - indexEnd)
  164. // elements to mIndexList, so ensure that it has enough space to store that
  165. // so we can use push_back_noresize. If you find this code block getting hit
  166. // frequently, changing the value of 'IndexListReserveSize' or doing some selective
  167. // allocation is suggested
  168. //
  169. // TODO: Re-visit this, since it obviously does not work correctly, and than
  170. // re-enable the push_back_noresize
  171. //while(mIndexList.size() + mPlaneList.size() * (mIndexList.size() - indexStart) > mIndexList.capacity() )
  172. // mIndexList.reserve(mIndexList.capacity() * 2);
  173. // Need to do some clipping
  174. for (U32 p = 0; p < mPlaneList.size(); p++)
  175. {
  176. U32 pmask = 1 << p;
  177. // Only test against this plane if we have something
  178. // on both sides
  179. if (!(crossMask & pmask))
  180. continue;
  181. U32 indexEnd = mIndexList.size();
  182. U32 i1 = indexEnd - 1;
  183. U32 mask1 = mVertexList[mIndexList[i1]].mask;
  184. for (U32 i2 = indexStart; i2 < indexEnd; i2++)
  185. {
  186. U32 mask2 = mVertexList[mIndexList[i2]].mask;
  187. if ((mask1 ^ mask2) & pmask)
  188. {
  189. //
  190. mVertexList.increment();
  191. VectorF& v1 = mVertexList[mIndexList[i1]].point;
  192. VectorF& v2 = mVertexList[mIndexList[i2]].point;
  193. VectorF vv = v2 - v1;
  194. F32 t = -mPlaneList[p].distToPlane(v1) / mDot(mPlaneList[p],vv);
  195. mIndexList.push_back/*_noresize*/(mVertexList.size() - 1);
  196. Vertex& iv = mVertexList.last();
  197. iv.point.x = v1.x + vv.x * t;
  198. iv.point.y = v1.y + vv.y * t;
  199. iv.point.z = v1.z + vv.z * t;
  200. iv.mask = 0;
  201. // Test against the remaining planes
  202. for (U32 i = p + 1; i < mPlaneList.size(); i++)
  203. if (mPlaneList[i].distToPlane(iv.point) > 0)
  204. {
  205. iv.mask = 1 << i;
  206. break;
  207. }
  208. }
  209. if (!(mask2 & pmask))
  210. {
  211. U32 index = mIndexList[i2];
  212. mIndexList.push_back/*_noresize*/(index);
  213. }
  214. mask1 = mask2;
  215. i1 = i2;
  216. }
  217. // Check for degenerate
  218. indexStart = indexEnd;
  219. if (mIndexList.size() - indexStart < 3)
  220. {
  221. mIndexList.setSize(poly.vertexStart);
  222. mPolyList.decrement();
  223. return;
  224. }
  225. }
  226. // Emit what's left and compress the index list.
  227. poly.vertexCount = mIndexList.size() - indexStart;
  228. memcpy(&mIndexList[poly.vertexStart],
  229. &mIndexList[indexStart],poly.vertexCount);
  230. mIndexList.setSize(poly.vertexStart + poly.vertexCount);
  231. }
  232. //----------------------------------------------------------------------------
  233. void ClippedPolyList::memcpy(U32* dst, U32* src,U32 size)
  234. {
  235. U32* end = src + size;
  236. while (src != end)
  237. *dst++ = *src++;
  238. }
  239. void ClippedPolyList::cullUnusedVerts()
  240. {
  241. PROFILE_SCOPE( ClippedPolyList_CullUnusedVerts );
  242. U32 i = 0;
  243. U32 k, n, numDeleted;
  244. bool result;
  245. IndexListIterator iNextIter;
  246. VertexListIterator nextVIter;
  247. VertexListIterator vIter;
  248. for ( vIter = mVertexList.begin(); vIter != mVertexList.end(); vIter++, i++ )
  249. {
  250. // Is this vertex used?
  251. iNextIter = find( mIndexList.begin(), mIndexList.end(), i );
  252. if ( iNextIter != mIndexList.end() )
  253. continue;
  254. // If not, find the next used vertex.
  255. // i is an unused vertex
  256. // k is a used vertex
  257. // delete the vertices from i to j - 1
  258. k = 0;
  259. n = i + 1;
  260. result = false;
  261. numDeleted = 0;
  262. for ( nextVIter = vIter + 1; nextVIter != mVertexList.end(); nextVIter++, n++ )
  263. {
  264. iNextIter = find( mIndexList.begin(), mIndexList.end(), n );
  265. // If we found a used vertex
  266. // grab its index for later use
  267. // and set our result bool.
  268. if ( (*iNextIter) == n )
  269. {
  270. k = n;
  271. result = true;
  272. break;
  273. }
  274. }
  275. // All the remaining verts are unused.
  276. if ( !result )
  277. {
  278. mVertexList.setSize( i );
  279. break;
  280. }
  281. // Erase unused verts.
  282. numDeleted = (k-1) - i + 1;
  283. mVertexList.erase( i, numDeleted );
  284. // Find any references to vertices after those deleted
  285. // in the mIndexList and correct with an offset
  286. for ( iNextIter = mIndexList.begin(); iNextIter != mIndexList.end(); iNextIter++ )
  287. {
  288. if ( (*iNextIter) > i )
  289. (*iNextIter) -= numDeleted;
  290. }
  291. // After the erase the current iter should
  292. // point at the used vertex we found... the
  293. // loop will continue with the next vert.
  294. }
  295. }
  296. void ClippedPolyList::triangulate()
  297. {
  298. PROFILE_SCOPE( ClippedPolyList_Triangulate );
  299. // Copy the source lists to our temp list and clear
  300. // the originals which will recieve the results.
  301. mTempPolyList.set( mPolyList.address(), mPolyList.size() );
  302. mTempIndexList.set( mIndexList.address(), mIndexList.size() );
  303. mPolyList.clear();
  304. mIndexList.clear();
  305. U32 j, numTriangles;
  306. //
  307. PolyListIterator polyIter = mTempPolyList.begin();
  308. for ( ; polyIter != mTempPolyList.end(); polyIter++ )
  309. {
  310. const Poly &poly = *polyIter;
  311. // How many triangles in this poly?
  312. numTriangles = poly.vertexCount - 2;
  313. // Build out the triangles.
  314. for ( j = 0; j < numTriangles; j++ )
  315. {
  316. mPolyList.increment();
  317. Poly &triangle = mPolyList.last();
  318. triangle = poly;
  319. triangle.vertexCount = 3;
  320. triangle.vertexStart = mIndexList.size();
  321. mIndexList.push_back( mTempIndexList[ poly.vertexStart ] );
  322. mIndexList.push_back( mTempIndexList[ poly.vertexStart + 1 + j ] );
  323. mIndexList.push_back( mTempIndexList[ poly.vertexStart + 2 + j ] );
  324. }
  325. }
  326. }
  327. void ClippedPolyList::generateNormals()
  328. {
  329. PROFILE_SCOPE( ClippedPolyList_GenerateNormals );
  330. mNormalList.setSize( mVertexList.size() );
  331. U32 i, polyCount;
  332. VectorF normal;
  333. PolyListIterator polyIter;
  334. IndexListIterator indexIter;
  335. Vector<VectorF>::iterator normalIter = mNormalList.begin();
  336. U32 n = 0;
  337. for ( ; normalIter != mNormalList.end(); normalIter++, n++ )
  338. {
  339. // Average all the face normals which
  340. // share this vertex index.
  341. indexIter = mIndexList.begin();
  342. normal.zero();
  343. polyCount = 0;
  344. i = 0;
  345. for ( ; indexIter != mIndexList.end(); indexIter++, i++ )
  346. {
  347. if ( n != *indexIter )
  348. continue;
  349. polyIter = mPolyList.begin();
  350. for ( ; polyIter != mPolyList.end(); polyIter++ )
  351. {
  352. const Poly& poly = *polyIter;
  353. if ( i < poly.vertexStart || i > poly.vertexStart + poly.vertexCount )
  354. continue;
  355. ++polyCount;
  356. normal += poly.plane;
  357. }
  358. }
  359. // Average it.
  360. if ( polyCount > 0 )
  361. normal /= (F32)polyCount;
  362. // Note: we use a temporary for the normal averaging
  363. // then copy the result to limit the number of arrays
  364. // we're touching during the innermost loop.
  365. *normalIter = normal;
  366. }
  367. }