tsCollision.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730
  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 "ts/tsShapeInstance.h"
  24. #include "ts/tsMaterialList.h"
  25. #include "scene/sceneObject.h"
  26. #include "collision/convex.h"
  27. #include "collision/collision.h"
  28. #include "T3D/tsStatic.h" // TODO: We shouldn't have this dependancy!
  29. #include "T3D/physics/physicsPlugin.h"
  30. #include "T3D/physics/physicsCollision.h"
  31. #include "collision/concretePolyList.h"
  32. #include "collision/vertexPolyList.h"
  33. #include "platform/profiler.h"
  34. #include "opcode/Opcode.h"
  35. #include "opcode/Ice/IceAABB.h"
  36. #include "opcode/Ice/IcePoint.h"
  37. #include "opcode/OPC_AABBTree.h"
  38. #include "opcode/OPC_AABBCollider.h"
  39. static bool gOpcodeInitialized = false;
  40. //-------------------------------------------------------------------------------------
  41. // Collision methods
  42. //-------------------------------------------------------------------------------------
  43. bool TSShapeInstance::buildPolyList(AbstractPolyList * polyList, S32 dl)
  44. {
  45. // if dl==-1, nothing to do
  46. if (dl==-1)
  47. return false;
  48. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
  49. // get subshape and object detail
  50. const TSDetail * detail = &mShape->details[dl];
  51. S32 ss = detail->subShapeNum;
  52. S32 od = detail->objectDetailNum;
  53. // This detail does not have any geometry.
  54. if ( ss < 0 )
  55. return false;
  56. // nothing emitted yet...
  57. bool emitted = false;
  58. U32 surfaceKey = 0;
  59. S32 start = mShape->subShapeFirstObject[ss];
  60. S32 end = mShape->subShapeNumObjects[ss] + start;
  61. if (start<end)
  62. {
  63. MatrixF initialMat;
  64. Point3F initialScale;
  65. polyList->getTransform(&initialMat,&initialScale);
  66. // set up for first object's node
  67. MatrixF mat;
  68. MatrixF scaleMat(true);
  69. F32* p = scaleMat;
  70. p[0] = initialScale.x;
  71. p[5] = initialScale.y;
  72. p[10] = initialScale.z;
  73. const MatrixF *previousMat = &mMeshObjects[start].getTransform();
  74. mat.mul(initialMat,scaleMat);
  75. mat.mul(*previousMat);
  76. polyList->setTransform(&mat,Point3F(1, 1, 1));
  77. // run through objects and collide
  78. for (S32 i=start; i<end; i++)
  79. {
  80. MeshObjectInstance * mesh = &mMeshObjects[i];
  81. if (od >= mesh->object->numMeshes)
  82. continue;
  83. if (&mesh->getTransform() != previousMat)
  84. {
  85. // different node from before, set up for this node
  86. previousMat = &mesh->getTransform();
  87. if (previousMat != NULL)
  88. {
  89. mat.mul(initialMat,scaleMat);
  90. mat.mul(*previousMat);
  91. polyList->setTransform(&mat,Point3F(1, 1, 1));
  92. }
  93. }
  94. // collide...
  95. emitted |= mesh->buildPolyList(od,polyList,surfaceKey,mMaterialList);
  96. }
  97. // restore original transform...
  98. polyList->setTransform(&initialMat,initialScale);
  99. }
  100. return emitted;
  101. }
  102. bool TSShapeInstance::getFeatures(const MatrixF& mat, const Point3F& n, ConvexFeature* cf, S32 dl)
  103. {
  104. // if dl==-1, nothing to do
  105. if (dl==-1)
  106. return false;
  107. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
  108. // get subshape and object detail
  109. const TSDetail * detail = &mShape->details[dl];
  110. S32 ss = detail->subShapeNum;
  111. S32 od = detail->objectDetailNum;
  112. // nothing emitted yet...
  113. bool emitted = false;
  114. U32 surfaceKey = 0;
  115. S32 start = mShape->subShapeFirstObject[ss];
  116. S32 end = mShape->subShapeNumObjects[ss] + start;
  117. if (start<end)
  118. {
  119. MatrixF final;
  120. const MatrixF* previousMat = &mMeshObjects[start].getTransform();
  121. final.mul(mat, *previousMat);
  122. // run through objects and collide
  123. for (S32 i=start; i<end; i++)
  124. {
  125. MeshObjectInstance * mesh = &mMeshObjects[i];
  126. if (od >= mesh->object->numMeshes)
  127. continue;
  128. if (&mesh->getTransform() != previousMat)
  129. {
  130. previousMat = &mesh->getTransform();
  131. final.mul(mat, *previousMat);
  132. }
  133. emitted |= mesh->getFeatures(od, final, n, cf, surfaceKey);
  134. }
  135. }
  136. return emitted;
  137. }
  138. bool TSShapeInstance::castRay(const Point3F & a, const Point3F & b, RayInfo * rayInfo, S32 dl)
  139. {
  140. // if dl==-1, nothing to do
  141. if (dl==-1)
  142. return false;
  143. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::castRay");
  144. // get subshape and object detail
  145. const TSDetail * detail = &mShape->details[dl];
  146. S32 ss = detail->subShapeNum;
  147. S32 od = detail->objectDetailNum;
  148. // This detail has no geometry to hit.
  149. if ( ss < 0 )
  150. return false;
  151. S32 start = mShape->subShapeFirstObject[ss];
  152. S32 end = mShape->subShapeNumObjects[ss] + start;
  153. RayInfo saveRay;
  154. saveRay.t = 1.0f;
  155. const MatrixF * saveMat = NULL;
  156. bool found = false;
  157. if (start<end)
  158. {
  159. Point3F ta, tb;
  160. // set up for first object's node
  161. MatrixF mat;
  162. const MatrixF * previousMat = &mMeshObjects[start].getTransform();
  163. mat = *previousMat;
  164. mat.inverse();
  165. mat.mulP(a,&ta);
  166. mat.mulP(b,&tb);
  167. // run through objects and collide
  168. for (S32 i=start; i<end; i++)
  169. {
  170. MeshObjectInstance * mesh = &mMeshObjects[i];
  171. if (od >= mesh->object->numMeshes)
  172. continue;
  173. if (&mesh->getTransform() != previousMat)
  174. {
  175. // different node from before, set up for this node
  176. previousMat = &mesh->getTransform();
  177. if (previousMat != NULL)
  178. {
  179. mat = *previousMat;
  180. mat.inverse();
  181. mat.mulP(a,&ta);
  182. mat.mulP(b,&tb);
  183. }
  184. }
  185. // collide...
  186. if (mesh->castRay(od,ta,tb,rayInfo, mMaterialList))
  187. {
  188. if (!rayInfo)
  189. return true;
  190. if (rayInfo->t <= saveRay.t)
  191. {
  192. saveRay = *rayInfo;
  193. saveMat = previousMat;
  194. }
  195. found = true;
  196. }
  197. }
  198. }
  199. // collide with any skins for this detail level...
  200. // TODO: if ever...
  201. // finalize the deal...
  202. if (found)
  203. {
  204. *rayInfo = saveRay;
  205. saveMat->mulV(rayInfo->normal);
  206. rayInfo->point = b-a;
  207. rayInfo->point *= rayInfo->t;
  208. rayInfo->point += a;
  209. }
  210. return found;
  211. }
  212. bool TSShapeInstance::castRayRendered(const Point3F & a, const Point3F & b, RayInfo * rayInfo, S32 dl)
  213. {
  214. // if dl==-1, nothing to do
  215. if (dl==-1)
  216. return false;
  217. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::castRayRendered");
  218. // get subshape and object detail
  219. const TSDetail * detail = &mShape->details[dl];
  220. S32 ss = detail->subShapeNum;
  221. S32 od = detail->objectDetailNum;
  222. if ( ss == -1 )
  223. return false;
  224. S32 start = mShape->subShapeFirstObject[ss];
  225. S32 end = mShape->subShapeNumObjects[ss] + start;
  226. RayInfo saveRay;
  227. saveRay.t = 1.0f;
  228. const MatrixF * saveMat = NULL;
  229. bool found = false;
  230. if (start<end)
  231. {
  232. Point3F ta, tb;
  233. // set up for first object's node
  234. MatrixF mat;
  235. const MatrixF * previousMat = &mMeshObjects[start].getTransform();
  236. mat = *previousMat;
  237. mat.inverse();
  238. mat.mulP(a,&ta);
  239. mat.mulP(b,&tb);
  240. // run through objects and collide
  241. for (S32 i=start; i<end; i++)
  242. {
  243. MeshObjectInstance * mesh = &mMeshObjects[i];
  244. if (od >= mesh->object->numMeshes)
  245. continue;
  246. if (&mesh->getTransform() != previousMat)
  247. {
  248. // different node from before, set up for this node
  249. previousMat = &mesh->getTransform();
  250. if (previousMat != NULL)
  251. {
  252. mat = *previousMat;
  253. mat.inverse();
  254. mat.mulP(a,&ta);
  255. mat.mulP(b,&tb);
  256. }
  257. }
  258. // collide...
  259. if (mesh->castRayRendered(od,ta,tb,rayInfo, mMaterialList))
  260. {
  261. if (!rayInfo)
  262. return true;
  263. if (rayInfo->t <= saveRay.t)
  264. {
  265. saveRay = *rayInfo;
  266. saveMat = previousMat;
  267. }
  268. found = true;
  269. }
  270. }
  271. }
  272. // collide with any skins for this detail level...
  273. // TODO: if ever...
  274. // finalize the deal...
  275. if (found)
  276. {
  277. *rayInfo = saveRay;
  278. saveMat->mulV(rayInfo->normal);
  279. rayInfo->point = b-a;
  280. rayInfo->point *= rayInfo->t;
  281. rayInfo->point += a;
  282. }
  283. return found;
  284. }
  285. Point3F TSShapeInstance::support(const Point3F & v, S32 dl)
  286. {
  287. // if dl==-1, nothing to do
  288. AssertFatal(dl != -1, "Error, should never try to collide with a non-existant detail level!");
  289. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::support");
  290. // get subshape and object detail
  291. const TSDetail * detail = &mShape->details[dl];
  292. S32 ss = detail->subShapeNum;
  293. S32 od = detail->objectDetailNum;
  294. S32 start = mShape->subShapeFirstObject[ss];
  295. S32 end = mShape->subShapeNumObjects[ss] + start;
  296. F32 currMaxDP = -1e9f;
  297. Point3F currSupport = Point3F(0, 0, 0);
  298. const MatrixF * previousMat = NULL;
  299. MatrixF mat;
  300. if (start<end)
  301. {
  302. Point3F va;
  303. // set up for first object's node
  304. previousMat = &mMeshObjects[start].getTransform();
  305. mat = *previousMat;
  306. mat.inverse();
  307. // run through objects and collide
  308. for (S32 i=start; i<end; i++)
  309. {
  310. MeshObjectInstance * mesh = &mMeshObjects[i];
  311. if (od >= mesh->object->numMeshes)
  312. continue;
  313. TSMesh* physMesh = mesh->getMesh(od);
  314. if (physMesh && !mesh->forceHidden && mesh->visible > 0.01f)
  315. {
  316. // collide...
  317. if (&mesh->getTransform() != previousMat)
  318. {
  319. // different node from before, set up for this node
  320. previousMat = &mesh->getTransform();
  321. mat = *previousMat;
  322. mat.inverse();
  323. }
  324. mat.mulV(v, &va);
  325. physMesh->support(mesh->frame, va, &currMaxDP, &currSupport);
  326. }
  327. }
  328. }
  329. if (currMaxDP != -1e9f)
  330. {
  331. previousMat->mulP(currSupport);
  332. return currSupport;
  333. }
  334. else
  335. {
  336. return Point3F(0, 0, 0);
  337. }
  338. }
  339. void TSShapeInstance::computeBounds(S32 dl, Box3F & bounds)
  340. {
  341. // if dl==-1, nothing to do
  342. if (dl==-1)
  343. return;
  344. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::computeBounds");
  345. // get subshape and object detail
  346. const TSDetail * detail = &mShape->details[dl];
  347. S32 ss = detail->subShapeNum;
  348. S32 od = detail->objectDetailNum;
  349. // use shape bounds for imposter details
  350. if (ss < 0)
  351. {
  352. bounds = mShape->mBounds;
  353. return;
  354. }
  355. S32 start = mShape->subShapeFirstObject[ss];
  356. S32 end = mShape->subShapeNumObjects[ss] + start;
  357. // run through objects and updating bounds as we go
  358. bounds.minExtents.set( 10E30f, 10E30f, 10E30f);
  359. bounds.maxExtents.set(-10E30f,-10E30f,-10E30f);
  360. Box3F box;
  361. for (S32 i=start; i<end; i++)
  362. {
  363. MeshObjectInstance * mesh = &mMeshObjects[i];
  364. if (od >= mesh->object->numMeshes)
  365. continue;
  366. if (mesh->getMesh(od))
  367. {
  368. mesh->getMesh(od)->computeBounds(mesh->getTransform(),box, 0); // use frame 0 so TSSkinMesh uses skinned verts to compute bounds
  369. bounds.minExtents.setMin(box.minExtents);
  370. bounds.maxExtents.setMax(box.maxExtents);
  371. }
  372. }
  373. }
  374. //-------------------------------------------------------------------------------------
  375. // Object (MeshObjectInstance & PluginObjectInstance) collision methods
  376. //-------------------------------------------------------------------------------------
  377. bool TSShapeInstance::ObjectInstance::buildPolyList(S32 objectDetail, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials )
  378. {
  379. TORQUE_UNUSED( objectDetail );
  380. TORQUE_UNUSED( polyList );
  381. TORQUE_UNUSED( surfaceKey );
  382. TORQUE_UNUSED( materials );
  383. AssertFatal(0,"TSShapeInstance::ObjectInstance::buildPolyList: no default method.");
  384. return false;
  385. }
  386. bool TSShapeInstance::ObjectInstance::getFeatures(S32 objectDetail, const MatrixF& mat, const Point3F& n, ConvexFeature* cf, U32& surfaceKey)
  387. {
  388. TORQUE_UNUSED( objectDetail );
  389. TORQUE_UNUSED( mat );
  390. TORQUE_UNUSED( n );
  391. TORQUE_UNUSED( cf );
  392. TORQUE_UNUSED( surfaceKey );
  393. AssertFatal(0,"TSShapeInstance::ObjectInstance::buildPolyList: no default method.");
  394. return false;
  395. }
  396. void TSShapeInstance::ObjectInstance::support(S32, const Point3F&, F32*, Point3F*)
  397. {
  398. AssertFatal(0,"TSShapeInstance::ObjectInstance::supprt: no default method.");
  399. }
  400. bool TSShapeInstance::ObjectInstance::castRay( S32 objectDetail, const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials )
  401. {
  402. TORQUE_UNUSED( objectDetail );
  403. TORQUE_UNUSED( start );
  404. TORQUE_UNUSED( end );
  405. TORQUE_UNUSED( rayInfo );
  406. AssertFatal(0,"TSShapeInstance::ObjectInstance::castRay: no default method.");
  407. return false;
  408. }
  409. bool TSShapeInstance::MeshObjectInstance::buildPolyList( S32 objectDetail, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials )
  410. {
  411. TSMesh * mesh = getMesh(objectDetail);
  412. if (mesh && !forceHidden && visible>0.01f)
  413. return mesh->buildPolyList(frame,polyList,surfaceKey,materials);
  414. return false;
  415. }
  416. bool TSShapeInstance::MeshObjectInstance::getFeatures(S32 objectDetail, const MatrixF& mat, const Point3F& n, ConvexFeature* cf, U32& surfaceKey)
  417. {
  418. TSMesh* mesh = getMesh(objectDetail);
  419. if (mesh && !forceHidden && visible > 0.01f)
  420. return mesh->getFeatures(frame, mat, n, cf, surfaceKey);
  421. return false;
  422. }
  423. void TSShapeInstance::MeshObjectInstance::support(S32 objectDetail, const Point3F& v, F32* currMaxDP, Point3F* currSupport)
  424. {
  425. TSMesh* mesh = getMesh(objectDetail);
  426. if (mesh && !forceHidden && visible > 0.01f)
  427. mesh->support(frame, v, currMaxDP, currSupport);
  428. }
  429. bool TSShapeInstance::MeshObjectInstance::castRay( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials )
  430. {
  431. TSMesh* mesh = getMesh( objectDetail );
  432. if( mesh && !forceHidden && visible > 0.01f )
  433. return mesh->castRay( frame, start, end, rayInfo, materials );
  434. return false;
  435. }
  436. bool TSShapeInstance::MeshObjectInstance::castRayRendered( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials )
  437. {
  438. TSMesh* mesh = getMesh( objectDetail );
  439. if( mesh && !forceHidden && visible > 0.01f )
  440. return mesh->castRayRendered( frame, start, end, rayInfo, materials );
  441. return false;
  442. }
  443. bool TSShapeInstance::ObjectInstance::castRayOpcode( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo *rayInfo, TSMaterialList* materials )
  444. {
  445. TORQUE_UNUSED( objectDetail );
  446. TORQUE_UNUSED( start );
  447. TORQUE_UNUSED( end );
  448. TORQUE_UNUSED( rayInfo );
  449. TORQUE_UNUSED( materials );
  450. return false;
  451. }
  452. bool TSShapeInstance::ObjectInstance::buildPolyListOpcode( S32 objectDetail, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials )
  453. {
  454. TORQUE_UNUSED( objectDetail );
  455. TORQUE_UNUSED( polyList );
  456. TORQUE_UNUSED( surfaceKey );
  457. TORQUE_UNUSED( materials );
  458. return false;
  459. }
  460. bool TSShapeInstance::ObjectInstance::buildConvexOpcode( const MatrixF &mat, S32 objectDetail, const Box3F &bounds, Convex *c, Convex *list )
  461. {
  462. TORQUE_UNUSED( mat );
  463. TORQUE_UNUSED( objectDetail );
  464. TORQUE_UNUSED( bounds );
  465. TORQUE_UNUSED( c );
  466. TORQUE_UNUSED( list );
  467. return false;
  468. }
  469. bool TSShapeInstance::MeshObjectInstance::castRayOpcode( S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo *info, TSMaterialList* materials )
  470. {
  471. TSMesh * mesh = getMesh(objectDetail);
  472. if (mesh && !forceHidden && visible>0.01f)
  473. return mesh->castRayOpcode(start, end, info, materials);
  474. return false;
  475. }
  476. bool TSShapeInstance::MeshObjectInstance::buildPolyListOpcode( S32 objectDetail, AbstractPolyList *polyList, const Box3F &box, TSMaterialList *materials )
  477. {
  478. TSMesh * mesh = getMesh(objectDetail);
  479. if ( mesh && !forceHidden && visible > 0.01f && box.isOverlapped( mesh->getBounds() ) )
  480. return mesh->buildPolyListOpcode(frame,polyList,box,materials);
  481. return false;
  482. }
  483. bool TSShapeInstance::MeshObjectInstance::buildConvexOpcode( const MatrixF &mat, S32 objectDetail, const Box3F &bounds, Convex *c, Convex *list)
  484. {
  485. TSMesh * mesh = getMesh(objectDetail);
  486. if ( mesh && !forceHidden && visible > 0.01f && bounds.isOverlapped( mesh->getBounds() ) )
  487. return mesh->buildConvexOpcode(mat, bounds, c, list);
  488. return false;
  489. }
  490. bool TSShapeInstance::buildPolyListOpcode( S32 dl, AbstractPolyList *polyList, const Box3F &box )
  491. {
  492. PROFILE_SCOPE( TSShapeInstance_buildPolyListOpcode_MeshObjInst );
  493. if (dl==-1)
  494. return false;
  495. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyListOpcode");
  496. // get subshape and object detail
  497. const TSDetail * detail = &mShape->details[dl];
  498. S32 ss = detail->subShapeNum;
  499. if ( ss < 0 )
  500. return false;
  501. S32 od = detail->objectDetailNum;
  502. // nothing emitted yet...
  503. bool emitted = false;
  504. S32 start = mShape->subShapeFirstObject[ss];
  505. S32 end = mShape->subShapeNumObjects[ss] + start;
  506. if (start<end)
  507. {
  508. MatrixF initialMat;
  509. Point3F initialScale;
  510. polyList->getTransform(&initialMat,&initialScale);
  511. // set up for first object's node
  512. MatrixF mat;
  513. MatrixF scaleMat(true);
  514. F32* p = scaleMat;
  515. p[0] = initialScale.x;
  516. p[5] = initialScale.y;
  517. p[10] = initialScale.z;
  518. const MatrixF * previousMat = &mMeshObjects[start].getTransform();
  519. mat.mul(initialMat,scaleMat);
  520. mat.mul(*previousMat);
  521. polyList->setTransform(&mat,Point3F(1, 1, 1));
  522. // Update our bounding box...
  523. Box3F localBox = box;
  524. MatrixF otherMat = mat;
  525. otherMat.inverse();
  526. otherMat.mul(localBox);
  527. // run through objects and collide
  528. for (S32 i=start; i<end; i++)
  529. {
  530. MeshObjectInstance * mesh = &mMeshObjects[i];
  531. if (od >= mesh->object->numMeshes)
  532. continue;
  533. if (&mesh->getTransform() != previousMat)
  534. {
  535. // different node from before, set up for this node
  536. previousMat = &mesh->getTransform();
  537. if (previousMat != NULL)
  538. {
  539. mat.mul(initialMat,scaleMat);
  540. mat.mul(*previousMat);
  541. polyList->setTransform(&mat,Point3F(1, 1, 1));
  542. // Update our bounding box...
  543. otherMat = mat;
  544. otherMat.inverse();
  545. localBox = box;
  546. otherMat.mul(localBox);
  547. }
  548. }
  549. // collide...
  550. emitted |= mesh->buildPolyListOpcode(od,polyList,localBox,mMaterialList);
  551. }
  552. // restore original transform...
  553. polyList->setTransform(&initialMat,initialScale);
  554. }
  555. return emitted;
  556. }
  557. bool TSShapeInstance::castRayOpcode( S32 dl, const Point3F & startPos, const Point3F & endPos, RayInfo *info)
  558. {
  559. // if dl==-1, nothing to do
  560. if (dl==-1)
  561. return false;
  562. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::castRayOpcode");
  563. info->t = 100.f;
  564. // get subshape and object detail
  565. const TSDetail * detail = &mShape->details[dl];
  566. S32 ss = detail->subShapeNum;
  567. if ( ss < 0 )
  568. return false;
  569. S32 od = detail->objectDetailNum;
  570. // nothing emitted yet...
  571. bool emitted = false;
  572. const MatrixF* saveMat = NULL;
  573. S32 start = mShape->subShapeFirstObject[ss];
  574. S32 end = mShape->subShapeNumObjects[ss] + start;
  575. if (start<end)
  576. {
  577. MatrixF mat;
  578. const MatrixF * previousMat = &mMeshObjects[start].getTransform();
  579. mat = *previousMat;
  580. mat.inverse();
  581. Point3F localStart, localEnd;
  582. mat.mulP(startPos, &localStart);
  583. mat.mulP(endPos, &localEnd);
  584. // run through objects and collide
  585. for (S32 i=start; i<end; i++)
  586. {
  587. MeshObjectInstance * mesh = &mMeshObjects[i];
  588. if (od >= mesh->object->numMeshes)
  589. continue;
  590. if (&mesh->getTransform() != previousMat)
  591. {
  592. // different node from before, set up for this node
  593. previousMat = &mesh->getTransform();
  594. if (previousMat != NULL)
  595. {
  596. mat = *previousMat;
  597. mat.inverse();
  598. mat.mulP(startPos, &localStart);
  599. mat.mulP(endPos, &localEnd);
  600. }
  601. }
  602. // collide...
  603. if ( mesh->castRayOpcode(od,localStart, localEnd, info, mMaterialList) )
  604. {
  605. saveMat = previousMat;
  606. emitted = true;
  607. }
  608. }
  609. }
  610. if ( emitted )
  611. {
  612. saveMat->mulV(info->normal);
  613. info->point = endPos - startPos;
  614. info->point *= info->t;
  615. info->point += startPos;
  616. }
  617. return emitted;
  618. }
  619. bool TSShapeInstance::buildConvexOpcode( const MatrixF &objMat, const Point3F &objScale, S32 dl, const Box3F &bounds, Convex *c, Convex *list )
  620. {
  621. AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildConvexOpcode");
  622. // get subshape and object detail
  623. const TSDetail * detail = &mShape->details[dl];
  624. S32 ss = detail->subShapeNum;
  625. S32 od = detail->objectDetailNum;
  626. // nothing emitted yet...
  627. bool emitted = false;
  628. S32 start = mShape->subShapeFirstObject[ss];
  629. S32 end = mShape->subShapeNumObjects[ss] + start;
  630. if (start<end)
  631. {
  632. MatrixF initialMat = objMat;
  633. Point3F initialScale = objScale;
  634. // set up for first object's node
  635. MatrixF mat;
  636. MatrixF scaleMat(true);
  637. F32* p = scaleMat;
  638. p[0] = initialScale.x;
  639. p[5] = initialScale.y;
  640. p[10] = initialScale.z;
  641. const MatrixF * previousMat = &mMeshObjects[start].getTransform();
  642. mat.mul(initialMat,scaleMat);
  643. mat.mul(*previousMat);
  644. // Update our bounding box...
  645. Box3F localBox = bounds;
  646. MatrixF otherMat = mat;
  647. otherMat.inverse();
  648. otherMat.mul(localBox);
  649. // run through objects and collide
  650. for (S32 i=start; i<end; i++)
  651. {
  652. MeshObjectInstance * mesh = &mMeshObjects[i];
  653. if (od >= mesh->object->numMeshes)
  654. continue;
  655. if (&mesh->getTransform() != previousMat)
  656. {
  657. // different node from before, set up for this node
  658. previousMat = &mesh->getTransform();
  659. if (previousMat != NULL)
  660. {
  661. mat.mul(initialMat,scaleMat);
  662. mat.mul(*previousMat);
  663. // Update our bounding box...
  664. otherMat = mat;
  665. otherMat.inverse();
  666. localBox = bounds;
  667. otherMat.mul(localBox);
  668. }
  669. }
  670. // collide... note we pass the original mech transform
  671. // here so that the convex data returned is in mesh space.
  672. emitted |= mesh->buildConvexOpcode(*previousMat,od,localBox,c, list);
  673. }
  674. }
  675. return emitted;
  676. }
  677. void TSShape::findColDetails( bool useVisibleMesh, Vector<S32> *outDetails, Vector<S32> *outLOSDetails, S32 specifiedLOD) const
  678. {
  679. PROFILE_SCOPE( TSShape_findColDetails );
  680. if ( useVisibleMesh || (specifiedLOD !=0))
  681. {
  682. // If we're using the visible mesh for collision then
  683. // find the highest detail and use that.
  684. U32 highestDetail = -1;
  685. F32 highestSize = -F32_MAX;
  686. for ( U32 i = 0; i < details.size(); i++ )
  687. {
  688. // Make sure we skip any details that shouldn't be rendered
  689. if ( details[i].size < 0 )
  690. continue;
  691. /*
  692. // Also make sure we skip any collision details with a size.
  693. const String &name = names[details[i].nameIndex];
  694. if ( dStrStartsWith( name, "Collision" ) ||
  695. dStrStartsWith( name, "LOS" ) )
  696. continue;
  697. */
  698. if (specifiedLOD != 0)
  699. {
  700. if (details[i].size == specifiedLOD)
  701. {
  702. highestDetail = i;
  703. highestSize = details[i].size;
  704. }
  705. }
  706. else
  707. {
  708. // Otherwise test against the current highest size
  709. if (details[i].size > highestSize)
  710. {
  711. highestDetail = i;
  712. highestSize = details[i].size;
  713. }
  714. }
  715. }
  716. // We use the same detail for both raycast and collisions.
  717. if ( highestDetail != -1 )
  718. {
  719. outDetails->push_back( highestDetail );
  720. if ( outLOSDetails )
  721. outLOSDetails->push_back( highestDetail );
  722. }
  723. return;
  724. }
  725. // Detail meshes starting with COL or LOS is considered
  726. // to be a collision mesh.
  727. //
  728. // The LOS (light of sight) details are used for raycasts.
  729. for ( U32 i = 0; i < details.size(); i++ )
  730. {
  731. const String &name = names[ details[i].nameIndex ];
  732. if ( !dStrStartsWith( name, "Collision" ) )
  733. continue;
  734. outDetails->push_back(i);
  735. // If we're not returning LOS details then skip out.
  736. if ( !outLOSDetails )
  737. continue;
  738. // The way LOS works is that it will check to see if there is a LOS detail that matches
  739. // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
  740. // the future). If it can't find a matching LOS it will simply use the collision instead.
  741. // We check for any "unmatched" LOS's further down.
  742. // Extract the detail number from the name.
  743. S32 number = 0;
  744. String::GetTrailingNumber( name, number );
  745. // Look for a matching LOS collision detail.
  746. //
  747. // TODO: Fix the old 9 detail offset which is there
  748. // because you cannot have two detail markers with
  749. // the same detail number.
  750. //
  751. const S32 LOSOverrideOffset = 9;
  752. String buff = String::ToString( "LOS-%d", mAbs( number ) + LOSOverrideOffset );
  753. S32 los = findDetail( buff );
  754. // If we didn't find the lod detail then use the
  755. // normal collision detail for LOS tests.
  756. if ( los == -1 )
  757. los = i;
  758. outLOSDetails->push_back( los );
  759. }
  760. // If we're not returning LOS details then skip out.
  761. if ( !outLOSDetails )
  762. return;
  763. // Snag any "unmatched" LOS details and put
  764. // them at the end of the list.
  765. for ( U32 i = 0; i < details.size(); i++ )
  766. {
  767. const String &name = names[ details[i].nameIndex ];
  768. if ( !dStrStartsWith( name, "LOS" ) )
  769. continue;
  770. // See if we already have this LOS
  771. bool found = false;
  772. for (U32 j = 0; j < outLOSDetails->size(); j++)
  773. {
  774. if ( (*outLOSDetails)[j] == i )
  775. {
  776. found = true;
  777. break;
  778. }
  779. }
  780. if ( !found )
  781. outLOSDetails->push_back(i);
  782. }
  783. }
  784. PhysicsCollision* TSShape::buildColShape( bool useVisibleMesh, const Point3F &scale )
  785. {
  786. return _buildColShapes( useVisibleMesh, scale, NULL, false );
  787. }
  788. void TSShape::buildColShapes( bool useVisibleMesh, const Point3F &scale, Vector< CollisionShapeInfo > *list )
  789. {
  790. _buildColShapes( useVisibleMesh, scale, list, true );
  791. }
  792. PhysicsCollision* TSShape::_buildColShapes( bool useVisibleMesh, const Point3F &scale, Vector< CollisionShapeInfo > *list, bool perMesh )
  793. {
  794. PROFILE_SCOPE( TSShape_buildColShapes );
  795. if ( !PHYSICSMGR )
  796. return NULL;
  797. PhysicsCollision *colShape = NULL;
  798. U32 surfaceKey = 0;
  799. if ( useVisibleMesh )
  800. {
  801. // Here we build triangle collision meshes from the
  802. // visible detail levels.
  803. // A negative subshape on the detail means we don't have geometry.
  804. const TSShape::Detail &detail = details[0];
  805. if ( detail.subShapeNum < 0 )
  806. return NULL;
  807. // We don't try to optimize the triangles we're given
  808. // and assume the art was created properly for collision.
  809. ConcretePolyList polyList;
  810. polyList.setTransform( &MatrixF::Identity, scale );
  811. // Create the collision meshes.
  812. S32 start = subShapeFirstObject[ detail.subShapeNum ];
  813. S32 end = start + subShapeNumObjects[ detail.subShapeNum ];
  814. for ( S32 o=start; o < end; o++ )
  815. {
  816. const TSShape::Object &object = objects[o];
  817. if ( detail.objectDetailNum >= object.numMeshes )
  818. continue;
  819. // No mesh or no verts.... nothing to do.
  820. TSMesh *mesh = meshes[ object.startMeshIndex + detail.objectDetailNum ];
  821. if ( !mesh || mesh->mNumVerts == 0 )
  822. continue;
  823. // Gather the mesh triangles.
  824. polyList.clear();
  825. mesh->buildPolyList( 0, &polyList, surfaceKey, NULL );
  826. // Create the collision shape if we haven't already.
  827. if ( !colShape )
  828. colShape = PHYSICSMGR->createCollision();
  829. // Get the object space mesh transform.
  830. MatrixF localXfm;
  831. getNodeWorldTransform( object.nodeIndex, &localXfm );
  832. colShape->addTriangleMesh( polyList.mVertexList.address(),
  833. polyList.mVertexList.size(),
  834. polyList.mIndexList.address(),
  835. polyList.mIndexList.size() / 3,
  836. localXfm );
  837. if ( perMesh )
  838. {
  839. list->increment();
  840. list->last().colNode = -1;
  841. list->last().colShape = colShape;
  842. colShape = NULL;
  843. }
  844. }
  845. // Return what we built... if anything.
  846. return colShape;
  847. }
  848. // Scan out the collision hulls...
  849. //
  850. // TODO: We need to support LOS collision for physics.
  851. //
  852. for ( U32 i = 0; i < details.size(); i++ )
  853. {
  854. const TSShape::Detail &detail = details[i];
  855. const String &name = names[detail.nameIndex];
  856. // Is this a valid collision detail.
  857. if ( !dStrStartsWith( name, "Collision" ) || detail.subShapeNum < 0 )
  858. continue;
  859. // Now go thru the meshes for this detail.
  860. S32 start = subShapeFirstObject[ detail.subShapeNum ];
  861. S32 end = start + subShapeNumObjects[ detail.subShapeNum ];
  862. if ( start >= end )
  863. continue;
  864. for ( S32 o=start; o < end; o++ )
  865. {
  866. const TSShape::Object &object = objects[o];
  867. const String &meshName = names[ object.nameIndex ];
  868. if ( object.numMeshes <= detail.objectDetailNum )
  869. continue;
  870. // No mesh, a flat bounds, or no verts.... nothing to do.
  871. TSMesh *mesh = meshes[ object.startMeshIndex + detail.objectDetailNum ];
  872. if ( !mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0 )
  873. continue;
  874. // We need the default mesh transform.
  875. MatrixF localXfm;
  876. getNodeWorldTransform( object.nodeIndex, &localXfm );
  877. Point3F nodeWorldPosition = localXfm.getPosition();
  878. nodeWorldPosition.convolve(scale);
  879. localXfm.setPosition(nodeWorldPosition);
  880. // We have some sort of collision shape... so allocate it.
  881. if ( !colShape )
  882. colShape = PHYSICSMGR->createCollision();
  883. // We have geometry... what is it?
  884. if ( dStrStartsWith( meshName, "Colbox" ) )
  885. {
  886. // The bounds define the box extents directly.
  887. Point3F halfWidth = mesh->getBounds().getExtents() * scale * 0.5f;
  888. // Add the offset to the center of the bounds
  889. // into the local space transform.
  890. MatrixF centerXfm( true );
  891. Point3F meshBoundsCenter = mesh->getBounds().getCenter();
  892. meshBoundsCenter.convolve(scale);
  893. centerXfm.setPosition(meshBoundsCenter);
  894. localXfm.mul( centerXfm );
  895. colShape->addBox( halfWidth, localXfm );
  896. }
  897. else if ( dStrStartsWith( meshName, "Colsphere" ) )
  898. {
  899. // Get a sphere inscribed to the bounds.
  900. Point3F extents = mesh->getBounds().getExtents() * scale;
  901. F32 radius = extents.least() * 0.5f;
  902. // Add the offset to the center of the bounds
  903. // into the local space transform.
  904. MatrixF primXfm( true );
  905. Point3F meshBoundsCenter = mesh->getBounds().getCenter();
  906. meshBoundsCenter.convolve(scale);
  907. primXfm.setPosition(meshBoundsCenter);
  908. localXfm.mul( primXfm );
  909. colShape->addSphere( radius, localXfm );
  910. }
  911. else if ( dStrStartsWith( meshName, "Colcapsule" ) )
  912. {
  913. // Use the smallest extent as the radius for the capsule.
  914. Point3F extents = mesh->getBounds().getExtents() * scale;
  915. F32 radius = extents.least() * 0.5f;
  916. // We need to center the capsule and align it to the Y axis.
  917. MatrixF primXfm( true );
  918. Point3F meshBoundsCenter = mesh->getBounds().getCenter();
  919. meshBoundsCenter.convolve(scale);
  920. primXfm.setPosition(meshBoundsCenter);
  921. // Use the longest axis as the capsule height.
  922. F32 height = -radius * 2.0f;
  923. if ( extents.x > extents.y && extents.x > extents.z )
  924. {
  925. primXfm.setColumn( 0, Point3F( 0, 0, 1 ) );
  926. primXfm.setColumn( 1, Point3F( 1, 0, 0 ) );
  927. primXfm.setColumn( 2, Point3F( 0, 1, 0 ) );
  928. height += extents.x;
  929. }
  930. else if ( extents.z > extents.x && extents.z > extents.y )
  931. {
  932. primXfm.setColumn( 0, Point3F( 0, 1, 0 ) );
  933. primXfm.setColumn( 1, Point3F( 0, 0, 1 ) );
  934. primXfm.setColumn( 2, Point3F( 1, 0, 0 ) );
  935. height += extents.z;
  936. }
  937. else
  938. height += extents.y;
  939. // Add the primitive transform into the local transform.
  940. localXfm.mul( primXfm );
  941. // If we didn't find a positive height then fallback to
  942. // creating a sphere which is better than nothing.
  943. if ( height > 0.0f )
  944. colShape->addCapsule( radius, height, localXfm );
  945. else
  946. colShape->addSphere( radius, localXfm );
  947. }
  948. else if ( dStrStartsWith( meshName, "Colmesh" ) )
  949. {
  950. // For a triangle mesh we gather the triangles raw from the
  951. // mesh and don't do any optimizations or cleanup.
  952. ConcretePolyList polyList;
  953. polyList.setTransform( &MatrixF::Identity, scale );
  954. mesh->buildPolyList( 0, &polyList, surfaceKey, NULL );
  955. colShape->addTriangleMesh( polyList.mVertexList.address(),
  956. polyList.mVertexList.size(),
  957. polyList.mIndexList.address(),
  958. polyList.mIndexList.size() / 3,
  959. localXfm );
  960. }
  961. else
  962. {
  963. // Any other mesh name we assume as a generic convex hull.
  964. //
  965. // Collect the verts using the vertex polylist which will
  966. // filter out duplicates. This is importaint as the convex
  967. // generators can sometimes fail with duplicate verts.
  968. //
  969. VertexPolyList polyList;
  970. MatrixF meshMat( localXfm );
  971. polyList.setTransform( &MatrixF::Identity, scale );
  972. mesh->buildPolyList( 0, &polyList, surfaceKey, NULL );
  973. colShape->addConvex( polyList.getVertexList().address(),
  974. polyList.getVertexList().size(),
  975. meshMat );
  976. }
  977. if ( perMesh )
  978. {
  979. list->increment();
  980. S32 detailNum;
  981. String::GetTrailingNumber( name, detailNum );
  982. String str = String::ToString( "%s%i", meshName.c_str(), detailNum );
  983. S32 found = findNode( str );
  984. if ( found == -1 )
  985. {
  986. str = str.replace('-','_');
  987. found = findNode( str );
  988. }
  989. list->last().colNode = found;
  990. list->last().colShape = colShape;
  991. colShape = NULL;
  992. }
  993. } // objects
  994. } // details
  995. return colShape;
  996. }
  997. bool TSMesh::buildPolyListOpcode( const S32 od, AbstractPolyList *polyList, const Box3F &nodeBox, TSMaterialList *materials )
  998. {
  999. PROFILE_SCOPE( TSMesh_buildPolyListOpcode );
  1000. // This is small... there is no win for preallocating it.
  1001. Opcode::AABBCollider opCollider;
  1002. opCollider.SetPrimitiveTests( true );
  1003. // This isn't really needed within the AABBCollider as
  1004. // we don't use temporal coherance... use a static to
  1005. // remove the allocation overhead.
  1006. static Opcode::AABBCache opCache;
  1007. IceMaths::AABB opBox;
  1008. opBox.SetMinMax( Point( nodeBox.minExtents.x, nodeBox.minExtents.y, nodeBox.minExtents.z ),
  1009. Point( nodeBox.maxExtents.x, nodeBox.maxExtents.y, nodeBox.maxExtents.z ) );
  1010. Opcode::CollisionAABB opCBox(opBox);
  1011. if ( !opCollider.Collide( opCache, opCBox, *mOptTree ) )
  1012. return false;
  1013. U32 count = opCollider.GetNbTouchedPrimitives();
  1014. const udword *idx = opCollider.GetTouchedPrimitives();
  1015. Opcode::VertexPointers vp;
  1016. U32 plIdx[3];
  1017. S32 j;
  1018. Point3F tmp;
  1019. const IceMaths::Point **verts;
  1020. const Opcode::MeshInterface *mi = mOptTree->GetMeshInterface();
  1021. for ( S32 i=0; i < count; i++ )
  1022. {
  1023. // Get the triangle...
  1024. mi->GetTriangle( vp, idx[i] );
  1025. verts = vp.Vertex;
  1026. // And register it in the polylist...
  1027. polyList->begin( NULL, i );
  1028. for( j = 2; j > -1; j-- )
  1029. {
  1030. tmp.set( verts[j]->x, verts[j]->y, verts[j]->z );
  1031. plIdx[j] = polyList->addPoint( tmp );
  1032. polyList->vertex( plIdx[j] );
  1033. }
  1034. polyList->plane( plIdx[0], plIdx[2], plIdx[1] );
  1035. polyList->end();
  1036. }
  1037. // TODO: Add a polyList->getCount() so we can see if we
  1038. // got clipped polys and didn't really emit anything.
  1039. return count > 0;
  1040. }
  1041. bool TSMesh::buildConvexOpcode( const MatrixF &meshToObjectMat, const Box3F &nodeBox, Convex *convex, Convex *list )
  1042. {
  1043. PROFILE_SCOPE( TSMesh_buildConvexOpcode );
  1044. // This is small... there is no win for preallocating it.
  1045. Opcode::AABBCollider opCollider;
  1046. opCollider.SetPrimitiveTests( true );
  1047. // This isn't really needed within the AABBCollider as
  1048. // we don't use temporal coherance... use a static to
  1049. // remove the allocation overhead.
  1050. static Opcode::AABBCache opCache;
  1051. IceMaths::AABB opBox;
  1052. opBox.SetMinMax( Point( nodeBox.minExtents.x, nodeBox.minExtents.y, nodeBox.minExtents.z ),
  1053. Point( nodeBox.maxExtents.x, nodeBox.maxExtents.y, nodeBox.maxExtents.z ) );
  1054. Opcode::CollisionAABB opCBox(opBox);
  1055. if( !opCollider.Collide( opCache, opCBox, *mOptTree ) )
  1056. return false;
  1057. U32 cnt = opCollider.GetNbTouchedPrimitives();
  1058. const udword *idx = opCollider.GetTouchedPrimitives();
  1059. Opcode::VertexPointers vp;
  1060. for ( S32 i = 0; i < cnt; i++ )
  1061. {
  1062. // First, check our active convexes for a potential match (and clean things
  1063. // up, too.)
  1064. const U32 curIdx = idx[i];
  1065. // See if the square already exists as part of the working set.
  1066. bool gotMatch = false;
  1067. CollisionWorkingList& wl = convex->getWorkingList();
  1068. for ( CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext )
  1069. {
  1070. if( itr->mConvex->getType() != TSPolysoupConvexType )
  1071. continue;
  1072. const TSStaticPolysoupConvex *chunkc = static_cast<TSStaticPolysoupConvex*>( itr->mConvex );
  1073. if( chunkc->getObject() != TSStaticPolysoupConvex::smCurObject )
  1074. continue;
  1075. if( chunkc->mesh != this )
  1076. continue;
  1077. if( chunkc->idx != curIdx )
  1078. continue;
  1079. // A match! Don't need to add it.
  1080. gotMatch = true;
  1081. break;
  1082. }
  1083. if( gotMatch )
  1084. continue;
  1085. // Get the triangle...
  1086. mOptTree->GetMeshInterface()->GetTriangle( vp, idx[i] );
  1087. Point3F a( vp.Vertex[0]->x, vp.Vertex[0]->y, vp.Vertex[0]->z );
  1088. Point3F b( vp.Vertex[1]->x, vp.Vertex[1]->y, vp.Vertex[1]->z );
  1089. Point3F c( vp.Vertex[2]->x, vp.Vertex[2]->y, vp.Vertex[2]->z );
  1090. // Transform the result into object space!
  1091. meshToObjectMat.mulP( a );
  1092. meshToObjectMat.mulP( b );
  1093. meshToObjectMat.mulP( c );
  1094. PlaneF p( c, b, a );
  1095. Point3F peak = ((a + b + c) / 3.0f) - (p * 0.15f);
  1096. // Set up the convex...
  1097. TSStaticPolysoupConvex *cp = new TSStaticPolysoupConvex();
  1098. list->registerObject( cp );
  1099. convex->addToWorkingList( cp );
  1100. cp->mesh = this;
  1101. cp->idx = curIdx;
  1102. cp->mObject = TSStaticPolysoupConvex::smCurObject;
  1103. cp->normal = p;
  1104. cp->verts[0] = a;
  1105. cp->verts[1] = b;
  1106. cp->verts[2] = c;
  1107. cp->verts[3] = peak;
  1108. // Update the bounding box.
  1109. Box3F &bounds = cp->box;
  1110. bounds.minExtents.set( F32_MAX, F32_MAX, F32_MAX );
  1111. bounds.maxExtents.set( -F32_MAX, -F32_MAX, -F32_MAX );
  1112. bounds.minExtents.setMin( a );
  1113. bounds.minExtents.setMin( b );
  1114. bounds.minExtents.setMin( c );
  1115. bounds.minExtents.setMin( peak );
  1116. bounds.maxExtents.setMax( a );
  1117. bounds.maxExtents.setMax( b );
  1118. bounds.maxExtents.setMax( c );
  1119. bounds.maxExtents.setMax( peak );
  1120. }
  1121. return true;
  1122. }
  1123. void TSMesh::prepOpcodeCollision()
  1124. {
  1125. // Make sure opcode is loaded!
  1126. if( !gOpcodeInitialized )
  1127. {
  1128. Opcode::InitOpcode();
  1129. gOpcodeInitialized = true;
  1130. }
  1131. // Don't re init if we already have something...
  1132. if ( mOptTree )
  1133. return;
  1134. // Ok, first set up a MeshInterface
  1135. Opcode::MeshInterface *mi = new Opcode::MeshInterface();
  1136. mOpMeshInterface = mi;
  1137. // Figure out how many triangles we have...
  1138. U32 triCount = 0;
  1139. const U32 base = 0;
  1140. for ( U32 i = 0; i < mPrimitives.size(); i++ )
  1141. {
  1142. TSDrawPrimitive & draw = mPrimitives[i];
  1143. const U32 start = draw.start;
  1144. AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" );
  1145. // gonna depend on what kind of primitive it is...
  1146. if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )
  1147. triCount += draw.numElements / 3;
  1148. else
  1149. {
  1150. // Have to walk the tristrip to get a count... may have degenerates
  1151. U32 idx0 = base + mIndices[start + 0];
  1152. U32 idx1;
  1153. U32 idx2 = base + mIndices[start + 1];
  1154. U32 * nextIdx = &idx1;
  1155. for ( S32 j = 2; j < draw.numElements; j++ )
  1156. {
  1157. *nextIdx = idx2;
  1158. // nextIdx = (j%2)==0 ? &idx0 : &idx1;
  1159. nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
  1160. idx2 = base + mIndices[start + j];
  1161. if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )
  1162. continue;
  1163. triCount++;
  1164. }
  1165. }
  1166. }
  1167. // Just do the first trilist for now.
  1168. mi->SetNbVertices( mVertexData.isReady() ? mNumVerts : mVerts.size() );
  1169. mi->SetNbTriangles( triCount );
  1170. // Stuff everything into appropriate arrays.
  1171. IceMaths::IndexedTriangle *its = new IceMaths::IndexedTriangle[ mi->GetNbTriangles() ], *curIts = its;
  1172. IceMaths::Point *pts = new IceMaths::Point[ mi->GetNbVertices() ];
  1173. mOpTris = its;
  1174. mOpPoints = pts;
  1175. // add the polys...
  1176. for ( U32 i = 0; i < mPrimitives.size(); i++ )
  1177. {
  1178. TSDrawPrimitive & draw = mPrimitives[i];
  1179. const U32 start = draw.start;
  1180. AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" );
  1181. const U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask;
  1182. // gonna depend on what kind of primitive it is...
  1183. if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )
  1184. {
  1185. for ( S32 j = 0; j < draw.numElements; )
  1186. {
  1187. curIts->mVRef[2] = base + mIndices[start + j + 0];
  1188. curIts->mVRef[1] = base + mIndices[start + j + 1];
  1189. curIts->mVRef[0] = base + mIndices[start + j + 2];
  1190. curIts->mMatIdx = matIndex;
  1191. curIts++;
  1192. j += 3;
  1193. }
  1194. }
  1195. else
  1196. {
  1197. AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::buildPolyList (2)" );
  1198. U32 idx0 = base + mIndices[start + 0];
  1199. U32 idx1;
  1200. U32 idx2 = base + mIndices[start + 1];
  1201. U32 * nextIdx = &idx1;
  1202. for ( S32 j = 2; j < draw.numElements; j++ )
  1203. {
  1204. *nextIdx = idx2;
  1205. // nextIdx = (j%2)==0 ? &idx0 : &idx1;
  1206. nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
  1207. idx2 = base + mIndices[start + j];
  1208. if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )
  1209. continue;
  1210. curIts->mVRef[2] = idx0;
  1211. curIts->mVRef[1] = idx1;
  1212. curIts->mVRef[0] = idx2;
  1213. curIts->mMatIdx = matIndex;
  1214. curIts++;
  1215. }
  1216. }
  1217. }
  1218. AssertFatal( (curIts - its) == mi->GetNbTriangles(), "Triangle count mismatch!" );
  1219. for( S32 i = 0; i < mi->GetNbVertices(); i++ )
  1220. {
  1221. if( mVertexData.isReady() )
  1222. {
  1223. const __TSMeshVertexBase &vertData = mVertexData.getBase(i);
  1224. pts[i].Set( vertData.vert().x, vertData.vert().y, vertData.vert().z );
  1225. }
  1226. else
  1227. {
  1228. pts[i].Set( mVerts[i].x, mVerts[i].y, mVerts[i].z );
  1229. }
  1230. }
  1231. mi->SetPointers( its, pts );
  1232. // Ok, we've got a mesh interface populated, now let's build a thingy to collide against.
  1233. mOptTree = new Opcode::Model();
  1234. Opcode::OPCODECREATE opcc;
  1235. opcc.mCanRemap = true;
  1236. opcc.mIMesh = mi;
  1237. opcc.mKeepOriginal = false;
  1238. opcc.mNoLeaf = false;
  1239. opcc.mQuantized = false;
  1240. opcc.mSettings.mLimit = 1;
  1241. mOptTree->Build( opcc );
  1242. }
  1243. static Point3F texGenAxis[18] =
  1244. {
  1245. Point3F(0,0,1), Point3F(1,0,0), Point3F(0,-1,0),
  1246. Point3F(0,0,-1), Point3F(1,0,0), Point3F(0,1,0),
  1247. Point3F(1,0,0), Point3F(0,1,0), Point3F(0,0,1),
  1248. Point3F(-1,0,0), Point3F(0,1,0), Point3F(0,0,-1),
  1249. Point3F(0,1,0), Point3F(1,0,0), Point3F(0,0,1),
  1250. Point3F(0,-1,0), Point3F(-1,0,0), Point3F(0,0,-1)
  1251. };
  1252. bool TSMesh::castRayOpcode( const Point3F &start, const Point3F &end, RayInfo *info, TSMaterialList *materials )
  1253. {
  1254. Opcode::RayCollider ray;
  1255. Opcode::CollisionFaces cfs;
  1256. IceMaths::Point dir(end.x - start.x, end.y - start.y, end.z - start.z );
  1257. const F32 rayLen = dir.Magnitude();
  1258. IceMaths::Ray vec( Point(start.x, start.y, start.z), dir.Normalize() );
  1259. ray.SetDestination( &cfs);
  1260. ray.SetFirstContact( false );
  1261. ray.SetClosestHit( true );
  1262. ray.SetPrimitiveTests( true );
  1263. ray.SetCulling( true );
  1264. ray.SetMaxDist( rayLen );
  1265. AssertFatal( ray.ValidateSettings() == NULL, "invalid ray settings" );
  1266. // Do collision.
  1267. bool safety = ray.Collide( vec, *mOptTree );
  1268. AssertFatal( safety, "TSMesh::castRayOpcode - no good ray collide!" );
  1269. // If no hit, just skip out.
  1270. if( cfs.GetNbFaces() == 0 )
  1271. return false;
  1272. // Got a hit!
  1273. AssertFatal( cfs.GetNbFaces() == 1, "bad" );
  1274. const Opcode::CollisionFace &face = cfs.GetFaces()[0];
  1275. // If the cast was successful let's check if the t value is less than what we had
  1276. // and toggle the collision boolean
  1277. // Stupid t... i prefer coffee
  1278. const F32 t = face.mDistance / rayLen;
  1279. if( t < 0.0f || t > 1.0f )
  1280. return false;
  1281. if( t <= info->t )
  1282. {
  1283. info->t = t;
  1284. // Calculate the normal.
  1285. Opcode::VertexPointers vp;
  1286. mOptTree->GetMeshInterface()->GetTriangle( vp, face.mFaceID );
  1287. if ( materials && vp.MatIdx >= 0 && vp.MatIdx < materials->size() )
  1288. info->material = materials->getMaterialInst( vp.MatIdx );
  1289. // Get the two edges.
  1290. IceMaths::Point baseVert = *vp.Vertex[0];
  1291. IceMaths::Point a = *vp.Vertex[1] - baseVert;
  1292. IceMaths::Point b = *vp.Vertex[2] - baseVert;
  1293. IceMaths::Point n;
  1294. n.Cross( a, b );
  1295. n.Normalize();
  1296. info->normal.set( n.x, n.y, n.z );
  1297. // generate UV coordinate across mesh based on
  1298. // matching normals, this isn't done by default and is
  1299. // primarily of interest in matching a collision point to
  1300. // either a GUI control coordinate or finding a hit pixel in texture space
  1301. if (info->generateTexCoord)
  1302. {
  1303. baseVert = *vp.Vertex[0];
  1304. a = *vp.Vertex[1];
  1305. b = *vp.Vertex[2];
  1306. Point3F facePoint = (1.0f - face.mU - face.mV) * Point3F(baseVert.x, baseVert.y, baseVert.z)
  1307. + face.mU * Point3F(a.x, a.y, a.z) + face.mV * Point3F(b.x, b.y, b.z);
  1308. U32 faces[1024];
  1309. U32 numFaces = 0;
  1310. for (U32 i = 0; i < mOptTree->GetMeshInterface()->GetNbTriangles(); i++)
  1311. {
  1312. if ( i == face.mFaceID )
  1313. {
  1314. faces[numFaces++] = i;
  1315. }
  1316. else
  1317. {
  1318. IceMaths::Point n2;
  1319. mOptTree->GetMeshInterface()->GetTriangle( vp, i );
  1320. baseVert = *vp.Vertex[0];
  1321. a = *vp.Vertex[1] - baseVert;
  1322. b = *vp.Vertex[2] - baseVert;
  1323. n2.Cross( a, b );
  1324. n2.Normalize();
  1325. F32 eps = .01f;
  1326. if ( mFabs(n.x - n2.x) < eps && mFabs(n.y - n2.y) < eps && mFabs(n.z - n2.z) < eps)
  1327. {
  1328. faces[numFaces++] = i;
  1329. }
  1330. }
  1331. if (numFaces == 1024)
  1332. {
  1333. // too many faces in this collision mesh for UV generation
  1334. return true;
  1335. }
  1336. }
  1337. Point3F min(F32_MAX, F32_MAX, F32_MAX);
  1338. Point3F max(-F32_MAX, -F32_MAX, -F32_MAX);
  1339. for (U32 i = 0; i < numFaces; i++)
  1340. {
  1341. mOptTree->GetMeshInterface()->GetTriangle( vp, faces[i] );
  1342. for ( U32 j =0; j < 3; j++)
  1343. {
  1344. a = *vp.Vertex[j];
  1345. if (a.x < min.x)
  1346. min.x = a.x;
  1347. if (a.y < min.y)
  1348. min.y = a.y;
  1349. if (a.z < min.z)
  1350. min.z = a.z;
  1351. if (a.x > max.x)
  1352. max.x = a.x;
  1353. if (a.y > max.y)
  1354. max.y = a.y;
  1355. if (a.z > max.z)
  1356. max.z = a.z;
  1357. }
  1358. }
  1359. // slerp
  1360. Point3F divSafe = (max - min);
  1361. if (divSafe.x == 0.0f) divSafe.x = POINT_EPSILON;
  1362. if (divSafe.y == 0.0f) divSafe.y = POINT_EPSILON;
  1363. if (divSafe.z == 0.0f) divSafe.z = POINT_EPSILON;
  1364. Point3F s = ( (max - min) - (facePoint - min) ) / divSafe;
  1365. // compute axis
  1366. S32 bestAxis = 0;
  1367. F32 best = 0.f;
  1368. for (U32 i = 0 ; i < 6 ; i++)
  1369. {
  1370. F32 dot = mDot (info->normal, texGenAxis[i*3]);
  1371. if (dot > best)
  1372. {
  1373. best = dot;
  1374. bestAxis = i;
  1375. }
  1376. }
  1377. Point3F xv = texGenAxis[bestAxis*3+1];
  1378. Point3F yv = texGenAxis[bestAxis*3+2];
  1379. S32 sv, tv;
  1380. if (xv.x)
  1381. sv = 0;
  1382. else if (xv.y)
  1383. sv = 1;
  1384. else
  1385. sv = 2;
  1386. if (yv.x)
  1387. tv = 0;
  1388. else if (yv.y)
  1389. tv = 1;
  1390. else
  1391. tv = 2;
  1392. // handle coord translation
  1393. if (bestAxis == 2 || bestAxis == 3)
  1394. {
  1395. S32 x = sv;
  1396. sv = tv;
  1397. tv = x;
  1398. if (yv.z < 0)
  1399. s[sv] = 1.f - s[sv];
  1400. }
  1401. if (bestAxis < 2)
  1402. {
  1403. if (yv.y < 0)
  1404. s[sv] = 1.f - s[sv];
  1405. }
  1406. if (bestAxis > 3)
  1407. {
  1408. s[sv] = 1.f - s[sv];
  1409. if (yv.z > 0)
  1410. s[tv] = 1.f - s[tv];
  1411. }
  1412. // done!
  1413. info->texCoord.set(s[sv], s[tv]);
  1414. }
  1415. return true;
  1416. }
  1417. return false;
  1418. }