interiorCollision.cpp 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775
  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 "interior/interior.h"
  23. #include "math/mSphere.h"
  24. #include "scene/sceneObject.h"
  25. #include "collision/abstractPolyList.h"
  26. #include "core/frameAllocator.h"
  27. #include "platform/profiler.h"
  28. namespace {
  29. //--------------------------------------
  30. // Custom on plane version to reduce numerical inaccuracies in the GJK stuff.
  31. // copied from terrCollision.cc
  32. inline bool isOnPlane(const Point3F& p, const PlaneF& plane)
  33. {
  34. F32 dist = mDot(plane,p) + plane.d;
  35. return mFabs(dist) < 0.1f;
  36. }
  37. } // namespace {}
  38. //--------------------------------------------------------------------------
  39. //-------------------------------------- SurfaceHash
  40. const U32 csgHashSize = 4096;
  41. class SurfaceHash
  42. {
  43. private:
  44. U32 hash(U32 i) { return i & (csgHashSize - 1); }
  45. public:
  46. U32 mSurfaceArray[csgHashSize];
  47. U32 mNumSurfaces;
  48. U32 mHashTable[csgHashSize];
  49. public:
  50. SurfaceHash()
  51. {
  52. AssertFatal(isPow2(csgHashSize), "Error, size must be power of 2");
  53. }
  54. void clear()
  55. {
  56. dMemset(mHashTable, 0xFF, sizeof(mHashTable));
  57. mNumSurfaces = 0;
  58. }
  59. void insert(U32 surface);
  60. };
  61. inline void SurfaceHash::insert(U32 surface)
  62. {
  63. AssertFatal(surface != 0xFFFFFFFF, "Hm, bad assumption. 0xFFFFFFFF is a valid surface index?");
  64. if (mNumSurfaces >= csgHashSize)
  65. {
  66. AssertFatal(false, "Error, exceeded surfaceCount restriction!");
  67. return;
  68. }
  69. U32 probe = hash(surface);
  70. U32 initialProbe = probe;
  71. while (mHashTable[probe] != 0xFFFFFFFF)
  72. {
  73. // If it's already in the table, bail.
  74. if (mHashTable[probe] == surface)
  75. return;
  76. probe = (probe + 1) % csgHashSize;
  77. AssertFatal(probe != initialProbe, "Hm, wraparound?");
  78. }
  79. // If we're here, then the probe failed, and the index isn't in the hash
  80. // table
  81. mHashTable[probe] = surface;
  82. mSurfaceArray[mNumSurfaces++] = surface;
  83. }
  84. class InteriorPolytope
  85. {
  86. // Convex Polyhedron
  87. public:
  88. struct Vertex
  89. {
  90. Point3F point;
  91. // Temp BSP clip info
  92. S32 side;
  93. };
  94. struct Edge
  95. {
  96. S32 vertex[2];
  97. S32 face[2];
  98. S32 next;
  99. };
  100. struct Face
  101. {
  102. S32 original;
  103. // Temp BSP clip info
  104. S32 vertex;
  105. };
  106. struct Volume
  107. {
  108. S32 edgeList;
  109. };
  110. struct StackElement
  111. {
  112. S32 edgeList;
  113. U32 popCount;
  114. U32 nodeIndex;
  115. };
  116. typedef Vector<Edge> EdgeList;
  117. typedef Vector<Face> FaceList;
  118. typedef Vector<Vertex> VertexList;
  119. typedef Vector<Volume> VolumeList;
  120. typedef Vector<StackElement> VolumeStack;
  121. //
  122. S32 sideCount;
  123. EdgeList mEdgeList;
  124. FaceList mFaceList;
  125. VertexList mVertexList;
  126. VolumeList mVolumeList;
  127. public:
  128. //
  129. InteriorPolytope();
  130. void clear();
  131. bool intersect(const PlaneF& plane,const Point3F& sp,const Point3F& ep);
  132. void buildBox(const Box3F& box, const MatrixF& transform, const Point3F& scale);
  133. inline bool didIntersect() { return mVolumeList.size() > 1; }
  134. };
  135. //----------------------------------------------------------------------------
  136. // Box should be axis aligned in the transform space provided.
  137. InteriorPolytope::InteriorPolytope()
  138. {
  139. mVertexList.reserve(256);
  140. mFaceList.reserve(200);
  141. mEdgeList.reserve(100);
  142. mVolumeList.reserve(20);
  143. sideCount = 0;
  144. }
  145. void InteriorPolytope::clear()
  146. {
  147. mVertexList.clear();
  148. mFaceList.clear();
  149. mEdgeList.clear();
  150. mVolumeList.clear();
  151. sideCount = 0;
  152. }
  153. void InteriorPolytope::buildBox(const Box3F& box, const MatrixF& transform, const Point3F&)
  154. {
  155. // Initial vertices
  156. mVertexList.setSize(8);
  157. mVertexList[0].point = Point3F(box.minExtents.x, box.minExtents.y, box.minExtents.z);
  158. mVertexList[1].point = Point3F(box.minExtents.x, box.maxExtents.y, box.minExtents.z);
  159. mVertexList[2].point = Point3F(box.maxExtents.x, box.maxExtents.y, box.minExtents.z);
  160. mVertexList[3].point = Point3F(box.maxExtents.x, box.minExtents.y, box.minExtents.z);
  161. mVertexList[4].point = Point3F(box.minExtents.x, box.minExtents.y, box.maxExtents.z);
  162. mVertexList[5].point = Point3F(box.minExtents.x, box.maxExtents.y, box.maxExtents.z);
  163. mVertexList[6].point = Point3F(box.maxExtents.x, box.maxExtents.y, box.maxExtents.z);
  164. mVertexList[7].point = Point3F(box.maxExtents.x, box.minExtents.y, box.maxExtents.z);
  165. S32 i;
  166. for (i = 0; i < 8; i++)
  167. {
  168. transform.mulP(mVertexList[i].point);
  169. mVertexList[i].side = 0;
  170. }
  171. // Initial faces
  172. mFaceList.setSize(6);
  173. for (S32 f = 0; f < 6; f++)
  174. {
  175. Face& face = mFaceList[f];
  176. face.original = true;
  177. face.vertex = 0;
  178. }
  179. // Initial edges
  180. mEdgeList.setSize(12);
  181. Edge* edge = mEdgeList.begin();
  182. S32 nextEdge = 0;
  183. for (i = 0; i < 4; i++)
  184. {
  185. S32 n = (i == 3)? 0: i + 1;
  186. S32 p = (i == 0)? 3: i - 1;
  187. edge->vertex[0] = i;
  188. edge->vertex[1] = n;
  189. edge->face[0] = i;
  190. edge->face[1] = 4;
  191. edge->next = ++nextEdge;
  192. edge++;
  193. edge->vertex[0] = 4 + i;
  194. edge->vertex[1] = 4 + n;
  195. edge->face[0] = i;
  196. edge->face[1] = 5;
  197. edge->next = ++nextEdge;
  198. edge++;
  199. edge->vertex[0] = i;
  200. edge->vertex[1] = 4 + i;
  201. edge->face[0] = i;
  202. edge->face[1] = p;
  203. edge->next = ++nextEdge;
  204. edge++;
  205. }
  206. edge[-1].next = -1;
  207. // Volume
  208. mVolumeList.setSize(1);
  209. Volume& volume = mVolumeList.last();
  210. volume.edgeList = 0;
  211. sideCount = 0;
  212. }
  213. bool InteriorPolytope::intersect(const PlaneF& plane,const Point3F& sp,const Point3F& ep)
  214. {
  215. // If den == 0 then the line and plane are parallel.
  216. F32 den;
  217. Point3F dt = ep - sp;
  218. if ((den = plane.x * dt.x + plane.y * dt.y + plane.z * dt.z) == 0.0f)
  219. return false;
  220. // Save the values in sp since the memory may go away after the increment
  221. F32 sp_x = sp.x;
  222. F32 sp_y = sp.y;
  223. F32 sp_z = sp.z;
  224. mVertexList.increment();
  225. Vertex& v = mVertexList.last();
  226. F32 s = -(plane.x * sp_x + plane.y * sp_y + plane.z * sp_z + plane.d) / den;
  227. v.point.x = sp_x + dt.x * s;
  228. v.point.y = sp_y + dt.y * s;
  229. v.point.z = sp_z + dt.z * s;
  230. v.side = 0;
  231. return true;
  232. }
  233. //--------------------------------------------------------------------------
  234. void Interior::collisionFanFromSurface(const Surface& rSurface, U32* fanIndices, U32* numIndices) const
  235. {
  236. U32 tempIndices[32];
  237. tempIndices[0] = 0;
  238. U32 idx = 1;
  239. U32 i;
  240. for (i = 1; i < rSurface.windingCount; i += 2)
  241. tempIndices[idx++] = i;
  242. for (i = ((rSurface.windingCount - 1) & (~0x1)); i > 0; i -= 2)
  243. tempIndices[idx++] = i;
  244. idx = 0;
  245. for (i = 0; i < rSurface.windingCount; i++)
  246. {
  247. if (rSurface.fanMask & (1 << i))
  248. {
  249. fanIndices[idx++] = mWindings[rSurface.windingStart + tempIndices[i]];
  250. }
  251. }
  252. *numIndices = idx;
  253. }
  254. void Interior::fullWindingFromSurface(const Surface& rSurface, U32* fanIndices, U32* numIndices) const
  255. {
  256. U32 tempIndices[32];
  257. tempIndices[0] = 0;
  258. U32 idx = 1;
  259. U32 i;
  260. for (i = 1; i < rSurface.windingCount; i += 2)
  261. tempIndices[idx++] = i;
  262. for (i = ((rSurface.windingCount - 1) & (~0x1)); i > 0; i -= 2)
  263. tempIndices[idx++] = i;
  264. idx = 0;
  265. for (i = 0; i < rSurface.windingCount; i++)
  266. fanIndices[idx++] = mWindings[rSurface.windingStart + tempIndices[i]];
  267. *numIndices = idx;
  268. }
  269. bool Interior::castRay_r(const U32 node,
  270. const U16 planeIndex,
  271. const Point3F& s,
  272. const Point3F& e,
  273. RayInfo* info)
  274. {
  275. if (isBSPLeafIndex(node) == false)
  276. {
  277. const IBSPNode& rNode = mBSPNodes[node];
  278. const PlaneF& rPlane = getPlane(rNode.planeIndex);
  279. const PlaneF::Side sSide = rPlane.whichSide(s);
  280. const PlaneF::Side eSide = rPlane.whichSide(e);
  281. switch (PlaneSwitchCode(sSide, eSide))
  282. {
  283. case PlaneSwitchCode(PlaneF::Front, PlaneF::Front):
  284. case PlaneSwitchCode(PlaneF::Front, PlaneF::On):
  285. case PlaneSwitchCode(PlaneF::On, PlaneF::Front):
  286. return castRay_r(rNode.frontIndex, planeIndex, s, e, info);
  287. break;
  288. case PlaneSwitchCode(PlaneF::On, PlaneF::Back):
  289. case PlaneSwitchCode(PlaneF::Back, PlaneF::On):
  290. case PlaneSwitchCode(PlaneF::Back, PlaneF::Back):
  291. return castRay_r(rNode.backIndex, planeIndex, s, e, info);
  292. break;
  293. case PlaneSwitchCode(PlaneF::On, PlaneF::On):
  294. // Line lies on the plane
  295. if (isBSPLeafIndex(rNode.backIndex) == false)
  296. {
  297. if (castRay_r(rNode.backIndex, planeIndex, s, e, info))
  298. return true;
  299. }
  300. if (isBSPLeafIndex(rNode.frontIndex) == false)
  301. {
  302. if (castRay_r(rNode.frontIndex, planeIndex, s, e, info))
  303. return true;
  304. }
  305. return false;
  306. break;
  307. case PlaneSwitchCode(PlaneF::Front, PlaneF::Back):
  308. {
  309. Point3F ip;
  310. F32 intersectT = rPlane.intersect(s, e);
  311. AssertFatal(intersectT != PARALLEL_PLANE, "Error, this should never happen in this case!");
  312. ip.interpolate(s, e, intersectT);
  313. if (castRay_r(rNode.frontIndex, planeIndex, s, ip, info))
  314. return true;
  315. return castRay_r(rNode.backIndex, rNode.planeIndex, ip, e, info);
  316. }
  317. break;
  318. case PlaneSwitchCode(PlaneF::Back, PlaneF::Front):
  319. {
  320. Point3F ip;
  321. F32 intersectT = rPlane.intersect(s, e);
  322. AssertFatal(intersectT != PARALLEL_PLANE, "Error, this should never happen in this case!");
  323. ip.interpolate(s, e, intersectT);
  324. if (castRay_r(rNode.backIndex, planeIndex, s, ip, info))
  325. return true;
  326. return castRay_r(rNode.frontIndex, rNode.planeIndex, ip, e, info);
  327. }
  328. break;
  329. default:
  330. AssertFatal(false, "Misunderstood switchCode in Interior::castRay_r");
  331. return false;
  332. }
  333. }
  334. if (isBSPSolidLeaf(node))
  335. {
  336. // DMM: Set material info here.. material info? hahaha
  337. info->point = s;
  338. if (planeIndex != U16(-1))
  339. {
  340. const PlaneF& rPlane = getPlane(planeIndex);
  341. info->normal = rPlane;
  342. if (planeIsFlipped(planeIndex))
  343. {
  344. info->normal.neg();
  345. if (rPlane.whichSide(e) == PlaneF::Back)
  346. info->normal.neg();
  347. }
  348. else
  349. {
  350. if (rPlane.whichSide(e) == PlaneF::Front)
  351. info->normal.neg();
  352. }
  353. }
  354. else
  355. {
  356. // Point started in solid;
  357. if (s == e)
  358. {
  359. info->normal.set(0.0f, 0.0f, 1.0f);
  360. }
  361. else
  362. {
  363. info->normal = s - e;
  364. info->normal.normalize();
  365. }
  366. }
  367. // ok.. let's get it on! get the face that was hit
  368. info->face = U32(-1);
  369. U32 numStaticSurfaces = 0;
  370. const IBSPLeafSolid & rLeaf = mBSPSolidLeaves[getBSPSolidLeafIndex(node)];
  371. for(U32 i = 0; i < rLeaf.surfaceCount; i++)
  372. {
  373. U32 surfaceIndex = mSolidLeafSurfaces[rLeaf.surfaceIndex + i];
  374. if(isNullSurfaceIndex(surfaceIndex))
  375. {
  376. const NullSurface & rSurface = mNullSurfaces[getNullSurfaceIndex(surfaceIndex)];
  377. if (rSurface.surfaceFlags & SurfaceStaticMesh)
  378. numStaticSurfaces++;
  379. continue;
  380. }
  381. const Surface & rSurface = mSurfaces[surfaceIndex];
  382. if(!areEqualPlanes(rSurface.planeIndex, planeIndex))
  383. continue;
  384. PlaneF plane = getPlane(rSurface.planeIndex);
  385. if(planeIsFlipped(rSurface.planeIndex))
  386. plane.neg();
  387. // unfan this surface
  388. U32 winding[32];
  389. U32 windingCount;
  390. collisionFanFromSurface(rSurface, winding, &windingCount);
  391. // inside this surface?
  392. bool inside = true;
  393. for(U32 j = 0; inside && (j < windingCount); j++)
  394. {
  395. U32 k = (j+1) % windingCount;
  396. Point3F vec1 = mPoints[winding[k]].point - mPoints[winding[j]].point;
  397. Point3F vec2 = info->point - mPoints[winding[j]].point;
  398. Point3F cross;
  399. mCross(vec2, vec1, &cross);
  400. if(mDot(plane, cross) < 0.f)
  401. inside = false;
  402. }
  403. if(inside)
  404. {
  405. info->face = surfaceIndex;
  406. info->material = mMaterialList->getMaterialInst( rSurface.textureIndex );
  407. break;
  408. }
  409. }
  410. if (Interior::smLightingCastRays && numStaticSurfaces == rLeaf.surfaceCount && numStaticSurfaces > 0)
  411. return false;
  412. return true;
  413. }
  414. return false;
  415. }
  416. bool Interior::castRay(const Point3F& s, const Point3F& e, RayInfo* info)
  417. {
  418. // DMM: Going to need normal here eventually.
  419. bool hit = castRay_r(0, U16(-1), s, e, info);
  420. if (hit)
  421. {
  422. Point3F vec = e - s;
  423. F32 len = vec.len();
  424. if (len < 1e-6f)
  425. {
  426. info->t = 0.0f;
  427. }
  428. else
  429. {
  430. vec /= len;
  431. info->t = mDot(info->point - s, vec) / len;
  432. }
  433. }
  434. AssertFatal(!hit || (info->normal.z == info->normal.z), "NaN returned from castRay.\n\nPlease talk to DMM if you are running this in the debugger");
  435. return hit;
  436. }
  437. void Interior::buildPolyList_r(InteriorPolytope& polytope,
  438. SurfaceHash& hash)
  439. {
  440. // Submit the first volume of the poly tope to the bsp tree
  441. static InteriorPolytope::VolumeStack stack;
  442. stack.reserve(256);
  443. stack.setSize(1);
  444. stack.last().edgeList = polytope.mVolumeList[0].edgeList;
  445. stack.last().nodeIndex = 0;
  446. stack.last().popCount = 0;
  447. static Vector<U16> collPlanes;
  448. collPlanes.reserve(64);
  449. collPlanes.clear();
  450. while (stack.empty() == false)
  451. {
  452. InteriorPolytope::StackElement volume = stack.last();
  453. stack.pop_back();
  454. if (isBSPLeafIndex(volume.nodeIndex))
  455. {
  456. if (isBSPSolidLeaf(volume.nodeIndex))
  457. {
  458. // Export the polys from this node.
  459. const IBSPLeafSolid& rLeaf = mBSPSolidLeaves[getBSPSolidLeafIndex(volume.nodeIndex)];
  460. for (U32 i = 0; i < rLeaf.surfaceCount; i++)
  461. {
  462. U32 surfaceIndex = mSolidLeafSurfaces[rLeaf.surfaceIndex + i];
  463. if (isNullSurfaceIndex(surfaceIndex))
  464. {
  465. // Is a NULL surface
  466. const NullSurface& rSurface = mNullSurfaces[getNullSurfaceIndex(surfaceIndex)];
  467. for (U32 j = 0; j < collPlanes.size(); j++)
  468. {
  469. if (areEqualPlanes(rSurface.planeIndex, collPlanes[j]) == true)
  470. {
  471. hash.insert(surfaceIndex);
  472. break;
  473. }
  474. }
  475. }
  476. else
  477. {
  478. const Surface& rSurface = mSurfaces[surfaceIndex];
  479. for (U32 j = 0; j < collPlanes.size(); j++)
  480. {
  481. if (areEqualPlanes(rSurface.planeIndex, collPlanes[j]) == true)
  482. {
  483. hash.insert(surfaceIndex);
  484. break;
  485. }
  486. }
  487. }
  488. }
  489. }
  490. if (volume.popCount)
  491. for (U32 i = 0; i < volume.popCount; i++)
  492. collPlanes.pop_back();
  493. continue;
  494. }
  495. const IBSPNode& rNode = mBSPNodes[volume.nodeIndex];
  496. // New front and back faces
  497. polytope.mFaceList.increment(2);
  498. InteriorPolytope::Face& frontFace = polytope.mFaceList[polytope.mFaceList.size() - 1];
  499. InteriorPolytope::Face& backFace = polytope.mFaceList[polytope.mFaceList.size() - 2];
  500. backFace.original = frontFace.original = false;
  501. backFace.vertex = frontFace.vertex = 0;
  502. // New front and back volumes
  503. InteriorPolytope::StackElement frontVolume,backVolume;
  504. frontVolume.edgeList = backVolume.edgeList = -1;
  505. PlaneF plane = getPlane(rNode.planeIndex);
  506. if (planeIsFlipped(rNode.planeIndex))
  507. plane.neg();
  508. S32 startVertex = polytope.mVertexList.size();
  509. // Test & clip all the edges
  510. S32 sideBase = ++polytope.sideCount << 1;
  511. for (S32 i = volume.edgeList; i >= 0; i = polytope.mEdgeList[i].next)
  512. {
  513. // Copy into tmp first to avoid problems with the array.
  514. InteriorPolytope::Edge edge = polytope.mEdgeList[i];
  515. InteriorPolytope::Vertex& v0 = polytope.mVertexList[edge.vertex[0]];
  516. if (v0.side < sideBase)
  517. v0.side = sideBase + ((plane.distToPlane(v0.point) >= 0)? 0: 1);
  518. InteriorPolytope::Vertex& v1 = polytope.mVertexList[edge.vertex[1]];
  519. if (v1.side < sideBase)
  520. v1.side = sideBase + ((plane.distToPlane(v1.point) >= 0)? 0: 1);
  521. if (v0.side != v1.side)
  522. {
  523. S32 s = v0.side - sideBase;
  524. polytope.intersect(plane,v0.point,v1.point);
  525. // Split the edge into each volume
  526. polytope.mEdgeList.increment(2);
  527. InteriorPolytope::Edge& e0 = polytope.mEdgeList.last();
  528. e0.next = frontVolume.edgeList;
  529. frontVolume.edgeList = polytope.mEdgeList.size() - 1;
  530. InteriorPolytope::Edge& e1 = *(&e0 - 1);
  531. e1.next = backVolume.edgeList;
  532. backVolume.edgeList = frontVolume.edgeList - 1;
  533. e0.vertex[0] = edge.vertex[s];
  534. e1.vertex[0] = edge.vertex[s ^ 1];
  535. e0.vertex[1] = e1.vertex[1] = polytope.mVertexList.size() - 1;
  536. e0.face[0] = e1.face[0] = edge.face[0];
  537. e0.face[1] = e1.face[1] = edge.face[1];
  538. // Add new edges on the plane, one to each volume
  539. for (S32 f = 0; f < 2; f++)
  540. {
  541. InteriorPolytope::Face& face = polytope.mFaceList[edge.face[f]];
  542. if (face.vertex < startVertex)
  543. {
  544. face.vertex = polytope.mVertexList.size() - 1;
  545. }
  546. else
  547. {
  548. polytope.mEdgeList.increment(2);
  549. InteriorPolytope::Edge& e0 = polytope.mEdgeList.last();
  550. e0.next = frontVolume.edgeList;
  551. frontVolume.edgeList = polytope.mEdgeList.size() - 1;
  552. InteriorPolytope::Edge& e1 = *(&e0 - 1);
  553. e1.next = backVolume.edgeList;
  554. backVolume.edgeList = frontVolume.edgeList - 1;
  555. e1.vertex[0] = e0.vertex[0] = face.vertex;
  556. e1.vertex[1] = e0.vertex[1] = polytope.mVertexList.size() - 1;
  557. e1.face[0] = e0.face[0] = edge.face[f];
  558. e1.face[1] = polytope.mFaceList.size() - 1;
  559. e0.face[1] = e1.face[1] - 1;
  560. }
  561. }
  562. }
  563. else
  564. {
  565. if (v0.side == sideBase)
  566. {
  567. polytope.mEdgeList.push_back(edge);
  568. InteriorPolytope::Edge& ne = polytope.mEdgeList.last();
  569. ne.next = frontVolume.edgeList;
  570. frontVolume.edgeList = polytope.mEdgeList.size() - 1;
  571. }
  572. else
  573. {
  574. polytope.mEdgeList.push_back(edge);
  575. InteriorPolytope::Edge& ne = polytope.mEdgeList.last();
  576. ne.next = backVolume.edgeList;
  577. backVolume.edgeList = polytope.mEdgeList.size() - 1;
  578. }
  579. }
  580. }
  581. // Push the front and back nodes
  582. if (frontVolume.edgeList >= 0 && backVolume.edgeList >= 0)
  583. {
  584. collPlanes.push_back(rNode.planeIndex);
  585. frontVolume.nodeIndex = rNode.frontIndex;
  586. frontVolume.popCount = volume.popCount + 1;
  587. stack.push_back(frontVolume);
  588. backVolume.nodeIndex = rNode.backIndex;
  589. backVolume.popCount = 0;
  590. stack.push_back(backVolume);
  591. }
  592. else if (frontVolume.edgeList >= 0)
  593. {
  594. frontVolume.nodeIndex = rNode.frontIndex;
  595. frontVolume.popCount = volume.popCount;
  596. stack.push_back(frontVolume);
  597. }
  598. else if (backVolume.edgeList >= 0)
  599. {
  600. backVolume.nodeIndex = rNode.backIndex;
  601. backVolume.popCount = volume.popCount;
  602. stack.push_back(backVolume);
  603. }
  604. else
  605. {
  606. // Pop off our own planes...
  607. if (volume.popCount)
  608. for (U32 i = 0; i < volume.popCount; i++)
  609. collPlanes.pop_back();
  610. }
  611. }
  612. AssertFatal(collPlanes.size() == 0, "Unbalanced stack!");
  613. }
  614. bool Interior::buildPolyList(AbstractPolyList* list,
  615. const Box3F& box,
  616. const MatrixF& transform,
  617. const Point3F& scale)
  618. {
  619. Box3F testBox;
  620. MatrixF toItr;
  621. if (!list->getMapping(&toItr,&testBox))
  622. {
  623. // this list doesn't do this, use world space box and transform
  624. testBox = box;
  625. toItr = transform;
  626. }
  627. // construct an interior space box from testBox and toItr
  628. // source space may be world space, or may be something else...
  629. // that's up to the list
  630. // Note: transform maps to interior, but scale is itr -> world...
  631. // that is why we divide by scale below...
  632. F32 * f = toItr;
  633. F32 xx = mFabs(f[0]); F32 xy = mFabs(f[4]); F32 xz = mFabs(f[8]);
  634. F32 yx = mFabs(f[1]); F32 yy = mFabs(f[5]); F32 yz = mFabs(f[9]);
  635. F32 zx = mFabs(f[2]); F32 zy = mFabs(f[6]); F32 zz = mFabs(f[10]);
  636. F32 xlen = testBox.maxExtents.x - testBox.minExtents.x;
  637. F32 ylen = testBox.maxExtents.y - testBox.minExtents.y;
  638. F32 zlen = testBox.maxExtents.z - testBox.minExtents.z;
  639. F32 invScalex = 1.0f/scale.x;
  640. F32 invScaley = 1.0f/scale.y;
  641. F32 invScalez = 1.0f/scale.z;
  642. F32 xrad = (xx * xlen + yx * ylen + zx * zlen) * invScalex;
  643. F32 yrad = (xy * xlen + yy * ylen + zy * zlen) * invScaley;
  644. F32 zrad = (xz * xlen + yz * ylen + zz * zlen) * invScalez;
  645. Box3F interiorBox;
  646. testBox.getCenter(&interiorBox.minExtents);
  647. toItr.mulP(interiorBox.minExtents);
  648. interiorBox.minExtents.x *= invScalex;
  649. interiorBox.minExtents.y *= invScaley;
  650. interiorBox.minExtents.z *= invScalez;
  651. interiorBox.maxExtents = interiorBox.minExtents;
  652. interiorBox.minExtents.x -= xrad;
  653. interiorBox.minExtents.y -= yrad;
  654. interiorBox.minExtents.z -= zrad;
  655. interiorBox.maxExtents.x += xrad;
  656. interiorBox.maxExtents.y += yrad;
  657. interiorBox.maxExtents.z += zrad;
  658. U32 waterMark = FrameAllocator::getWaterMark();
  659. U16* hulls = (U16*)FrameAllocator::alloc(mConvexHulls.size() * sizeof(U16));
  660. U32 numHulls = 0;
  661. getIntersectingHulls(interiorBox,hulls, &numHulls);
  662. if (numHulls == 0)
  663. {
  664. FrameAllocator::setWaterMark(waterMark);
  665. return false;
  666. }
  667. // we've found all the hulls that intersect the lists interior space bounding box...
  668. // now cull out those hulls which don't intersect the oriented bounding box...
  669. Point3F radii = testBox.maxExtents - testBox.minExtents;
  670. radii *= 0.5f;
  671. radii.x *= invScalex;
  672. radii.y *= invScaley;
  673. radii.z *= invScalez;
  674. // adjust toItr transform so that origin of source space is box center
  675. // Note: center of interior box will be = to transformed center of testBox
  676. Point3F center = interiorBox.minExtents + interiorBox.maxExtents;
  677. center *= 0.5f;
  678. toItr.setColumn(3,center); // (0,0,0) now goes where box center used to...
  679. for (S32 i=0; i<numHulls; i++)
  680. {
  681. const ConvexHull & hull = mConvexHulls[hulls[i]];
  682. Box3F hullBox(hull.minX,hull.minY,hull.minZ,hull.maxX,hull.maxY,hull.maxZ);
  683. if (!hullBox.collideOrientedBox(radii,toItr))
  684. // oriented bounding boxes don't intersect...
  685. continue;
  686. // test for static mesh removal...
  687. if(hull.staticMesh && Interior::smLightingBuildPolyList)
  688. continue;
  689. for (S32 j=0; j<hull.surfaceCount; j++)
  690. {
  691. U32 surfaceIndex = mHullSurfaceIndices[j+hull.surfaceStart];
  692. if (isNullSurfaceIndex(surfaceIndex))
  693. {
  694. // Is a NULL surface
  695. const Interior::NullSurface& rSurface = mNullSurfaces[getNullSurfaceIndex(surfaceIndex)];
  696. U32 array[32];
  697. list->begin(0, rSurface.planeIndex);
  698. for (U32 k = 0; k < rSurface.windingCount; k++)
  699. {
  700. array[k] = list->addPoint(mPoints[mWindings[rSurface.windingStart + k]].point);
  701. list->vertex(array[k]);
  702. }
  703. list->plane(getFlippedPlane(rSurface.planeIndex));
  704. list->end();
  705. }
  706. else
  707. {
  708. const Interior::Surface& rSurface = mSurfaces[surfaceIndex];
  709. U32 array[32];
  710. U32 fanVerts[32];
  711. U32 numVerts;
  712. collisionFanFromSurface(rSurface, fanVerts, &numVerts);
  713. list->begin(0, rSurface.planeIndex);
  714. for (U32 k = 0; k < numVerts; k++)
  715. {
  716. array[k] = list->addPoint(mPoints[fanVerts[k]].point);
  717. list->vertex(array[k]);
  718. }
  719. list->plane(getFlippedPlane(rSurface.planeIndex));
  720. list->end();
  721. }
  722. }
  723. }
  724. FrameAllocator::setWaterMark(waterMark);
  725. return !list->isEmpty();
  726. }
  727. //---------------------------------------------------------------------------------
  728. //-------------------------------------- Zone scan. Not really collision, but hey.
  729. //
  730. struct Edge
  731. {
  732. U16 p1;
  733. U16 p2;
  734. Edge(U16 o, U16 t) : p1(o), p2(t) { }
  735. };
  736. struct EdgeList
  737. {
  738. Vector<Point3F> points;
  739. Vector<Edge> edges;
  740. };
  741. void Interior::scanZoneNew(InteriorPolytope& polytope,
  742. U16* zones,
  743. U32* numZones)
  744. {
  745. PROFILE_START(InteriorScanZoneNew);
  746. // Submit the first volume of the poly tope to the bsp tree
  747. static InteriorPolytope::VolumeStack stack;
  748. stack.reserve(128);
  749. stack.setSize(1);
  750. stack.last().edgeList = polytope.mVolumeList[0].edgeList;
  751. stack.last().nodeIndex = 0;
  752. stack.last().popCount = 0;
  753. static Vector<U16> collPlanes;
  754. collPlanes.reserve(64);
  755. collPlanes.clear();
  756. while (stack.empty() == false)
  757. {
  758. InteriorPolytope::StackElement volume = stack.last();
  759. stack.pop_back();
  760. if (isBSPLeafIndex(volume.nodeIndex))
  761. {
  762. if (isBSPEmptyLeaf(volume.nodeIndex))
  763. {
  764. U16 zone = getBSPEmptyLeafZone(volume.nodeIndex);
  765. if (zone != 0x0FFF)
  766. {
  767. bool insert = true;
  768. for (U32 i = 0; i < *numZones; i++)
  769. {
  770. if (zones[i] == zone)
  771. {
  772. insert = false;
  773. break;
  774. }
  775. }
  776. if (insert)
  777. {
  778. zones[*numZones] = zone;
  779. (*numZones)++;
  780. }
  781. }
  782. }
  783. if (volume.popCount)
  784. for (U32 i = 0; i < volume.popCount; i++)
  785. collPlanes.pop_back();
  786. continue;
  787. }
  788. const IBSPNode& rNode = mBSPNodes[volume.nodeIndex];
  789. if ((rNode.terminalZone & U16(0x8000)) != 0)
  790. {
  791. // Hah! we don't need to search any further
  792. U16 zone = rNode.terminalZone & (~0x8000);
  793. if (zone != 0x7FFF && zone != 0x0FFF)
  794. {
  795. bool insert = true;
  796. for (U32 i = 0; i < *numZones; i++)
  797. {
  798. if (zones[i] == zone)
  799. {
  800. insert = false;
  801. break;
  802. }
  803. }
  804. if (insert)
  805. {
  806. zones[*numZones] = zone;
  807. (*numZones)++;
  808. }
  809. }
  810. if (volume.popCount)
  811. for (U32 i = 0; i < volume.popCount; i++)
  812. collPlanes.pop_back();
  813. continue;
  814. }
  815. // New front and back faces
  816. polytope.mFaceList.increment(2);
  817. InteriorPolytope::Face& frontFace = polytope.mFaceList.last();
  818. InteriorPolytope::Face& backFace = *(&frontFace - 1);
  819. backFace.original = frontFace.original = false;
  820. backFace.vertex = frontFace.vertex = 0;
  821. // New front and back volumes
  822. InteriorPolytope::StackElement frontVolume,backVolume;
  823. frontVolume.edgeList = backVolume.edgeList = -1;
  824. PlaneF plane = getFlippedPlane(rNode.planeIndex);
  825. S32 startVertex = polytope.mVertexList.size();
  826. // Test & clip all the edges
  827. S32 sideBase = ++polytope.sideCount << 1;
  828. AssertFatal(sideBase != 0, "Well, crap.");
  829. for (S32 i = volume.edgeList; i >= 0; i = polytope.mEdgeList[i].next)
  830. {
  831. // Copy into tmp first to avoid problems with the array.
  832. InteriorPolytope::Edge edge = polytope.mEdgeList[i];
  833. InteriorPolytope::Vertex& v0 = polytope.mVertexList[edge.vertex[0]];
  834. if (v0.side < sideBase)
  835. v0.side = sideBase + ((plane.distToPlane(v0.point) >= 0)? 0: 1);
  836. InteriorPolytope::Vertex& v1 = polytope.mVertexList[edge.vertex[1]];
  837. if (v1.side < sideBase)
  838. v1.side = sideBase + ((plane.distToPlane(v1.point) >= 0)? 0: 1);
  839. if (v0.side != v1.side)
  840. {
  841. S32 s = v0.side - sideBase;
  842. polytope.intersect(plane,v0.point,v1.point);
  843. // Split the edge into each volume
  844. polytope.mEdgeList.increment(2);
  845. InteriorPolytope::Edge& e0 = polytope.mEdgeList.last();
  846. e0.next = frontVolume.edgeList;
  847. frontVolume.edgeList = polytope.mEdgeList.size() - 1;
  848. InteriorPolytope::Edge& e1 = *(&e0 - 1);
  849. e1.next = backVolume.edgeList;
  850. backVolume.edgeList = frontVolume.edgeList - 1;
  851. e0.vertex[0] = edge.vertex[s];
  852. e1.vertex[0] = edge.vertex[s ^ 1];
  853. e0.vertex[1] = e1.vertex[1] = polytope.mVertexList.size() - 1;
  854. e0.face[0] = e1.face[0] = edge.face[0];
  855. e0.face[1] = e1.face[1] = edge.face[1];
  856. // Add new edges on the plane, one to each volume
  857. for (S32 f = 0; f < 2; f++)
  858. {
  859. InteriorPolytope::Face& face = polytope.mFaceList[edge.face[f]];
  860. if (face.vertex < startVertex)
  861. {
  862. face.vertex = polytope.mVertexList.size() - 1;
  863. }
  864. else
  865. {
  866. polytope.mEdgeList.increment(2);
  867. InteriorPolytope::Edge& e0 = polytope.mEdgeList.last();
  868. e0.next = frontVolume.edgeList;
  869. frontVolume.edgeList = polytope.mEdgeList.size() - 1;
  870. InteriorPolytope::Edge& e1 = *(&e0 - 1);
  871. e1.next = backVolume.edgeList;
  872. backVolume.edgeList = frontVolume.edgeList - 1;
  873. e1.vertex[0] = e0.vertex[0] = face.vertex;
  874. e1.vertex[1] = e0.vertex[1] = polytope.mVertexList.size() - 1;
  875. e1.face[0] = e0.face[0] = edge.face[f];
  876. e1.face[1] = polytope.mFaceList.size() - 1;
  877. e0.face[1] = e1.face[1] - 1;
  878. }
  879. }
  880. }
  881. else
  882. {
  883. if (v0.side == sideBase)
  884. {
  885. polytope.mEdgeList.push_back(edge);
  886. InteriorPolytope::Edge& ne = polytope.mEdgeList.last();
  887. ne.next = frontVolume.edgeList;
  888. frontVolume.edgeList = polytope.mEdgeList.size() - 1;
  889. }
  890. else
  891. {
  892. polytope.mEdgeList.push_back(edge);
  893. InteriorPolytope::Edge& ne = polytope.mEdgeList.last();
  894. ne.next = backVolume.edgeList;
  895. backVolume.edgeList = polytope.mEdgeList.size() - 1;
  896. }
  897. }
  898. }
  899. // Push the front and back nodes
  900. if (frontVolume.edgeList >= 0 && backVolume.edgeList >= 0)
  901. {
  902. collPlanes.push_back(rNode.planeIndex);
  903. frontVolume.nodeIndex = rNode.frontIndex;
  904. frontVolume.popCount = volume.popCount + 1;
  905. stack.push_back(frontVolume);
  906. backVolume.nodeIndex = rNode.backIndex;
  907. backVolume.popCount = 0;
  908. stack.push_back(backVolume);
  909. }
  910. else if (frontVolume.edgeList >= 0)
  911. {
  912. frontVolume.nodeIndex = rNode.frontIndex;
  913. frontVolume.popCount = volume.popCount;
  914. stack.push_back(frontVolume);
  915. }
  916. else if (backVolume.edgeList >= 0)
  917. {
  918. backVolume.nodeIndex = rNode.backIndex;
  919. backVolume.popCount = volume.popCount;
  920. stack.push_back(backVolume);
  921. }
  922. else
  923. {
  924. // Pop off our own planes...
  925. if (volume.popCount)
  926. for (U32 i = 0; i < volume.popCount; i++)
  927. collPlanes.pop_back();
  928. }
  929. }
  930. AssertFatal(collPlanes.size() == 0, "Unbalanced stack!");
  931. PROFILE_END();
  932. }
  933. void Interior::scanZone_r(const U32 node,
  934. const Point3F& center,
  935. const Point3F& axisx,
  936. const Point3F& axisy,
  937. const Point3F& axisz,
  938. U16* zones,
  939. U32* numZones)
  940. {
  941. if (isBSPLeafIndex(node) == false)
  942. {
  943. const IBSPNode& rNode = mBSPNodes[node];
  944. const PlaneF& rPlane = getPlane(rNode.planeIndex);
  945. PlaneF::Side side = rPlane.whichSideBox(center, axisx, axisy, axisz);
  946. if (planeIsFlipped(rNode.planeIndex))
  947. side = PlaneF::Side(-S32(side));
  948. switch (side)
  949. {
  950. case PlaneF::Front:
  951. scanZone_r(rNode.frontIndex, center, axisx, axisy, axisz, zones, numZones);
  952. break;
  953. case PlaneF::Back:
  954. scanZone_r(rNode.backIndex, center, axisx, axisy, axisz, zones, numZones);
  955. break;
  956. case PlaneF::On:
  957. scanZone_r(rNode.frontIndex, center, axisx, axisy, axisz, zones, numZones);
  958. scanZone_r(rNode.backIndex, center, axisx, axisy, axisz, zones, numZones);
  959. break;
  960. default:
  961. AssertFatal(false, "Misunderstood switchCode in Interior::zoneRay_r");
  962. }
  963. return;
  964. }
  965. if (isBSPEmptyLeaf(node))
  966. {
  967. U16 zone = getBSPEmptyLeafZone(node);
  968. if (zone != 0x0FFF)
  969. {
  970. for (U32 i = 0; i < *numZones; i++)
  971. {
  972. if (zones[i] == zone)
  973. return;
  974. }
  975. zones[*numZones] = zone;
  976. (*numZones)++;
  977. }
  978. }
  979. }
  980. bool Interior::scanZones(const Box3F& box,
  981. const MatrixF& transform,
  982. U16* zones,
  983. U32* numZones)
  984. {
  985. // We don't need an exact answer, so let's just blast a box through
  986. // the planes and see what we intersect. scanZoneNew is good if you
  987. // have an exact volume to clip.
  988. Point3F center;
  989. box.getCenter(&center);
  990. Point3F xRad((box.maxExtents.x - box.minExtents.x) * 0.5f, 0.0f, 0.0f);
  991. Point3F yRad(0.0f, (box.maxExtents.y - box.minExtents.y) * 0.5f, 0.0f);
  992. Point3F zRad(0.0f, 0.0f, (box.maxExtents.z - box.minExtents.z) * 0.5f);
  993. transform.mulP(center);
  994. transform.mulV(xRad);
  995. transform.mulV(yRad);
  996. transform.mulV(zRad);
  997. scanZone_r(0, center, xRad, yRad, zRad, zones, numZones);
  998. bool outsideToo = false;
  999. if (*numZones != 0)
  1000. {
  1001. for (U32 i = 0; i < *numZones; /**/)
  1002. {
  1003. if (zones[i])
  1004. {
  1005. i++;
  1006. continue;
  1007. }
  1008. outsideToo = true;
  1009. zones[i] = zones[(*numZones) - 1];
  1010. (*numZones)--;
  1011. }
  1012. }
  1013. else
  1014. {
  1015. // If it ain't in us, it's outside us.
  1016. outsideToo = true;
  1017. }
  1018. return outsideToo;
  1019. }
  1020. bool Interior::getIntersectingHulls(const Box3F& query, U16* hulls, U32* numHulls)
  1021. {
  1022. AssertFatal(*numHulls == 0, "Error, some stuff in the hull vector already!");
  1023. // This is paranoia, and I probably wouldn't do it if the tag was 32 bits, but
  1024. // a possible collision every 65k searches is just a little too small for comfort
  1025. // DMM
  1026. if (mSearchTag == 0)
  1027. {
  1028. for (U32 i = 0; i < mConvexHulls.size(); i++)
  1029. mConvexHulls[i].searchTag = 0;
  1030. mSearchTag = 1;
  1031. }
  1032. else
  1033. {
  1034. mSearchTag++;
  1035. }
  1036. F32 xBinSize = mBoundingBox.len_x() / F32(NumCoordBins);
  1037. F32 yBinSize = mBoundingBox.len_y() / F32(NumCoordBins);
  1038. F32 queryMinX = getMax(mBoundingBox.minExtents.x, query.minExtents.x);
  1039. F32 queryMinY = getMax(mBoundingBox.minExtents.y, query.minExtents.y);
  1040. F32 queryMaxX = getMin(mBoundingBox.maxExtents.x, query.maxExtents.x);
  1041. F32 queryMaxY = getMin(mBoundingBox.maxExtents.y, query.maxExtents.y);
  1042. S32 startX = S32(mFloor((queryMinX - mBoundingBox.minExtents.x) / xBinSize));
  1043. S32 endX = S32( mCeil((queryMaxX - mBoundingBox.minExtents.x) / xBinSize));
  1044. S32 startY = S32(mFloor((queryMinY - mBoundingBox.minExtents.y) / yBinSize));
  1045. S32 endY = S32( mCeil((queryMaxY - mBoundingBox.minExtents.y) / yBinSize));
  1046. AssertFatal(startX >= 0, "Error, bad startx");
  1047. AssertFatal(startY >= 0, "Error, bad starty");
  1048. AssertFatal(endX <= NumCoordBins, "Error, bad endX");
  1049. AssertFatal(endY <= NumCoordBins, "Error, bad endY");
  1050. // Handle non-debug case
  1051. startX = getMax(startX, 0);
  1052. endX = getMin(endX, NumCoordBins);
  1053. startY = getMax(startY, 0);
  1054. endY = getMin(endY, NumCoordBins);
  1055. for (S32 i = startX; i < endX; i++)
  1056. {
  1057. for (S32 j = startY; j < endY; j++)
  1058. {
  1059. const CoordBin& rBin = mCoordBins[i * NumCoordBins + j];
  1060. for (U32 k = rBin.binStart; k < rBin.binStart + rBin.binCount; k++)
  1061. {
  1062. U16 hullIndex = mCoordBinIndices[k];
  1063. ConvexHull& rHull = mConvexHulls[hullIndex];
  1064. // Don't check twice! (We're not Santa Claus.)
  1065. if (rHull.searchTag == mSearchTag)
  1066. continue;
  1067. rHull.searchTag = mSearchTag;
  1068. Box3F qb(rHull.minX, rHull.minY, rHull.minZ, rHull.maxX, rHull.maxY, rHull.maxZ);
  1069. if (query.isOverlapped(qb))
  1070. {
  1071. hulls[*numHulls] = hullIndex;
  1072. (*numHulls)++;
  1073. }
  1074. }
  1075. }
  1076. }
  1077. return *numHulls != 0;
  1078. }
  1079. bool Interior::getIntersectingVehicleHulls(const Box3F& query, U16* hulls, U32* numHulls)
  1080. {
  1081. AssertFatal(*numHulls == 0, "Error, some stuff in the hull vector already!");
  1082. for (U16 i = 0; i < mVehicleConvexHulls.size(); i++)
  1083. {
  1084. ConvexHull& rHull = mVehicleConvexHulls[i];
  1085. Box3F qb(rHull.minX, rHull.minY, rHull.minZ, rHull.maxX, rHull.maxY, rHull.maxZ);
  1086. if (query.isOverlapped(qb))
  1087. {
  1088. hulls[*numHulls] = i;
  1089. (*numHulls)++;
  1090. }
  1091. }
  1092. return *numHulls != 0;
  1093. }
  1094. //--------------------------------------------------------------------------
  1095. Box3F InteriorConvex::getBoundingBox() const
  1096. {
  1097. return getBoundingBox(mObject->getTransform(), mObject->getScale());
  1098. }
  1099. Box3F InteriorConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const
  1100. {
  1101. Box3F newBox = box;
  1102. newBox.minExtents.convolve(scale);
  1103. newBox.maxExtents.convolve(scale);
  1104. mat.mul(newBox);
  1105. return newBox;
  1106. }
  1107. Point3F InteriorConvex::support(const VectorF& v) const
  1108. {
  1109. FrameAllocatorMarker fam;
  1110. if (hullId >= 0)
  1111. {
  1112. AssertFatal(hullId < pInterior->mConvexHulls.size(), "Out of bounds hull!");
  1113. const Interior::ConvexHull& rHull = pInterior->mConvexHulls[hullId];
  1114. F32* pDots = (F32*)fam.alloc(sizeof(F32) * rHull.hullCount);
  1115. m_point3F_bulk_dot_indexed(&v.x,
  1116. &pInterior->mPoints[0].point.x,
  1117. rHull.hullCount,
  1118. sizeof(ItrPaddedPoint),
  1119. &pInterior->mHullIndices[rHull.hullStart],
  1120. pDots);
  1121. U32 index = 0;
  1122. for (U32 i = 1; i < rHull.hullCount; i++)
  1123. {
  1124. if (pDots[i] > pDots[index])
  1125. index = i;
  1126. }
  1127. return pInterior->mPoints[pInterior->mHullIndices[rHull.hullStart + index]].point;
  1128. }
  1129. else
  1130. {
  1131. S32 actualId = -(hullId + 1);
  1132. AssertFatal(actualId < pInterior->mVehicleConvexHulls.size(), "Out of bounds hull!");
  1133. const Interior::ConvexHull& rHull = pInterior->mVehicleConvexHulls[actualId];
  1134. F32* pDots = (F32*)fam.alloc(sizeof(F32) * rHull.hullCount);
  1135. m_point3F_bulk_dot_indexed(&v.x,
  1136. &pInterior->mVehiclePoints[0].point.x,
  1137. rHull.hullCount,
  1138. sizeof(ItrPaddedPoint),
  1139. &pInterior->mVehicleHullIndices[rHull.hullStart],
  1140. pDots);
  1141. U32 index = 0;
  1142. for (U32 i = 1; i < rHull.hullCount; i++)
  1143. {
  1144. if (pDots[i] > pDots[index])
  1145. index = i;
  1146. }
  1147. return pInterior->mVehiclePoints[pInterior->mVehicleHullIndices[rHull.hullStart + index]].point;
  1148. }
  1149. }
  1150. void InteriorConvex::getFeatures(const MatrixF& mat, const VectorF& n, ConvexFeature* cf)
  1151. {
  1152. S32 i;
  1153. cf->material = 0;
  1154. cf->object = mObject;
  1155. if (hullId >= 0)
  1156. {
  1157. // We find the support ourselves here since we want the index too...
  1158. const Interior::ConvexHull& rHull = pInterior->mConvexHulls[hullId];
  1159. U32 spIndex = 0;
  1160. F32 maxSp = mDot(pInterior->mPoints[pInterior->mHullIndices[rHull.hullStart + spIndex]].point, n);
  1161. for (i = 1; i < rHull.hullCount; i++)
  1162. {
  1163. U32 index = pInterior->mHullIndices[rHull.hullStart + i];
  1164. const Point3F& rPoint = pInterior->mPoints[index].point;
  1165. F32 dot = mDot(rPoint, n);
  1166. if (dot > maxSp)
  1167. {
  1168. spIndex = i;
  1169. maxSp = dot;
  1170. }
  1171. }
  1172. // Ok, now we have the support point, let's extract the emission string for this
  1173. // vertex...
  1174. U32 currPos = 0;
  1175. const U8* pString = &pInterior->mConvexHullEmitStrings[pInterior->mHullEmitStringIndices[rHull.hullStart + spIndex]];
  1176. FrameAllocatorMarker fam;
  1177. U32* pRemaps = (U32*)fam.alloc(256 * sizeof(U32));
  1178. // Ok, this is a piece of cake. Lets dump the points first...
  1179. U32 numPoints = pString[currPos++];
  1180. for (i = 0; i < numPoints; i++)
  1181. {
  1182. U32 index = pString[currPos++];
  1183. pRemaps[i] = cf->mVertexList.size();
  1184. cf->mVertexList.increment();
  1185. const Point3F& rPoint = pInterior->mPoints[pInterior->mHullIndices[rHull.hullStart + index]].point;
  1186. mat.mulP(rPoint, &cf->mVertexList.last());
  1187. }
  1188. // Then the edges...
  1189. U32 numEdges = pString[currPos++];
  1190. for (i = 0; i < numEdges; i++)
  1191. {
  1192. U32 index0 = pString[currPos++];
  1193. U32 index1 = pString[currPos++];
  1194. cf->mEdgeList.increment();
  1195. cf->mEdgeList.last().vertex[0] = pRemaps[index0];
  1196. cf->mEdgeList.last().vertex[1] = pRemaps[index1];
  1197. }
  1198. // Then the polys...
  1199. U32 numPolys = pString[currPos++];
  1200. for (i = 0; i < numPolys; i++)
  1201. {
  1202. U32 vertexCount = pString[currPos++];
  1203. U32 planeIndex = pString[currPos++];
  1204. U32 verts[3];
  1205. verts[0] = pString[currPos++];
  1206. verts[1] = pString[currPos++];
  1207. AssertFatal( verts[0] < numPoints, "InteriorConvex::getFeatures verts out of range" );
  1208. for (U32 j = 2; j < vertexCount; j++)
  1209. {
  1210. verts[2] = pString[currPos++];
  1211. // Emit this poly
  1212. cf->mFaceList.increment();
  1213. cf->mFaceList.last().normal = pInterior->getPlane(pInterior->mHullPlaneIndices[rHull.planeStart + planeIndex]);
  1214. AssertFatal( verts[1] < numPoints, "InteriorConvex::getFeatures verts out of range" );
  1215. AssertFatal( verts[2] < numPoints, "InteriorConvex::getFeatures verts out of range" );
  1216. cf->mFaceList.last().vertex[0] = pRemaps[verts[0]];
  1217. cf->mFaceList.last().vertex[1] = pRemaps[verts[1]];
  1218. cf->mFaceList.last().vertex[2] = pRemaps[verts[2]];
  1219. PlaneF plane(cf->mVertexList[pRemaps[verts[0]]],
  1220. cf->mVertexList[pRemaps[verts[1]]],
  1221. cf->mVertexList[pRemaps[verts[2]]]);
  1222. cf->mFaceList.last().normal = plane;
  1223. // Shift the fan over
  1224. verts[1] = verts[2];
  1225. }
  1226. }
  1227. }
  1228. else
  1229. {
  1230. S32 actualId = -(hullId + 1);
  1231. // We find the support ourselves here since we want the index too...
  1232. const Interior::ConvexHull& rHull = pInterior->mVehicleConvexHulls[actualId];
  1233. U32 spIndex = 0;
  1234. F32 maxSp = mDot(pInterior->mVehiclePoints[pInterior->mVehicleHullIndices[rHull.hullStart + spIndex]].point, n);
  1235. for (i = 1; i < rHull.hullCount; i++)
  1236. {
  1237. U32 index = pInterior->mVehicleHullIndices[rHull.hullStart + i];
  1238. const Point3F& rPoint = pInterior->mVehiclePoints[index].point;
  1239. F32 dot = mDot(rPoint, n);
  1240. if (dot > maxSp)
  1241. {
  1242. spIndex = i;
  1243. maxSp = dot;
  1244. }
  1245. }
  1246. // Ok, now we have the support point, let's extract the emission string for this
  1247. // vertex...
  1248. U32 currPos = 0;
  1249. const U8* pString = &pInterior->mVehicleConvexHullEmitStrings[
  1250. pInterior->mVehicleHullEmitStringIndices[rHull.hullStart + spIndex]
  1251. ];
  1252. FrameAllocatorMarker fam;
  1253. U32* pRemaps = (U32*)fam.alloc(256 * sizeof(U32));
  1254. // Ok, this is a piece of cake. Lets dump the points first...
  1255. U32 numPoints = pString[currPos++];
  1256. for (i = 0; i < numPoints; i++)
  1257. {
  1258. U32 index = pString[currPos++];
  1259. pRemaps[i] = cf->mVertexList.size();
  1260. cf->mVertexList.increment();
  1261. const Point3F& rPoint = pInterior->mVehiclePoints[pInterior->mVehicleHullIndices[rHull.hullStart + index]].point;
  1262. mat.mulP(rPoint, &cf->mVertexList.last());
  1263. }
  1264. // Then the edges...
  1265. U32 numEdges = pString[currPos++];
  1266. for (i = 0; i < numEdges; i++)
  1267. {
  1268. U32 index0 = pString[currPos++];
  1269. U32 index1 = pString[currPos++];
  1270. cf->mEdgeList.increment();
  1271. cf->mEdgeList.last().vertex[0] = pRemaps[index0];
  1272. cf->mEdgeList.last().vertex[1] = pRemaps[index1];
  1273. }
  1274. // Then the polys...
  1275. U32 numPolys = pString[currPos++];
  1276. for (i = 0; i < numPolys; i++)
  1277. {
  1278. U32 vertexCount = pString[currPos++];
  1279. U32 planeIndex = pString[currPos++];
  1280. U32 verts[3];
  1281. verts[0] = pString[currPos++];
  1282. verts[1] = pString[currPos++];
  1283. for (U32 j = 2; j < vertexCount; j++)
  1284. {
  1285. verts[2] = pString[currPos++];
  1286. // Emit this poly
  1287. cf->mFaceList.increment();
  1288. cf->mFaceList.last().vertex[0] = pRemaps[verts[0]];
  1289. cf->mFaceList.last().vertex[1] = pRemaps[verts[1]];
  1290. cf->mFaceList.last().vertex[2] = pRemaps[verts[2]];
  1291. cf->mFaceList.last().normal = pInterior->getPlane(planeIndex);
  1292. // Shift the fan over
  1293. verts[1] = verts[2];
  1294. }
  1295. }
  1296. }
  1297. }
  1298. void InteriorConvex::getPolyList(AbstractPolyList* list)
  1299. {
  1300. // Setup collision state data
  1301. {
  1302. list->setTransform(&mObject->getTransform(), mObject->getScale());
  1303. list->setObject(mObject);
  1304. }
  1305. if (hullId >= 0)
  1306. {
  1307. // Get our hull
  1308. const Interior::ConvexHull& rHull = pInterior->mConvexHulls[hullId];
  1309. // Build up the lists of points and strings
  1310. const U8* pString = &pInterior->mPolyListStrings[rHull.polyListStringStart];
  1311. U32 currPos = 0;
  1312. U32 numPlanes = pString[currPos++];
  1313. // It can happen that a hull has no collision surfaces. In that case, just bail out
  1314. // here...
  1315. if (numPlanes == 0)
  1316. return;
  1317. const U8* planeString = &pString[currPos];
  1318. currPos += numPlanes;
  1319. U32 numPoints = pString[currPos++] << 8;
  1320. numPoints |= pString[currPos++];
  1321. const U8* pointString = &pString[currPos];
  1322. currPos += numPoints;
  1323. U32 numSurfaces = pString[currPos++];
  1324. const U16* planeIndices = &pInterior->mPolyListPlanes[rHull.polyListPlaneStart];
  1325. const U32* pointIndices = &pInterior->mPolyListPoints[rHull.polyListPointStart];
  1326. //--------------------------------------
  1327. // At this point, currPos is pointing to the first surface in the string
  1328. //--------------------------------------
  1329. // First thing to do: build the interest mask, by seeing if the list is interested
  1330. // in our planes...
  1331. U8 interestMask = 0;
  1332. U32 remappedPlaneBase;
  1333. {
  1334. U16 planeIndex = planeIndices[0];
  1335. PlaneF plane = pInterior->getPlane(planeIndex);
  1336. if (Interior::planeIsFlipped(planeIndex))
  1337. plane.neg();
  1338. remappedPlaneBase = list->addPlane(plane);
  1339. if (list->isInterestedInPlane(remappedPlaneBase))
  1340. interestMask |= planeString[0];
  1341. for (U32 i = 1; i < numPlanes; i++)
  1342. {
  1343. planeIndex = planeIndices[i];
  1344. plane = pInterior->getPlane(planeIndex);
  1345. if (Interior::planeIsFlipped(planeIndex))
  1346. plane.neg();
  1347. list->addPlane(plane);
  1348. if (list->isInterestedInPlane(remappedPlaneBase + i))
  1349. interestMask |= planeString[i];
  1350. }
  1351. }
  1352. // Now, whip through the points, and build up the remap table, adding only
  1353. // those points that the list is interested in. Note that we use the frameAllocator
  1354. // to get enoughMemory to deal with the variable sized remap array
  1355. FrameAllocatorMarker fam;
  1356. U32* pointRemapTable = reinterpret_cast<U32*>(fam.alloc(numPoints * sizeof(U32)));
  1357. {
  1358. for (U32 i = 0; i < numPoints; i++)
  1359. {
  1360. if ((interestMask & pointString[i]) != 0)
  1361. {
  1362. const Point3F& rPoint = pInterior->mPoints[pointIndices[i]].point;
  1363. pointRemapTable[i] = list->addPoint(rPoint);
  1364. }
  1365. }
  1366. }
  1367. // Now, whip through the surfaces, checking to make sure that we're interested in
  1368. // that poly as we go. At this point, currPos should point to the first surface.
  1369. // The format of the surface string can be found in interior.cc, in the
  1370. // processHullPolyLists function
  1371. {
  1372. for (U32 i = 0; i < numSurfaces; i++)
  1373. {
  1374. U32 snPoints = pString[currPos++];
  1375. U32 sMask = pString[currPos++];
  1376. U32 sPlane = pString[currPos++];
  1377. if ((interestMask & sMask) != 0)
  1378. {
  1379. // Add the poly
  1380. //
  1381. list->begin(0, planeIndices[sPlane]);
  1382. for (U32 j = 0; j < snPoints; j++)
  1383. {
  1384. U16 remappedIndex = pString[currPos++] << 8;
  1385. remappedIndex |= pString[currPos++];
  1386. remappedIndex = pointRemapTable[remappedIndex];
  1387. list->vertex(remappedIndex);
  1388. }
  1389. list->plane(remappedPlaneBase + sPlane);
  1390. list->end();
  1391. }
  1392. else
  1393. {
  1394. // Superflous poly, just skip past the points
  1395. currPos += snPoints * 2;
  1396. }
  1397. }
  1398. }
  1399. }
  1400. else
  1401. {
  1402. S32 actualId = -(hullId + 1);
  1403. // Get our hull
  1404. const Interior::ConvexHull& rHull = pInterior->mVehicleConvexHulls[actualId];
  1405. // Build up the lists of points and strings
  1406. const U8* pString = &pInterior->mVehiclePolyListStrings[rHull.polyListStringStart];
  1407. U32 currPos = 0;
  1408. U32 numPlanes = pString[currPos++];
  1409. // It can happen that a hull has no collision surfaces. In that case, just bail out
  1410. // here...
  1411. if (numPlanes == 0)
  1412. return;
  1413. const U8* planeString = &pString[currPos];
  1414. currPos += numPlanes;
  1415. U32 numPoints = pString[currPos++] << 8;
  1416. numPoints |= pString[currPos++];
  1417. const U8* pointString = &pString[currPos];
  1418. currPos += numPoints;
  1419. U32 numSurfaces = pString[currPos++];
  1420. const U16* planeIndices = &pInterior->mVehiclePolyListPlanes[rHull.polyListPlaneStart];
  1421. const U32* pointIndices = &pInterior->mVehiclePolyListPoints[rHull.polyListPointStart];
  1422. //--------------------------------------
  1423. // At this point, currPos is pointing to the first surface in the string
  1424. //--------------------------------------
  1425. // First thing to do: build the interest mask, by seeing if the list is interested
  1426. // in our planes...
  1427. U8 interestMask = 0;
  1428. U32 remappedPlaneBase;
  1429. {
  1430. U16 planeIndex = planeIndices[0];
  1431. PlaneF plane = pInterior->getPlane(planeIndex);
  1432. if (Interior::planeIsFlipped(planeIndex))
  1433. plane.neg();
  1434. remappedPlaneBase = list->addPlane(plane);
  1435. if (list->isInterestedInPlane(remappedPlaneBase))
  1436. interestMask |= planeString[0];
  1437. for (U32 i = 1; i < numPlanes; i++)
  1438. {
  1439. planeIndex = planeIndices[i];
  1440. plane = pInterior->getPlane(planeIndex);
  1441. if (Interior::planeIsFlipped(planeIndex))
  1442. plane.neg();
  1443. list->addPlane(plane);
  1444. if (list->isInterestedInPlane(remappedPlaneBase + i))
  1445. interestMask |= planeString[i];
  1446. }
  1447. }
  1448. // Now, whip through the points, and build up the remap table, adding only
  1449. // those points that the list is interested in. Note that we use the frameAllocator
  1450. // to get enoughMemory to deal with the variable sized remap array
  1451. FrameAllocatorMarker fam;
  1452. U32* pointRemapTable = reinterpret_cast<U32*>(fam.alloc(numPoints * sizeof(U32)));
  1453. {
  1454. for (U32 i = 0; i < numPoints; i++)
  1455. {
  1456. if ((interestMask & pointString[i]) != 0)
  1457. {
  1458. const Point3F& rPoint = pInterior->mVehiclePoints[pointIndices[i]].point;
  1459. pointRemapTable[i] = list->addPoint(rPoint);
  1460. }
  1461. }
  1462. }
  1463. // Now, whip through the surfaces, checking to make sure that we're interested in
  1464. // that poly as we go. At this point, currPos should point to the first surface.
  1465. // The format of the surface string can be found in interior.cc, in the
  1466. // processHullPolyLists function
  1467. {
  1468. for (U32 i = 0; i < numSurfaces; i++)
  1469. {
  1470. U32 snPoints = pString[currPos++];
  1471. U32 sMask = pString[currPos++];
  1472. U32 sPlane = pString[currPos++];
  1473. if ((interestMask & sMask) != 0)
  1474. {
  1475. // Add the poly
  1476. //
  1477. list->begin(0, planeIndices[sPlane]);
  1478. for (U32 j = 0; j < snPoints; j++)
  1479. {
  1480. U16 remappedIndex = pString[currPos++] << 8;
  1481. remappedIndex |= pString[currPos++];
  1482. remappedIndex = pointRemapTable[remappedIndex];
  1483. list->vertex(remappedIndex);
  1484. }
  1485. list->plane(remappedPlaneBase + sPlane);
  1486. list->end();
  1487. }
  1488. else
  1489. {
  1490. // Superflous poly, just skip past the points
  1491. currPos += snPoints * 2;
  1492. }
  1493. }
  1494. }
  1495. }
  1496. }