clippedPolyList.cpp 13 KB

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