CollisionVisitor.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. /***************************************************************************
  2. CollisionVisitor.cpp - description
  3. -------------------
  4. begin : Wed Jan 26 2000
  5. copyright : (C) 2000 by Henrik Enqvist
  6. email : henqvist@excite.com
  7. ***************************************************************************/
  8. #include "Private.h"
  9. #include "CollisionVisitor.h"
  10. #include "Group.h"
  11. #include "Behavior.h"
  12. #include "Shape3D.h"
  13. #include "CollisionBounds.h"
  14. #include "Polygon.h"
  15. #include "OctTree.h"
  16. #if EM_DEBUG
  17. int em_bounds = 0;
  18. int em_shapes = 0;
  19. int em_polygons = 0;
  20. int em_groups = 0;
  21. float em_bounds_m = 0;
  22. float em_shapes_m = 0;
  23. float em_polygons_m = 0;
  24. float em_groups_m = 0;
  25. #endif
  26. CollisionVisitor * CollisionVisitor::p_CollisionVisitor = NULL;
  27. CollisionVisitor * CollisionVisitor::getInstance() {
  28. if (p_CollisionVisitor == NULL) {
  29. p_CollisionVisitor = new CollisionVisitor();
  30. }
  31. return p_CollisionVisitor;
  32. }
  33. CollisionVisitor::CollisionVisitor() {
  34. //m_iPolygonsA = 0;
  35. //m_iPolygonsB = 0;
  36. // TODO: Some way to control the global octtree
  37. p_OctTree = new OctTree(1, 100);
  38. }
  39. CollisionVisitor::~CollisionVisitor() {
  40. p_CollisionVisitor = NULL;
  41. }
  42. void CollisionVisitor::visit(Group * g) {
  43. if (g->p_CollisionBounds == NULL) return;
  44. #if EM_DEBUG_COLLISION
  45. if (g->getShape3DSize() > 0) g->getShape3D(0)->setColor(1,1,1,0.3f);
  46. #endif
  47. // check collisions with nodes in octtree
  48. this->traverse(g, p_OctTree);
  49. // insert group into octtree
  50. p_OctTree->insertGroup(g);
  51. }
  52. /* Call this method each render loop. */
  53. void CollisionVisitor::empty() {
  54. #if EM_DEBUG
  55. em_bounds_m = em_bounds_m*0.7 + em_bounds*0.3;
  56. em_shapes_m = em_shapes_m*0.7 + em_shapes*0.3;
  57. em_polygons_m = em_polygons_m*0.7 + em_polygons*0.3;
  58. em_groups_m = em_groups_m*0.7 + em_groups*0.3;
  59. EM_COUT("CollisionVisitor::empty() groups " << em_groups, 0);
  60. EM_COUT("CollisionVisitor::empty() shapes " << em_shapes, 0);
  61. EM_COUT("CollisionVisitor::empty() bounds " << em_bounds, 0);
  62. EM_COUT("CollisionVisitor::empty() polys " << em_polygons, 0);
  63. em_bounds = 0;
  64. em_shapes = 0;
  65. em_polygons = 0;
  66. em_groups = 0;
  67. #endif
  68. // empty the octtree
  69. // p_OctTree->printTree();
  70. p_OctTree->clear();
  71. }
  72. void CollisionVisitor::traverse(Group * g, OctTree * octtree) {
  73. EmAssert(g != NULL, "OctTree::insestGroup() group NULL");
  74. EmAssert(g->p_CollisionBounds, "OctTree::insertGroup() collisionbounds NULL");
  75. if (!octtree->collide(g->p_CollisionBounds)) return;
  76. // collide this group with all groups in octtree node
  77. vector<Group*>::iterator groupIter = octtree->m_vGroup.begin();
  78. vector<Group*>::iterator groupEnd = octtree->m_vGroup.end();
  79. // collide group against all groups in octtree node
  80. for (; groupIter != groupEnd; groupIter++) {
  81. #if EM_DEBUG
  82. ++em_groups;
  83. #endif
  84. // groups in with same user properties are not collided
  85. // allows user to remove unnecessary collision detection
  86. if ((*groupIter)->m_iCollisionGroup == g->m_iCollisionGroup) {
  87. continue;
  88. }
  89. // no need to check if neither have a behavior object
  90. // if ((*groupIter)->m_vBehavior.size() == 0 && g->m_vBehavior.size() == 0) {
  91. // continue;
  92. // }
  93. if ((*groupIter)->getBehavior() == NULL && g->getBehavior() == NULL) {
  94. continue;
  95. }
  96. #if EM_DEBUG
  97. ++em_shapes;
  98. #endif
  99. Vertex3D vtxNml1 = { 0.0f, 0.0f, 0.0f };
  100. Vertex3D vtxNml2 = { 0.0f, 0.0f, 0.0f };
  101. // check collision
  102. if (!((*groupIter)->p_CollisionBounds->hasShape3D()) &&
  103. !(g->p_CollisionBounds->hasShape3D())) {
  104. // use fast sphere-sphere collision for bounds without polygons
  105. if (this->intersect((*groupIter)->p_CollisionBounds, g->p_CollisionBounds,
  106. vtxNml1, vtxNml2)) {
  107. EMath::normalizeVector(vtxNml1);
  108. EMath::normalizeVector(vtxNml2);
  109. this->notifyBehaviors((*groupIter), g, vtxNml1, vtxNml2);
  110. }
  111. } else if (!((*groupIter)->p_CollisionBounds->hasShape3D())) {
  112. // use fast sphere-poly collision for bounds without polygons
  113. m_vPolygon1.clear();
  114. if (this->detectCollisionEmpty((*groupIter)->p_CollisionBounds,
  115. g->p_CollisionBounds, vtxNml1)) {
  116. EMath::normalizeVector(vtxNml1);
  117. this->countNormal(vtxNml2, m_vPolygon1);
  118. this->notifyBehaviors((*groupIter), g, vtxNml1, vtxNml2);
  119. }
  120. } else if (!(g->p_CollisionBounds->hasShape3D())) {
  121. // use fast sphere-poly collision for bounds without polygons
  122. m_vPolygon1.clear();
  123. if (this->detectCollisionEmpty(g->p_CollisionBounds,
  124. (*groupIter)->p_CollisionBounds, vtxNml2)) {
  125. EMath::normalizeVector(vtxNml2);
  126. this->countNormal(vtxNml1, m_vPolygon1);
  127. this->notifyBehaviors((*groupIter), g, vtxNml1, vtxNml2);
  128. }
  129. } else {
  130. m_vPolygon1.clear();
  131. m_vPolygon2.clear();
  132. if (this->detectCollision((*groupIter)->p_CollisionBounds, g->p_CollisionBounds)) {
  133. this->countNormal(vtxNml1, m_vPolygon1);
  134. this->countNormal(vtxNml2, m_vPolygon2);
  135. this->notifyBehaviors((*groupIter), g, vtxNml1, vtxNml2);
  136. }
  137. }
  138. }
  139. // propagate the group to all the nodes
  140. if (octtree->m_vOctTree.size() > 0) {
  141. vector<OctTree*>::iterator iter = octtree->m_vOctTree.begin();
  142. vector<OctTree*>::iterator end = octtree->m_vOctTree.end();
  143. for ( ; iter != end; iter++) {
  144. this->traverse(g, (*iter));
  145. }
  146. }
  147. }
  148. void CollisionVisitor::notifyBehaviors(Group * g1, Group * g2,
  149. const Vertex3D & nml1, const Vertex3D & nml2) {
  150. // call all onCollision methods for behaviors in both groups
  151. // vector<Behavior*>::iterator behIter = g1->m_vBehavior.begin();
  152. // vector<Behavior*>::iterator behEnd = g1->m_vBehavior.end();
  153. // for(; behIter != behEnd; behIter++) {
  154. // (*behIter)->onCollision(nml2, nml1, g2);
  155. // }
  156. // behIter = g2->m_vBehavior.begin();
  157. // behEnd = g2->m_vBehavior.end();
  158. // for(; behIter != behEnd; behIter++) {
  159. // (*behIter)->onCollision(nml1, nml2, g1);
  160. // }
  161. if (g1->getBehavior() != NULL) {
  162. g1->getBehavior()->onCollision(nml2, nml1, g2);
  163. }
  164. if (g2->getBehavior() != NULL) {
  165. g2->getBehavior()->onCollision(nml1, nml2, g1);
  166. }
  167. }
  168. /*************************************************************
  169. * Intersect bounds
  170. ************************************************************/
  171. /* Returns true if the bounds of cb1 and cb2 intersects. */
  172. bool CollisionVisitor::intersect(CollisionBounds * cb1, CollisionBounds * cb2,
  173. Vertex3D & nml1, Vertex3D & nml2) {
  174. #if EM_DEBUG
  175. ++em_bounds;
  176. #endif
  177. float dx = cb2->m_vtxTrans.x - cb1->m_vtxTrans.x;
  178. float dy = cb2->m_vtxTrans.y - cb1->m_vtxTrans.y;
  179. float dz = cb2->m_vtxTrans.z - cb1->m_vtxTrans.z;
  180. float radius = cb1->m_fRadius + cb2->m_fRadius;
  181. if ((dx*dx + dy*dy + dz*dz) <= radius*radius) {
  182. nml1.x = dx;
  183. nml1.y = dy;
  184. nml1.z = dz;
  185. nml2.x = -dx;
  186. nml2.y = -dy;
  187. nml2.z = -dz;
  188. return true;
  189. }
  190. return false;
  191. }
  192. bool CollisionVisitor::intersect(CollisionBounds * cb1, CollisionBounds * cb2) {
  193. #if EM_DEBUG
  194. ++em_bounds;
  195. #endif
  196. float dx = cb2->m_vtxTrans.x - cb1->m_vtxTrans.x;
  197. float dy = cb2->m_vtxTrans.y - cb1->m_vtxTrans.y;
  198. float dz = cb2->m_vtxTrans.z - cb1->m_vtxTrans.z;
  199. float radius = cb1->m_fRadius + cb2->m_fRadius;
  200. if ((dx*dx + dy*dy + dz*dz) <= radius*radius) {
  201. return true;
  202. }
  203. return false;
  204. }
  205. /*****************************************************************
  206. * Detects collision between two CollisionBounds objects.
  207. * Recusively traverses the collision bounds.
  208. * If the boxes intersect, the shapes are detected for collision.
  209. * If there are no shape the function returns true.
  210. ****************************************************************/
  211. bool CollisionVisitor::detectCollision(CollisionBounds * cb1, CollisionBounds * cb2) {
  212. EM_COUT_D("CollisionVisitor::detectCollision()", 0);
  213. if (this->intersect(cb1, cb2)) {
  214. EM_COUT_D("CollisionVisitor::detectCollision() bounds collide", 0);
  215. // cb1 and cb2 is split up into more bounds collide all of them
  216. if (cb1->m_vCollisionBounds.size() > 0 && cb2->m_vCollisionBounds.size() > 0) {
  217. bool collision = false;
  218. vector<CollisionBounds*>::iterator iter1 = cb1->m_vCollisionBounds.begin();
  219. vector<CollisionBounds*>::iterator end1 = cb1->m_vCollisionBounds.end();
  220. for ( ; iter1 != end1; iter1++) {
  221. vector<CollisionBounds*>::iterator iter2 = cb2->m_vCollisionBounds.begin();
  222. vector<CollisionBounds*>::iterator end2 = cb2->m_vCollisionBounds.end();
  223. for ( ; iter2 != end2; iter2++) {
  224. if (this->detectCollision((*iter1), (*iter2))) {
  225. collision = true;
  226. }
  227. }
  228. }
  229. return collision;
  230. // cb1 is split up and cb2 is a leaf
  231. } else if (cb1->m_vCollisionBounds.size() > 0) {
  232. bool collision = false;
  233. vector<CollisionBounds*>::iterator iter = cb1->m_vCollisionBounds.begin();
  234. vector<CollisionBounds*>::iterator end = cb1->m_vCollisionBounds.end();
  235. for ( ; iter != end; iter++) {
  236. if (this->detectCollision((*iter), cb2)) {
  237. collision = true;
  238. }
  239. }
  240. return collision;
  241. // cb1 is a leaf and cb2 is split up
  242. } else if (cb2->m_vCollisionBounds.size() > 0) {
  243. bool collision = false;
  244. vector<CollisionBounds*>::iterator iter = cb2->m_vCollisionBounds.begin();
  245. vector<CollisionBounds*>::iterator end = cb2->m_vCollisionBounds.end();
  246. for ( ; iter != end; iter++) {
  247. if (this->detectCollision(cb1, (*iter))) {
  248. collision = true;
  249. }
  250. }
  251. return collision;
  252. // cb1 and cb2 are leaves
  253. } else {
  254. // poly-poly collision
  255. if (this->collidePolygons(cb1, cb2)) {
  256. return true;
  257. }
  258. EM_COUT_D("CollisionVisitor::detectCollision() false alarm", 0);
  259. }
  260. }
  261. return false;
  262. }
  263. /* Top level function. */
  264. bool CollisionVisitor::detectCollisionEmpty(CollisionBounds * cb1, CollisionBounds * cb2,
  265. Vertex3D & nml1) {
  266. float distsqr = -1.0f;
  267. return this->detectCollisionEmpty(cb1, cb2, nml1, distsqr);
  268. }
  269. /* The first bounds does not have a shape, uses sphere-polygon detection.
  270. * The 'distsqr' gives the distance to the nearest polygon found so far,
  271. * (distsqr < 0) if nothing found yet. */
  272. bool CollisionVisitor::detectCollisionEmpty(CollisionBounds * cb1, CollisionBounds * cb2,
  273. Vertex3D & nml1, float & distsqr) {
  274. EM_COUT_D("CollisionVisitor::detectCollisionEmpty", 0);
  275. if (this->intersect(cb1, cb2)) {
  276. // cb1 is a leaf and cb2 is split up
  277. if (cb2->m_vCollisionBounds.size() > 0) {
  278. bool collision = false;
  279. vector<CollisionBounds*>::iterator iter = cb2->m_vCollisionBounds.begin();
  280. vector<CollisionBounds*>::iterator end = cb2->m_vCollisionBounds.end();
  281. for ( ; iter != end; iter++) {
  282. if (this->detectCollisionEmpty(cb1, (*iter), nml1, distsqr)) {
  283. collision = true;
  284. }
  285. }
  286. return collision;
  287. // cb1 and cb2 are leaves
  288. } else {
  289. // sphere-poly collision
  290. bool collision = false;
  291. float radiussqr = cb1->m_fRadius*cb1->m_fRadius;
  292. //float distsqr = 9999.9f; // TODO MaxFloat
  293. vector<Polygon3D *>::iterator iter = cb2->m_vPolygon.begin();
  294. vector<Polygon3D *>::iterator end = cb2->m_vPolygon.end();
  295. Vertex3D vtxDist;
  296. for (; iter != end; ++iter) {
  297. float d = this->vtxPolySqrDist(cb1->m_vtxTrans, (*iter), vtxDist);
  298. if (d <= radiussqr) {
  299. collision = true;
  300. // skip if polygon already in vector
  301. {
  302. bool isin = false;
  303. vector<Polygon3D *>::iterator vectIter = m_vPolygon1.begin();
  304. vector<Polygon3D *>::iterator vectEnd = m_vPolygon1.end();
  305. isin = false;
  306. for (; vectIter != vectEnd; vectIter++) {
  307. if ((*vectIter) == (*iter)) {
  308. isin = true;
  309. break;
  310. }
  311. }
  312. if (!isin) {
  313. m_vPolygon1.push_back(*iter);
  314. }
  315. }
  316. // use only the closest polygon
  317. if (d < distsqr || distsqr < 0.0f) {
  318. distsqr = d;
  319. nml1.x = vtxDist.x;
  320. nml1.y = vtxDist.y;
  321. nml1.z = vtxDist.z;
  322. }
  323. }
  324. }
  325. if (collision) return true;
  326. EM_COUT_D("CollisionVisitor::detectCollision() false alarm", 0);
  327. }
  328. }
  329. return false;
  330. }
  331. /******************************************************************
  332. * Check if bounds nb1 and nb2 intersect. Use intersect() to see if polygons in
  333. * shapes intersect. Use a hashtable to check that we don't make
  334. * the same intersection test more than once, a polygon can reside
  335. * in more than one collision bound.
  336. *****************************************************************/
  337. bool CollisionVisitor::collidePolygons(CollisionBounds * nb1, CollisionBounds * nb2) {
  338. bool collision = false;
  339. vector<Polygon3D*>::iterator iter1 = nb1->m_vPolygon.begin();
  340. vector<Polygon3D*>::iterator end1 = nb1->m_vPolygon.end();
  341. for ( ; iter1 != end1; ++iter1) {
  342. // skip if polygon already in vector
  343. vector<Polygon3D*>::iterator vectIter = m_vPolygon1.begin();
  344. vector<Polygon3D*>::iterator vectEnd = m_vPolygon1.end();
  345. bool isin = false;
  346. for (; vectIter != vectEnd; ++vectIter) {
  347. if ((*vectIter) == (*iter1)) {
  348. isin = true;
  349. break;
  350. }
  351. }
  352. if (isin) continue;
  353. vector<Polygon3D*>::iterator iter2 = nb2->m_vPolygon.begin();
  354. vector<Polygon3D*>::iterator end2 = nb2->m_vPolygon.end();
  355. for ( ; iter2 != end2; ++iter2) {
  356. // skip if polygon already in vector
  357. vectIter = m_vPolygon2.begin();
  358. vectEnd = m_vPolygon2.end();
  359. isin = false;
  360. for (; vectIter != vectEnd; vectIter++) {
  361. if ((*vectIter) == (*iter2)) {
  362. isin = true;
  363. break;
  364. }
  365. }
  366. if (isin) continue;
  367. #if EM_DEBUG_COLLISION
  368. (*iter1)->setColor(0, 0, 1, 0.5f);
  369. (*iter2)->setColor(0, 0, 1, 0.5f);
  370. #endif
  371. if ( CollisionVisitor::intersect((*iter1), (*iter2)) ) {
  372. #if EM_DEBUG_COLLISION
  373. (*iter1)->setColor(1, 0, 0, 0.5f);
  374. (*iter2)->setColor(1, 0, 0, 0.5f);
  375. #endif
  376. m_vPolygon1.push_back(*iter1);
  377. m_vPolygon2.push_back(*iter2);
  378. collision = true;
  379. }
  380. }
  381. }
  382. return collision;
  383. }
  384. /* Count a median normal for all polygons */
  385. void CollisionVisitor::countNormal(Vertex3D & vtx, vector<Polygon3D*> vPolygon) {
  386. EM_COUT_D("CollisionVisitor::countNormal " << vPolygon.size() << " polygons" << endl, 0);
  387. vtx.x = 0;
  388. vtx.y = 0;
  389. vtx.z = 0;
  390. vector<Polygon3D*>::iterator iter = vPolygon.begin();
  391. vector<Polygon3D*>::iterator end = vPolygon.end();
  392. for (; iter != end; ++iter) {
  393. vtx.x += (*iter)->m_nmlTrans.x;
  394. vtx.y += (*iter)->m_nmlTrans.y;
  395. vtx.z += (*iter)->m_nmlTrans.z;
  396. }
  397. if ( EM_ZERO(vtx.x) &&
  398. EM_ZERO(vtx.y) &&
  399. EM_ZERO(vtx.z) ) {
  400. vtx.y = 1;
  401. }
  402. EMath::normalizeVector(vtx);
  403. }
  404. /* TODO: */
  405. bool CollisionVisitor::intersect2d(Polygon3D *, Polygon3D *) {
  406. // int axis = 1;
  407. // float nx = ABS(p1->vtxTrNormal.x);
  408. // float ny = ABS(p1->vtxTrNormal.y);
  409. // float nz = ABS(p1->vtxTrNormal.z);
  410. // find which axis is most suitable to project on
  411. // if (nx > ny) {
  412. // if (nx > nz) axis = 1;
  413. // else if (ny > nz) axis = 2;
  414. // else axis = 3;
  415. // }
  416. // else if (ny > nz) axis = 2;
  417. // else axis = 3;
  418. // for (int a=0; a<p1->iPolygonEdges-1; a++) {
  419. // }
  420. // cerr << "-2D-" << endl;
  421. return false;
  422. }
  423. /********************************************************
  424. * Some sphere-polygon stuff
  425. *******************************************************/
  426. float CollisionVisitor::vtxPolySqrDist(const Vertex3D & vtx, Polygon3D * poly, Vertex3D & vtxDist) {
  427. EmAssert(poly->m_vIndex.size() > 2, "CollisionVisitor::vtxPolySqrDist polygon has less than 3 vertices");
  428. float sqrdist = 9999.9f;
  429. Vertex3D vtxTmp = {0.0f, 1.0f, 0.0f};
  430. Shape3D * shape = poly->p_Shape3D;
  431. int aa = poly->m_vIndex.size()-2;
  432. for (int a=0; a < aa; ++a) {
  433. float tmp = this->vtxTriSqrDist(vtx,
  434. shape->m_vVtxTrans[poly->m_vIndex[0]],
  435. shape->m_vVtxTrans[poly->m_vIndex[a+1]],
  436. shape->m_vVtxTrans[poly->m_vIndex[a+2]],
  437. vtxTmp);
  438. if (tmp < sqrdist) {
  439. sqrdist = tmp;
  440. vtxDist = vtxTmp;
  441. }
  442. }
  443. return sqrdist;
  444. }
  445. /*************************************************************
  446. * Distance from vertex to Polygon
  447. *
  448. * I have no idea of how this works, just stole it somewhere.
  449. * Transform the triangle to a s-t plane. Transform so
  450. * that vtxTri0 is at 0,0, vtxTri1 to 1,0 and vtxTr2 to
  451. * 0,1 (or was it 1,0).
  452. *
  453. * t
  454. * region 2 ^
  455. * \ |
  456. * \|
  457. * |
  458. * region 3 |\ region 1
  459. * | \
  460. * | \
  461. * | 0 \
  462. * ----------->s
  463. * | \
  464. * region 4 | 5 \ region 6
  465. *************************************************************/
  466. float CollisionVisitor::vtxTriSqrDist(const Vertex3D & vtx, const Vertex3D & vtxTri0,
  467. const Vertex3D & vtxTri1, const Vertex3D & vtxTri2,
  468. Vertex3D & vtxOut) {
  469. Vertex3D vtxDiff, vtxE0, vtxE1;
  470. vtxDiff.x = vtxTri0.x - vtx.x;
  471. vtxDiff.y = vtxTri0.y - vtx.y;
  472. vtxDiff.z = vtxTri0.z - vtx.z;
  473. vtxE0.x = vtxTri1.x - vtxTri0.x;
  474. vtxE0.y = vtxTri1.y - vtxTri0.y;
  475. vtxE0.z = vtxTri1.z - vtxTri0.z;
  476. vtxE1.x = vtxTri2.x - vtxTri0.x;
  477. vtxE1.y = vtxTri2.y - vtxTri0.y;
  478. vtxE1.z = vtxTri2.z - vtxTri0.z;
  479. float a00 = EMath::vectorLengthSqr(vtxE0);
  480. float a01 = EMath::dotProduct(vtxE0, vtxE1);
  481. float a11 = EMath::vectorLengthSqr(vtxE1);
  482. float b0 = EMath::dotProduct(vtxDiff, vtxE0);
  483. float b1 = EMath::dotProduct(vtxDiff, vtxE1);
  484. float c = EMath::vectorLengthSqr(vtxDiff);
  485. float det = a00*a11 - a01*a01;
  486. det = EM_ABS(det);
  487. float s = a01*b1 - a11*b0;
  488. float t = a01*b0 - a00*b1;
  489. float sqrdist;
  490. if (s + t <= det) { // region 0, 3, 4, and 5
  491. if (s < 0.0f) {
  492. if (t < 0.0f) { // region 4
  493. if (b0 < 0.0f) {
  494. t = 0.0f;
  495. if (-b0 >= a00) {
  496. s = 1.0f;
  497. sqrdist = a00 + 2.0f*b0 + c;
  498. } else {
  499. // TODO fix division by zero thing
  500. s = -b0/a00;
  501. sqrdist = b0*s + c;
  502. }
  503. } else { // (b0 < 0.0f)
  504. s = 0.0f;
  505. if (b1 >= 0.0f) {
  506. t = 0.0f;
  507. sqrdist = c;
  508. } else if (-b0 >= a11) {
  509. t = 1.0f;
  510. sqrdist = a11 + 2.0f*b1 + c;
  511. } else {
  512. // TODO fix division by zero thing
  513. t = -b1/a11;
  514. sqrdist = b1*t + c;
  515. }
  516. }
  517. } else { // region 3
  518. s = 0.0f;
  519. if (b1 >= 0.0f) {
  520. t = 0.0f;
  521. sqrdist = c;
  522. } else if (-b1 >= a11) {
  523. t = 1.0f;
  524. sqrdist = a11 + 2.0*b1 + c;
  525. } else {
  526. // TODO fix division by zero thing
  527. t = -b1/a11;
  528. sqrdist = b1*t + c;
  529. }
  530. }
  531. } else if (t < 0.0f) { // region 5
  532. t = 0.0f;
  533. if (b0 >= 0.0f) {
  534. s = 0.0f;
  535. sqrdist = c;
  536. } else if (-b0 >= a00) {
  537. s = 1.0f;
  538. sqrdist = a00 + 2.0f*b0 + c;
  539. } else {
  540. // TODO fix division by zero thing
  541. s = -b0/a00;
  542. sqrdist = b0*s + c;
  543. }
  544. } else { // region 0
  545. float invdet = 1.0f/det;
  546. s *= invdet;
  547. t *= invdet;
  548. sqrdist = s*(a00*s + a01*t + 2.0f*b0) + t*(a01*s + a11*t + 2.0f*b1) + c;
  549. }
  550. } else { // region 1, 2, and 6
  551. float tmp0, tmp1, numer, denom;
  552. if (s < 0.0f) { // region 2
  553. tmp0 = a01 + b0;
  554. tmp1 = a11 + b1;
  555. if (tmp1 > tmp0) {
  556. numer = tmp1 - tmp0;
  557. denom = a00 - 2.0f*a01 + a11;
  558. if (numer >= denom) {
  559. s = 1.0f;
  560. t = 0.0f;
  561. sqrdist = a00 + 2.0f*b0 + c;
  562. } else {
  563. // TODO fix division with zero thing
  564. s = numer/denom;
  565. t = 1.0f - s;
  566. sqrdist = s*(a00*s + a01*t + 2.0f*b0) + t*(a01*s + a11*t + 2.0f*b1) + c;
  567. }
  568. } else {
  569. s = 0.0f;
  570. if (tmp1 <= 0.0f) {
  571. t = 1.0f;
  572. sqrdist = a11 + 2.0f*b1 + c;
  573. } else if (b1 >= 0.0f) {
  574. t = 0.0f;
  575. sqrdist = c;
  576. } else {
  577. // TODO fix division by zero thing
  578. t = -b1/a11;
  579. sqrdist = b1*t + c;
  580. }
  581. }
  582. } else if (t < 0.0f) { // region 6
  583. tmp0 = a01 + b1;
  584. tmp1 = a00 + b0;
  585. if (tmp1 > tmp0) {
  586. numer = tmp1 - tmp0;
  587. denom = a00 - 2.0f*a01 + a11;
  588. if (numer >= denom) {
  589. t = 1.0f;
  590. s = 0.0f;
  591. sqrdist = a11 + 2.0f*b1 + c;
  592. } else {
  593. // numer is greater than zero, denom is greater than denom => denom > 0.0f
  594. t = numer/denom;
  595. s = 1.0f - t;
  596. sqrdist = s*(a00*s + a01*t + 2.0f*b0) + t*(a01*s + a11*t + 2.0f*b1) + c;
  597. }
  598. } else {
  599. t = 0.0f;
  600. if (tmp1 <= 0.0f) {
  601. s = 1.0f;
  602. sqrdist = a00 + 2.0f*b0 + c;
  603. } else if (b0 >= 0.0f) {
  604. s = 0.0f;
  605. sqrdist = c;
  606. } else {
  607. // TODO
  608. s = -b0/a00;
  609. sqrdist = b0*s + c;
  610. }
  611. }
  612. } else { // region 1
  613. numer = a11 + b1 - a01 - b0;
  614. if (numer <= 0.0f) {
  615. s = 0.0f;
  616. t = 1.0f;
  617. sqrdist = a11 + 2.0f*b1 + c;
  618. } else {
  619. denom = a00 - 2.0f*a01 + a11;
  620. if (numer >= denom) {
  621. s = 1.0f;
  622. t = 0.0f;
  623. sqrdist = a00 + 2.0f*b0 + c;
  624. } else {
  625. // numer is greater than zero, denom is greater than denom => denom > 0.0f
  626. s = numer/denom;
  627. t = 1.0f - s;
  628. sqrdist = s*(a00*s + a01*t + 2.0f*b0) + t*(a01*s + a11*t + 2.0f*b1) + c;
  629. }
  630. }
  631. }
  632. }
  633. EMath::scaleVector(vtxE0, s);
  634. EMath::scaleVector(vtxE1, t);
  635. vtxOut.x = vtxDiff.x + vtxE0.x + vtxE1.x;
  636. vtxOut.y = vtxDiff.y + vtxE0.y + vtxE1.y;
  637. vtxOut.z = vtxDiff.z + vtxE0.z + vtxE1.z;
  638. return EM_ABS(sqrdist);
  639. }
  640. /****************************************************************
  641. * Polygon - polygon intersection.
  642. * Project intersection lines onto 1D and check if lines overlap.
  643. ***************************************************************/
  644. #define FINDLINE_X(A, B, C, D, xx, ss, iter, nextIter, begin, end) \
  645. for ( ; ; ++iter, ++nextIter ) { \
  646. if (iter == end) return false; \
  647. if (nextIter == end) nextIter = begin; \
  648. float dist1 = A * ss->m_vVtxTrans[(*iter)].x + B * ss->m_vVtxTrans[(*iter)].y + \
  649. C * ss->m_vVtxTrans[(*iter)].z + D; \
  650. float dist2 = A * ss->m_vVtxTrans[(*nextIter)].x + B * ss->m_vVtxTrans[(*nextIter)].y + \
  651. C * ss->m_vVtxTrans[(*nextIter)].z + D; \
  652. if (dist1*dist2 < 0) { \
  653. Vertex3D vtxA = ss->m_vVtxTrans[(*iter)]; \
  654. Vertex3D vtxB = ss->m_vVtxTrans[(*nextIter)]; \
  655. dist1 = EM_ABS(dist1); \
  656. dist2 = dist1 + EM_ABS(dist2); \
  657. float xDd = dist1/dist2; \
  658. float dx = vtxB.x - vtxA.x; \
  659. xx = vtxA.x + dx*xDd; \
  660. ++iter; ++nextIter; break; \
  661. } \
  662. }
  663. #define FINDLINE_Y(A, B, C, D, yy, ss, iter, nextIter, begin, end) \
  664. for ( ; ; ++iter, ++nextIter ) { \
  665. if (iter == end) return false; \
  666. if (nextIter == end) nextIter = begin; \
  667. float dist1 = A * ss->m_vVtxTrans[(*iter)].x + B * ss->m_vVtxTrans[(*iter)].y + \
  668. C * ss->m_vVtxTrans[(*iter)].z + D; \
  669. float dist2 = A * ss->m_vVtxTrans[(*nextIter)].x + B * ss->m_vVtxTrans[(*nextIter)].y + \
  670. C * ss->m_vVtxTrans[(*nextIter)].z + D; \
  671. if (dist1*dist2 < 0) { \
  672. Vertex3D vtxA = ss->m_vVtxTrans[(*iter)]; \
  673. Vertex3D vtxB = ss->m_vVtxTrans[(*nextIter)]; \
  674. dist1 = EM_ABS(dist1); \
  675. dist2 = dist1 + EM_ABS(dist2); \
  676. float yDd = dist1/dist2; \
  677. float dy = vtxB.y - vtxA.y; \
  678. yy = vtxA.y + dy*yDd; \
  679. ++iter; ++nextIter; break; \
  680. } \
  681. }
  682. #define FINDLINE_Z(A, B, C, D, zz, ss, iter, nextIter, begin, end) \
  683. for ( ; ; ++iter, ++nextIter ) { \
  684. if (iter == end) return false; \
  685. if (nextIter == end) nextIter = begin; \
  686. float dist1 = A * ss->m_vVtxTrans[(*iter)].x + B * ss->m_vVtxTrans[(*iter)].y + \
  687. C * ss->m_vVtxTrans[(*iter)].z + D; \
  688. float dist2 = A * ss->m_vVtxTrans[(*nextIter)].x + B * ss->m_vVtxTrans[(*nextIter)].y + \
  689. C * ss->m_vVtxTrans[(*nextIter)].z + D; \
  690. if (dist1*dist2 < 0) { \
  691. Vertex3D vtxA = ss->m_vVtxTrans[(*iter)]; \
  692. Vertex3D vtxB = ss->m_vVtxTrans[(*nextIter)]; \
  693. dist1 = EM_ABS(dist1); \
  694. dist2 = dist1 + EM_ABS(dist2); \
  695. float zDd = dist1/dist2; \
  696. float dz = vtxB.z - vtxA.z; \
  697. zz = vtxA.z + dz*zDd; \
  698. ++iter; ++nextIter; break; \
  699. } \
  700. }
  701. /* Check if two polygons intersect. Only for convex polygons.
  702. * Checks that the polygons has at least tre vertices. Use some macros to speed things up. */
  703. bool CollisionVisitor::intersect(Polygon3D * p1, Polygon3D * p2) {
  704. if (p1->m_vIndex.size() < 3 || p2->m_vIndex.size() < 3) return false;
  705. #if EM_DEBUG
  706. ++em_polygons;
  707. #endif
  708. EM_COUT_D("CollisionVisitor::intersect()", 0);
  709. int axis;
  710. float D1, D2;
  711. float x1=0.0, x2=0.0, x3=0.0, x4=0.0;
  712. Vertex3D normalA, normalB, normalC;
  713. Shape3D * s1 = p1->p_Shape3D;
  714. Shape3D * s2 = p2->p_Shape3D;
  715. // Count the plane for p1
  716. normalA.x = p1->m_nmlTrans.x;
  717. normalA.y = p1->m_nmlTrans.y;
  718. normalA.z = p1->m_nmlTrans.z;
  719. D1 = - normalA.x * s1->m_vVtxTrans[p1->m_vIndex[0]].x
  720. - normalA.y * s1->m_vVtxTrans[p1->m_vIndex[0]].y
  721. - normalA.z * s1->m_vVtxTrans[p1->m_vIndex[0]].z;
  722. // Count the plane for p2
  723. normalB.x = p2->m_nmlTrans.x;
  724. normalB.y = p2->m_nmlTrans.y;
  725. normalB.z = p2->m_nmlTrans.z;
  726. D2 = - normalB.x * s2->m_vVtxTrans[p2->m_vIndex[0]].x
  727. - normalB.y * s2->m_vVtxTrans[p2->m_vIndex[0]].y
  728. - normalB.z * s2->m_vVtxTrans[p2->m_vIndex[0]].z;
  729. EM_COUT_D("CollisionVisitor::intersect() normalA " << normalA.x <<" "<< normalA.y <<" "<<
  730. normalA.z <<" "<< D1, 0);
  731. EM_COUT_D("CollisionVisitor::intersect() normalB " << normalB.x <<" "<< normalB.y <<" "<<
  732. normalB.z <<" "<< D2, 0);
  733. // Check if it is a 2d collision we should do
  734. if ( EM_ZERO(normalB.x-normalA.x) &&
  735. EM_ZERO(normalB.y-normalA.y) &&
  736. EM_ZERO(normalB.z-normalA.z) &&
  737. EM_ZERO(D1-D2) ) {
  738. return CollisionVisitor::intersect2d(p1 , p2);
  739. }
  740. // Count the cross product to find which axis is most
  741. // suitable to project on.
  742. EMath::crossProduct(normalA, normalB, normalC);
  743. normalC.x = EM_ABS(normalC.x);
  744. normalC.y = EM_ABS(normalC.y);
  745. normalC.z = EM_ABS(normalC.z);
  746. if (normalC.x > normalC.y) {
  747. if (normalC.x > normalC.z) axis = 1;
  748. else if (normalC.y > normalC.z) axis = 2;
  749. else axis = 3;
  750. }
  751. else if (normalC.y > normalC.z) axis = 2;
  752. else axis = 3;
  753. EM_COUT_D("CollisionVisitor::intersect() axis " << axis, 0);
  754. // Find lines in p1 intersecting p2. Intersection point between line and
  755. // plane will be projected on the chosen axis, x1 is the projecton
  756. // onto the axis for line 1, x2 projection for line 2.
  757. // We get a projection of polygon p1 to a axis defined by x1 and x2.
  758. // I.e. polygon 1 lies between points x1 and x2.
  759. vector<int>::iterator begin1 = p1->m_vIndex.begin();
  760. vector<int>::iterator iter1 = p1->m_vIndex.begin();
  761. vector<int>::iterator nextIter1 = begin1 + 1;
  762. vector<int>::iterator end1 = p1->m_vIndex.end();
  763. // Find lines in p2 intersecting p1. Intersection point between line and
  764. // plane will be projected on the chosen axis., x3 is value for projecton
  765. // onto acis for line 1, x4 for line 2.
  766. // We get a projection of polygon p1 to a axis defined by x3 and x4.
  767. // I.e. polygon 2 lies between points x3 and x4.
  768. vector<int>::iterator begin2 = p2->m_vIndex.begin();
  769. vector<int>::iterator iter2 = p2->m_vIndex.begin();
  770. vector<int>::iterator nextIter2 = begin2 + 1;
  771. vector<int>::iterator end2 = p2->m_vIndex.end();
  772. if (axis == 1) {
  773. // Find first line in poly1 that intersects plane A, B, C, D
  774. FINDLINE_X(normalB.x, normalB.y, normalB.z, D2, x1, s1, iter1, nextIter1, begin1, end1);
  775. // Find second line in poly1 that intersects plane A, B, C, D
  776. FINDLINE_X(normalB.x, normalB.y, normalB.z, D2, x2, s1, iter1, nextIter1, begin1, end1);
  777. // Find first line in poly2 that intersects plane A, B, C, D
  778. FINDLINE_X(normalA.x, normalA.y, normalA.z, D1, x3, s2, iter2, nextIter2, begin2, end2);
  779. // Find second line in poly2 that intersects plane A, B, C, D
  780. FINDLINE_X(normalA.x, normalA.y, normalA.z, D1, x4, s2, iter2, nextIter2, begin2, end2);
  781. } else if (axis == 2) {
  782. // Find first line in poly1 that intersects plane A, B, C, D
  783. FINDLINE_Y(normalB.x, normalB.y, normalB.z, D2, x1, s1, iter1, nextIter1, begin1, end1);
  784. // Find second line in poly1 that intersects plane A, B, C, D
  785. FINDLINE_Y(normalB.x, normalB.y, normalB.z, D2, x2, s1, iter1, nextIter1, begin1, end1);
  786. // Find first line in poly2 that intersects plane A, B, C, D
  787. FINDLINE_Y(normalA.x, normalA.y, normalA.z, D1, x3, s2, iter2, nextIter2, begin2, end2);
  788. // Find second line in poly2 that intersects plane A, B, C, D
  789. FINDLINE_Y(normalA.x, normalA.y, normalA.z, D1, x4, s2, iter2, nextIter2, begin2, end2);
  790. } else {
  791. // Find first line in poly1 that intersects plane A, B, C, D
  792. FINDLINE_Z(normalB.x, normalB.y, normalB.z, D2, x1, s1, iter1, nextIter1, begin1, end1);
  793. // Find second line in poly1 that intersects plane A, B, C, D
  794. FINDLINE_Z(normalB.x, normalB.y, normalB.z, D2, x2, s1, iter1, nextIter1, begin1, end1);
  795. // Find first line in poly2 that intersects plane A, B, C, D
  796. FINDLINE_Z(normalA.x, normalA.y, normalA.z, D1, x3, s2, iter2, nextIter2, begin2, end2);
  797. // Find second line in poly2 that intersects plane A, B, C, D
  798. FINDLINE_Z(normalA.x, normalA.y, normalA.z, D1, x4, s2, iter2, nextIter2, begin2, end2);
  799. }
  800. EM_COUT_D(x1 <<" "<< x2 <<" "<< x3 <<" "<< x4, 0);
  801. // Polygons intersect if line x1,x2 and x3,x4 intersect.
  802. if ((EM_MAX(x1,x2) > EM_MIN(x3, x4)) && (EM_MAX(x3, x4) > EM_MIN(x1, x2))) return true;
  803. return false;
  804. }
  805. /*
  806. * (y2,y2) (x1,z1)
  807. * / \ /
  808. * / \ /
  809. * / \ /
  810. * / \ /
  811. * .../.......(0,0)
  812. * x
  813. */
  814. /*
  815. bool CollisionVisitor::counterClockWise(int axis, const Vertex3D & vtxA, const Vertex3D & vtxB, const Vertex3D & vtxC) {
  816. if (axis == 1) {
  817. return counterClockWiseYZ(vtxA, vtxB, vtxC);
  818. }
  819. if (axis == 2) {
  820. return counterClockWiseXY(vtxA, vtxB, vtxC);
  821. }
  822. return counterClockWiseXY(vtxA, vtxB, vtxC);
  823. }
  824. bool CollisionVisitor::counterClockWiseXY(const Vertex3D & vtxA, const Vertex3D & vtxB, const Vertex3D & vtxC) {
  825. float x1 = vtxB.x - vtxA.x;
  826. float y1 = vtxB.y - vtxA.y;
  827. float x2 = vtxC.x - vtxA.x;
  828. float y2 = vtxC.y - vtxA.y;
  829. if ( EM_ZERO(y1) ) {
  830. return ( x1*y2 < 0 );
  831. }
  832. if ( EM_ZERO(x1) ) {
  833. return ( y1*x2 > 0 );
  834. }
  835. float x = x2 - y2*x1/y1;
  836. return (x*y1 > 0);
  837. }
  838. bool CollisionVisitor::counterClockWiseXZ(const Vertex3D & vtxA, const Vertex3D & vtxB, const Vertex3D & vtxC) {
  839. float x1 = vtxB.x - vtxA.x;
  840. float z1 = vtxB.z - vtxA.z;
  841. float x2 = vtxC.x - vtxA.x;
  842. float z2 = vtxC.z - vtxA.z;
  843. if ( EM_ZERO(z1) ) {
  844. return ( x1*z2 < 0 );
  845. }
  846. if ( EM_ZERO(x1) ) {
  847. return ( z1*x2 > 0 );
  848. }
  849. float x = x2 - z2*x1/z1;
  850. return (x*z1 > 0);
  851. }
  852. bool CollisionVisitor::counterClockWiseYZ(const Vertex3D & vtxA, const Vertex3D & vtxB, const Vertex3D & vtxC) {
  853. float y1 = vtxB.y - vtxA.y;
  854. float z1 = vtxB.z - vtxA.z;
  855. float y2 = vtxC.y - vtxA.y;
  856. float z2 = vtxC.z - vtxA.z;
  857. if ( EM_ZERO(z1) ) {
  858. return ( y1*z2 < 0 );
  859. }
  860. if ( EM_ZERO(y1) ) {
  861. return ( y1*y2 > 0 );
  862. }
  863. float y = y2 - z2*y1/z1;
  864. return (y*z1 > 0);
  865. }
  866. */