collisionComponent.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  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 "T3D/components/collision/collisionComponent.h"
  23. #include "scene/sceneObject.h"
  24. #include "T3D/entity.h"
  25. #include "console/engineAPI.h"
  26. #include "T3D/trigger.h"
  27. #include "materials/baseMatInstance.h"
  28. #include "collision/extrudedPolyList.h"
  29. #include "opcode/Opcode.h"
  30. #include "opcode/Ice/IceAABB.h"
  31. #include "opcode/Ice/IcePoint.h"
  32. #include "opcode/OPC_AABBTree.h"
  33. #include "opcode/OPC_AABBCollider.h"
  34. #include "collision/clippedPolyList.h"
  35. static F32 sTractionDistance = 0.04f;
  36. IMPLEMENT_CONOBJECT(CollisionComponent);
  37. CollisionComponent::CollisionComponent() : Component()
  38. {
  39. mFriendlyName = "Collision Component";
  40. mComponentType = "Collision";
  41. mDescription = getDescriptionText("A stub component class that collision components should inherit from.");
  42. mBlockColliding = true;
  43. CollisionMoveMask = (TerrainObjectType | PlayerObjectType |
  44. StaticShapeObjectType | VehicleObjectType |
  45. VehicleBlockerObjectType | DynamicShapeObjectType | StaticObjectType | EntityObjectType | TriggerObjectType);
  46. mPhysicsRep = nullptr;
  47. mPhysicsWorld = nullptr;
  48. mTimeoutList = nullptr;
  49. }
  50. CollisionComponent::~CollisionComponent()
  51. {
  52. for (S32 i = 0; i < mFields.size(); ++i)
  53. {
  54. ComponentField &field = mFields[i];
  55. SAFE_DELETE_ARRAY(field.mFieldDescription);
  56. }
  57. SAFE_DELETE_ARRAY(mDescription);
  58. SAFE_DELETE(mPhysicsRep);
  59. }
  60. bool CollisionComponent::checkCollisions(const F32 travelTime, Point3F *velocity, Point3F start)
  61. {
  62. return false;
  63. }
  64. bool CollisionComponent::updateCollisions(F32 time, VectorF vector, VectorF velocity)
  65. {
  66. return false;
  67. }
  68. void CollisionComponent::updateWorkingCollisionSet(const U32 mask)
  69. {
  70. }
  71. void CollisionComponent::handleCollisionList( CollisionList &collisionList, VectorF velocity )
  72. {
  73. Collision bestCol;
  74. mCollisionList = collisionList;
  75. for (U32 i=0; i < collisionList.getCount(); ++i)
  76. {
  77. Collision& colCheck = collisionList[i];
  78. if (colCheck.object)
  79. {
  80. if (colCheck.object->getTypeMask() & PlayerObjectType)
  81. {
  82. handleCollision( colCheck, velocity );
  83. }
  84. else if (colCheck.object->getTypeMask() & TriggerObjectType)
  85. {
  86. // We've hit it's bounding box, that's close enough for triggers
  87. Trigger* pTrigger = static_cast<Trigger*>(colCheck.object);
  88. Component *comp = dynamic_cast<Component*>(this);
  89. pTrigger->potentialEnterObject(comp->getOwner());
  90. }
  91. else if (colCheck.object->getTypeMask() & DynamicShapeObjectType)
  92. {
  93. Con::printf("HIT A GENERICALLY DYNAMIC OBJECT");
  94. handleCollision(colCheck, velocity);
  95. }
  96. else if(colCheck.object->getTypeMask() & EntityObjectType)
  97. {
  98. Entity* ent = dynamic_cast<Entity*>(colCheck.object);
  99. if (ent)
  100. {
  101. CollisionComponent *colObjectInterface = ent->getComponent<CollisionComponent>();
  102. if (colObjectInterface)
  103. {
  104. //convert us to our component
  105. Component *thisComp = dynamic_cast<Component*>(this);
  106. if (thisComp)
  107. {
  108. colObjectInterface->onCollisionSignal.trigger(thisComp->getOwner());
  109. //TODO: properly do this
  110. Collision oppositeCol = colCheck;
  111. oppositeCol.object = thisComp->getOwner();
  112. colObjectInterface->handleCollision(oppositeCol, velocity);
  113. }
  114. }
  115. }
  116. }
  117. else
  118. {
  119. handleCollision(colCheck, velocity);
  120. }
  121. }
  122. }
  123. }
  124. void CollisionComponent::handleCollision( Collision &col, VectorF velocity )
  125. {
  126. if (col.object && (mContactInfo.contactObject == NULL ||
  127. col.object->getId() != mContactInfo.contactObject->getId()))
  128. {
  129. queueCollision(col.object, velocity - col.object->getVelocity());
  130. //do the callbacks to script for this collision
  131. Component *comp = dynamic_cast<Component*>(this);
  132. if (comp->isMethod("onCollision"))
  133. {
  134. S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
  135. Con::executef(comp, "onCollision", col.object, col.normal, col.point, matId, velocity);
  136. }
  137. if (comp->getOwner()->isMethod("onCollisionEvent"))
  138. {
  139. S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
  140. Con::executef(comp->getOwner(), "onCollisionEvent", col.object, col.normal, col.point, matId, velocity);
  141. }
  142. }
  143. }
  144. void CollisionComponent::handleCollisionNotifyList()
  145. {
  146. //special handling for any collision components we should notify that a collision happened.
  147. for (U32 i = 0; i < mCollisionNotifyList.size(); ++i)
  148. {
  149. //convert us to our component
  150. Component *thisComp = dynamic_cast<Component*>(this);
  151. if (thisComp)
  152. {
  153. mCollisionNotifyList[i]->onCollisionSignal.trigger(thisComp->getOwner());
  154. }
  155. }
  156. mCollisionNotifyList.clear();
  157. }
  158. Chunker<CollisionComponent::CollisionTimeout> sCollisionTimeoutChunker;
  159. CollisionComponent::CollisionTimeout* CollisionComponent::sFreeTimeoutList = 0;
  160. void CollisionComponent::queueCollision( SceneObject *obj, const VectorF &vec)
  161. {
  162. // Add object to list of collisions.
  163. SimTime time = Sim::getCurrentTime();
  164. S32 num = obj->getId();
  165. CollisionTimeout** adr = &mTimeoutList;
  166. CollisionTimeout* ptr = mTimeoutList;
  167. while (ptr)
  168. {
  169. if (ptr->objectNumber == num)
  170. {
  171. if (ptr->expireTime < time)
  172. {
  173. ptr->expireTime = time + CollisionTimeoutValue;
  174. ptr->object = obj;
  175. ptr->vector = vec;
  176. }
  177. return;
  178. }
  179. // Recover expired entries
  180. if (ptr->expireTime < time)
  181. {
  182. CollisionTimeout* cur = ptr;
  183. *adr = ptr->next;
  184. ptr = ptr->next;
  185. cur->next = sFreeTimeoutList;
  186. sFreeTimeoutList = cur;
  187. }
  188. else
  189. {
  190. adr = &ptr->next;
  191. ptr = ptr->next;
  192. }
  193. }
  194. // New entry for the object
  195. if (sFreeTimeoutList != NULL)
  196. {
  197. ptr = sFreeTimeoutList;
  198. sFreeTimeoutList = ptr->next;
  199. ptr->next = NULL;
  200. }
  201. else
  202. {
  203. ptr = sCollisionTimeoutChunker.alloc();
  204. }
  205. ptr->object = obj;
  206. ptr->objectNumber = obj->getId();
  207. ptr->vector = vec;
  208. ptr->expireTime = time + CollisionTimeoutValue;
  209. ptr->next = mTimeoutList;
  210. mTimeoutList = ptr;
  211. }
  212. bool CollisionComponent::checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale,
  213. Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList)
  214. {
  215. Point3F end = start + velocity * time;
  216. Point3F distance = end - start;
  217. Box3F scaledBox = objectBox;
  218. scaledBox.minExtents.convolve(objectScale);
  219. scaledBox.maxExtents.convolve(objectScale);
  220. if (mFabs(distance.x) < objectBox.len_x() &&
  221. mFabs(distance.y) < objectBox.len_y() &&
  222. mFabs(distance.z) < objectBox.len_z())
  223. {
  224. // We can potentially early out of this. If there are no polys in the clipped polylist at our
  225. // end position, then we can bail, and just set start = end;
  226. Box3F wBox = scaledBox;
  227. wBox.minExtents += end;
  228. wBox.maxExtents += end;
  229. static EarlyOutPolyList eaPolyList;
  230. eaPolyList.clear();
  231. eaPolyList.mNormal.set(0.0f, 0.0f, 0.0f);
  232. eaPolyList.mPlaneList.clear();
  233. eaPolyList.mPlaneList.setSize(6);
  234. eaPolyList.mPlaneList[0].set(wBox.minExtents,VectorF(-1.0f, 0.0f, 0.0f));
  235. eaPolyList.mPlaneList[1].set(wBox.maxExtents,VectorF(0.0f, 1.0f, 0.0f));
  236. eaPolyList.mPlaneList[2].set(wBox.maxExtents,VectorF(1.0f, 0.0f, 0.0f));
  237. eaPolyList.mPlaneList[3].set(wBox.minExtents,VectorF(0.0f, -1.0f, 0.0f));
  238. eaPolyList.mPlaneList[4].set(wBox.minExtents,VectorF(0.0f, 0.0f, -1.0f));
  239. eaPolyList.mPlaneList[5].set(wBox.maxExtents,VectorF(0.0f, 0.0f, 1.0f));
  240. // Build list from convex states here...
  241. CollisionWorkingList& rList = colWorkingList;
  242. CollisionWorkingList* pList = rList.wLink.mNext;
  243. while (pList != &rList)
  244. {
  245. Convex* pConvex = pList->mConvex;
  246. if (pConvex->getObject()->getTypeMask() & collisionMask)
  247. {
  248. Box3F convexBox = pConvex->getBoundingBox();
  249. if (wBox.isOverlapped(convexBox))
  250. {
  251. // No need to separate out the physical zones here, we want those
  252. // to cause a fallthrough as well...
  253. pConvex->getPolyList(&eaPolyList);
  254. }
  255. }
  256. pList = pList->wLink.mNext;
  257. }
  258. if (eaPolyList.isEmpty())
  259. {
  260. return true;
  261. }
  262. }
  263. return false;
  264. }
  265. Collision* CollisionComponent::getCollision(S32 col)
  266. {
  267. if(col < mCollisionList.getCount() && col >= 0)
  268. return &mCollisionList[col];
  269. else
  270. return NULL;
  271. }
  272. Point3F CollisionComponent::getContactNormal()
  273. {
  274. return mContactInfo.contactNormal;
  275. }
  276. bool CollisionComponent::hasContact()
  277. {
  278. if (mContactInfo.contactObject)
  279. return true;
  280. else
  281. return false;
  282. }
  283. S32 CollisionComponent::getCollisionCount()
  284. {
  285. return mCollisionList.getCount();
  286. }
  287. Point3F CollisionComponent::getCollisionNormal(S32 collisionIndex)
  288. {
  289. if (collisionIndex < 0 || mCollisionList.getCount() < collisionIndex)
  290. return Point3F::Zero;
  291. return mCollisionList[collisionIndex].normal;
  292. }
  293. F32 CollisionComponent::getCollisionAngle(S32 collisionIndex, Point3F upVector)
  294. {
  295. if (collisionIndex < 0 || mCollisionList.getCount() < collisionIndex)
  296. return 0.0f;
  297. return mRadToDeg(mAcos(mDot(mCollisionList[collisionIndex].normal, upVector)));
  298. }
  299. S32 CollisionComponent::getBestCollision(Point3F upVector)
  300. {
  301. S32 bestCollision = -1;
  302. F32 bestAngle = 360.f;
  303. S32 count = mCollisionList.getCount();
  304. for (U32 i = 0; i < count; ++i)
  305. {
  306. F32 angle = mRadToDeg(mAcos(mDot(mCollisionList[i].normal, upVector)));
  307. if (angle < bestAngle)
  308. {
  309. bestCollision = i;
  310. bestAngle = angle;
  311. }
  312. }
  313. return bestCollision;
  314. }
  315. F32 CollisionComponent::getBestCollisionAngle(VectorF upVector)
  316. {
  317. S32 bestCol = getBestCollision(upVector);
  318. if (bestCol == -1)
  319. return 0;
  320. return getCollisionAngle(bestCol, upVector);
  321. }
  322. //
  323. bool CollisionComponent::buildConvexOpcode(TSShapeInstance* sI, S32 dl, const Box3F &bounds, Convex *c, Convex *list)
  324. {
  325. AssertFatal(dl >= 0 && dl < sI->getShape()->details.size(), "TSShapeInstance::buildConvexOpcode");
  326. TSShape* shape = sI->getShape();
  327. const MatrixF &objMat = mOwner->getObjToWorld();
  328. const Point3F &objScale = mOwner->getScale();
  329. // get subshape and object detail
  330. const TSDetail * detail = &shape->details[dl];
  331. S32 ss = detail->subShapeNum;
  332. S32 od = detail->objectDetailNum;
  333. // nothing emitted yet...
  334. bool emitted = false;
  335. S32 start = shape->subShapeFirstObject[ss];
  336. S32 end = shape->subShapeNumObjects[ss] + start;
  337. if (start<end)
  338. {
  339. MatrixF initialMat = objMat;
  340. Point3F initialScale = objScale;
  341. // set up for first object's node
  342. MatrixF mat;
  343. MatrixF scaleMat(true);
  344. F32* p = scaleMat;
  345. p[0] = initialScale.x;
  346. p[5] = initialScale.y;
  347. p[10] = initialScale.z;
  348. const MatrixF * previousMat = &sI->mMeshObjects[start].getTransform();
  349. mat.mul(initialMat, scaleMat);
  350. mat.mul(*previousMat);
  351. // Update our bounding box...
  352. Box3F localBox = bounds;
  353. MatrixF otherMat = mat;
  354. otherMat.inverse();
  355. otherMat.mul(localBox);
  356. // run through objects and collide
  357. for (S32 i = start; i<end; i++)
  358. {
  359. TSShapeInstance::MeshObjectInstance * meshInstance = &sI->mMeshObjects[i];
  360. if (od >= meshInstance->object->numMeshes)
  361. continue;
  362. if (&meshInstance->getTransform() != previousMat)
  363. {
  364. // different node from before, set up for this node
  365. previousMat = &meshInstance->getTransform();
  366. if (previousMat != NULL)
  367. {
  368. mat.mul(initialMat, scaleMat);
  369. mat.mul(*previousMat);
  370. // Update our bounding box...
  371. otherMat = mat;
  372. otherMat.inverse();
  373. localBox = bounds;
  374. otherMat.mul(localBox);
  375. }
  376. }
  377. // collide... note we pass the original mech transform
  378. // here so that the convex data returned is in mesh space.
  379. TSMesh * mesh = meshInstance->getMesh(od);
  380. if (mesh && !meshInstance->forceHidden && meshInstance->visible > 0.01f && localBox.isOverlapped(mesh->getBounds()))
  381. emitted |= buildMeshOpcode(mesh, *previousMat, localBox, c, list);
  382. else
  383. emitted |= false;
  384. }
  385. }
  386. return emitted;
  387. }
  388. bool CollisionComponent::buildMeshOpcode(TSMesh *mesh, const MatrixF &meshToObjectMat,
  389. const Box3F &nodeBox, Convex *convex, Convex *list)
  390. {
  391. /*PROFILE_SCOPE(MeshCollider_buildConvexOpcode);
  392. // This is small... there is no win for preallocating it.
  393. Opcode::AABBCollider opCollider;
  394. opCollider.SetPrimitiveTests(true);
  395. // This isn't really needed within the AABBCollider as
  396. // we don't use temporal coherance... use a static to
  397. // remove the allocation overhead.
  398. static Opcode::AABBCache opCache;
  399. IceMaths::AABB opBox;
  400. opBox.SetMinMax(Point(nodeBox.minExtents.x, nodeBox.minExtents.y, nodeBox.minExtents.z),
  401. Point(nodeBox.maxExtents.x, nodeBox.maxExtents.y, nodeBox.maxExtents.z));
  402. Opcode::CollisionAABB opCBox(opBox);
  403. if (!opCollider.Collide(opCache, opCBox, *mesh->mOptTree))
  404. return false;
  405. U32 cnt = opCollider.GetNbTouchedPrimitives();
  406. const udword *idx = opCollider.GetTouchedPrimitives();
  407. Opcode::VertexPointers vp;
  408. for (S32 i = 0; i < cnt; i++)
  409. {
  410. // First, check our active convexes for a potential match (and clean things
  411. // up, too.)
  412. const U32 curIdx = idx[i];
  413. // See if the square already exists as part of the working set.
  414. bool gotMatch = false;
  415. CollisionWorkingList& wl = convex->getWorkingList();
  416. for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext)
  417. {
  418. if (itr->mConvex->getType() != TSPolysoupConvexType)
  419. continue;
  420. const MeshColliderPolysoupConvex *chunkc = static_cast<MeshColliderPolysoupConvex*>(itr->mConvex);
  421. if (chunkc->getObject() != mOwner)
  422. continue;
  423. if (chunkc->mesh != mesh)
  424. continue;
  425. if (chunkc->idx != curIdx)
  426. continue;
  427. // A match! Don't need to add it.
  428. gotMatch = true;
  429. break;
  430. }
  431. if (gotMatch)
  432. continue;
  433. // Get the triangle...
  434. mesh->mOptTree->GetMeshInterface()->GetTriangle(vp, idx[i]);
  435. Point3F a(vp.Vertex[0]->x, vp.Vertex[0]->y, vp.Vertex[0]->z);
  436. Point3F b(vp.Vertex[1]->x, vp.Vertex[1]->y, vp.Vertex[1]->z);
  437. Point3F c(vp.Vertex[2]->x, vp.Vertex[2]->y, vp.Vertex[2]->z);
  438. // Transform the result into object space!
  439. meshToObjectMat.mulP(a);
  440. meshToObjectMat.mulP(b);
  441. meshToObjectMat.mulP(c);
  442. //If we're not doing debug rendering on the client, then set up our convex list as normal
  443. PlaneF p(c, b, a);
  444. Point3F peak = ((a + b + c) / 3.0f) - (p * 0.15f);
  445. // Set up the convex...
  446. MeshColliderPolysoupConvex *cp = new MeshColliderPolysoupConvex();
  447. list->registerObject(cp);
  448. convex->addToWorkingList(cp);
  449. cp->mesh = mesh;
  450. cp->idx = curIdx;
  451. cp->mObject = mOwner;
  452. cp->normal = p;
  453. cp->verts[0] = a;
  454. cp->verts[1] = b;
  455. cp->verts[2] = c;
  456. cp->verts[3] = peak;
  457. // Update the bounding box.
  458. Box3F &bounds = cp->box;
  459. bounds.minExtents.set(F32_MAX, F32_MAX, F32_MAX);
  460. bounds.maxExtents.set(-F32_MAX, -F32_MAX, -F32_MAX);
  461. bounds.minExtents.setMin(a);
  462. bounds.minExtents.setMin(b);
  463. bounds.minExtents.setMin(c);
  464. bounds.minExtents.setMin(peak);
  465. bounds.maxExtents.setMax(a);
  466. bounds.maxExtents.setMax(b);
  467. bounds.maxExtents.setMax(c);
  468. bounds.maxExtents.setMax(peak);
  469. }
  470. return true;*/
  471. return false;
  472. }
  473. bool CollisionComponent::castRayOpcode(S32 dl, const Point3F & startPos, const Point3F & endPos, RayInfo *info)
  474. {
  475. // if dl==-1, nothing to do
  476. //if (dl == -1 || !getShapeInstance())
  477. return false;
  478. /*TSShape *shape = getShapeInstance()->getShape();
  479. AssertFatal(dl >= 0 && dl < shape->details.size(), "TSShapeInstance::castRayOpcode");
  480. info->t = 100.f;
  481. // get subshape and object detail
  482. const TSDetail * detail = &shape->details[dl];
  483. S32 ss = detail->subShapeNum;
  484. if (ss < 0)
  485. return false;
  486. S32 od = detail->objectDetailNum;
  487. // nothing emitted yet...
  488. bool emitted = false;
  489. const MatrixF* saveMat = NULL;
  490. S32 start = shape->subShapeFirstObject[ss];
  491. S32 end = shape->subShapeNumObjects[ss] + start;
  492. if (start<end)
  493. {
  494. MatrixF mat;
  495. const MatrixF * previousMat = &getShapeInstance()->mMeshObjects[start].getTransform();
  496. mat = *previousMat;
  497. mat.inverse();
  498. Point3F localStart, localEnd;
  499. mat.mulP(startPos, &localStart);
  500. mat.mulP(endPos, &localEnd);
  501. // run through objects and collide
  502. for (S32 i = start; i<end; i++)
  503. {
  504. TSShapeInstance::MeshObjectInstance * meshInstance = &getShapeInstance()->mMeshObjects[i];
  505. if (od >= meshInstance->object->numMeshes)
  506. continue;
  507. if (&meshInstance->getTransform() != previousMat)
  508. {
  509. // different node from before, set up for this node
  510. previousMat = &meshInstance->getTransform();
  511. if (previousMat != NULL)
  512. {
  513. mat = *previousMat;
  514. mat.inverse();
  515. mat.mulP(startPos, &localStart);
  516. mat.mulP(endPos, &localEnd);
  517. }
  518. }
  519. // collide...
  520. TSMesh * mesh = meshInstance->getMesh(od);
  521. if (mesh && !meshInstance->forceHidden && meshInstance->visible > 0.01f)
  522. {
  523. if (castRayMeshOpcode(mesh, localStart, localEnd, info, getShapeInstance()->mMaterialList))
  524. {
  525. saveMat = previousMat;
  526. emitted = true;
  527. }
  528. }
  529. }
  530. }
  531. if (emitted)
  532. {
  533. saveMat->mulV(info->normal);
  534. info->point = endPos - startPos;
  535. info->point *= info->t;
  536. info->point += startPos;
  537. }
  538. return emitted;*/
  539. }
  540. static Point3F texGenAxis[18] =
  541. {
  542. Point3F(0,0,1), Point3F(1,0,0), Point3F(0,-1,0),
  543. Point3F(0,0,-1), Point3F(1,0,0), Point3F(0,1,0),
  544. Point3F(1,0,0), Point3F(0,1,0), Point3F(0,0,1),
  545. Point3F(-1,0,0), Point3F(0,1,0), Point3F(0,0,-1),
  546. Point3F(0,1,0), Point3F(1,0,0), Point3F(0,0,1),
  547. Point3F(0,-1,0), Point3F(-1,0,0), Point3F(0,0,-1)
  548. };
  549. bool CollisionComponent::castRayMeshOpcode(TSMesh *mesh, const Point3F &s, const Point3F &e, RayInfo *info, TSMaterialList *materials)
  550. {
  551. Opcode::RayCollider ray;
  552. Opcode::CollisionFaces cfs;
  553. IceMaths::Point dir(e.x - s.x, e.y - s.y, e.z - s.z);
  554. const F32 rayLen = dir.Magnitude();
  555. IceMaths::Ray vec(Point(s.x, s.y, s.z), dir.Normalize());
  556. ray.SetDestination(&cfs);
  557. ray.SetFirstContact(false);
  558. ray.SetClosestHit(true);
  559. ray.SetPrimitiveTests(true);
  560. ray.SetCulling(true);
  561. ray.SetMaxDist(rayLen);
  562. AssertFatal(ray.ValidateSettings() == NULL, "invalid ray settings");
  563. // Do collision.
  564. bool safety = ray.Collide(vec, *mesh->mOptTree);
  565. AssertFatal(safety, "CollisionComponent::castRayOpcode - no good ray collide!");
  566. // If no hit, just skip out.
  567. if (cfs.GetNbFaces() == 0)
  568. return false;
  569. // Got a hit!
  570. AssertFatal(cfs.GetNbFaces() == 1, "bad");
  571. const Opcode::CollisionFace &face = cfs.GetFaces()[0];
  572. // If the cast was successful let's check if the t value is less than what we had
  573. // and toggle the collision boolean
  574. // Stupid t... i prefer coffee
  575. const F32 t = face.mDistance / rayLen;
  576. if (t < 0.0f || t > 1.0f)
  577. return false;
  578. if (t <= info->t)
  579. {
  580. info->t = t;
  581. // Calculate the normal.
  582. Opcode::VertexPointers vp;
  583. mesh->mOptTree->GetMeshInterface()->GetTriangle(vp, face.mFaceID);
  584. if (materials && vp.MatIdx >= 0 && vp.MatIdx < materials->size())
  585. info->material = materials->getMaterialInst(vp.MatIdx);
  586. // Get the two edges.
  587. IceMaths::Point baseVert = *vp.Vertex[0];
  588. IceMaths::Point a = *vp.Vertex[1] - baseVert;
  589. IceMaths::Point b = *vp.Vertex[2] - baseVert;
  590. IceMaths::Point n;
  591. n.Cross(a, b);
  592. n.Normalize();
  593. info->normal.set(n.x, n.y, n.z);
  594. // generate UV coordinate across mesh based on
  595. // matching normals, this isn't done by default and is
  596. // primarily of interest in matching a collision point to
  597. // either a GUI control coordinate or finding a hit pixel in texture space
  598. if (info->generateTexCoord)
  599. {
  600. baseVert = *vp.Vertex[0];
  601. a = *vp.Vertex[1];
  602. b = *vp.Vertex[2];
  603. Point3F facePoint = (1.0f - face.mU - face.mV) * Point3F(baseVert.x, baseVert.y, baseVert.z)
  604. + face.mU * Point3F(a.x, a.y, a.z) + face.mV * Point3F(b.x, b.y, b.z);
  605. U32 faces[1024];
  606. U32 numFaces = 0;
  607. for (U32 i = 0; i < mesh->mOptTree->GetMeshInterface()->GetNbTriangles(); i++)
  608. {
  609. if (i == face.mFaceID)
  610. {
  611. faces[numFaces++] = i;
  612. }
  613. else
  614. {
  615. IceMaths::Point n2;
  616. mesh->mOptTree->GetMeshInterface()->GetTriangle(vp, i);
  617. baseVert = *vp.Vertex[0];
  618. a = *vp.Vertex[1] - baseVert;
  619. b = *vp.Vertex[2] - baseVert;
  620. n2.Cross(a, b);
  621. n2.Normalize();
  622. F32 eps = .01f;
  623. if (mFabs(n.x - n2.x) < eps && mFabs(n.y - n2.y) < eps && mFabs(n.z - n2.z) < eps)
  624. {
  625. faces[numFaces++] = i;
  626. }
  627. }
  628. if (numFaces == 1024)
  629. {
  630. // too many faces in this collision mesh for UV generation
  631. return true;
  632. }
  633. }
  634. Point3F min(F32_MAX, F32_MAX, F32_MAX);
  635. Point3F max(-F32_MAX, -F32_MAX, -F32_MAX);
  636. for (U32 i = 0; i < numFaces; i++)
  637. {
  638. mesh->mOptTree->GetMeshInterface()->GetTriangle(vp, faces[i]);
  639. for (U32 j = 0; j < 3; j++)
  640. {
  641. a = *vp.Vertex[j];
  642. if (a.x < min.x)
  643. min.x = a.x;
  644. if (a.y < min.y)
  645. min.y = a.y;
  646. if (a.z < min.z)
  647. min.z = a.z;
  648. if (a.x > max.x)
  649. max.x = a.x;
  650. if (a.y > max.y)
  651. max.y = a.y;
  652. if (a.z > max.z)
  653. max.z = a.z;
  654. }
  655. }
  656. // slerp
  657. Point3F s = ((max - min) - (facePoint - min)) / (max - min);
  658. // compute axis
  659. S32 bestAxis = 0;
  660. F32 best = 0.f;
  661. for (U32 i = 0; i < 6; i++)
  662. {
  663. F32 dot = mDot(info->normal, texGenAxis[i * 3]);
  664. if (dot > best)
  665. {
  666. best = dot;
  667. bestAxis = i;
  668. }
  669. }
  670. Point3F xv = texGenAxis[bestAxis * 3 + 1];
  671. Point3F yv = texGenAxis[bestAxis * 3 + 2];
  672. S32 sv, tv;
  673. if (xv.x)
  674. sv = 0;
  675. else if (xv.y)
  676. sv = 1;
  677. else
  678. sv = 2;
  679. if (yv.x)
  680. tv = 0;
  681. else if (yv.y)
  682. tv = 1;
  683. else
  684. tv = 2;
  685. // handle coord translation
  686. if (bestAxis == 2 || bestAxis == 3)
  687. {
  688. S32 x = sv;
  689. sv = tv;
  690. tv = x;
  691. if (yv.z < 0)
  692. s[sv] = 1.f - s[sv];
  693. }
  694. if (bestAxis < 2)
  695. {
  696. if (yv.y < 0)
  697. s[sv] = 1.f - s[sv];
  698. }
  699. if (bestAxis > 3)
  700. {
  701. s[sv] = 1.f - s[sv];
  702. if (yv.z > 0)
  703. s[tv] = 1.f - s[tv];
  704. }
  705. // done!
  706. info->texCoord.set(s[sv], s[tv]);
  707. }
  708. return true;
  709. }
  710. return false;
  711. }