OPC_SweepAndPrune.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /*
  3. * OPCODE - Optimized Collision Detection
  4. * Copyright (C) 2001 Pierre Terdiman
  5. * Homepage: http://www.codercorner.com/Opcode.htm
  6. */
  7. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. /**
  10. * Contains an implementation of the sweep-and-prune algorithm (moved from Z-Collide)
  11. * \file OPC_SweepAndPrune.cpp
  12. * \author Pierre Terdiman
  13. * \date January, 29, 2000
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. #include "Opcode.h"
  18. #if (defined _MSC_VER) && (_MSC_VER <= 1500)
  19. #ifdef _WIN64 // [
  20. typedef unsigned __int64 uintptr_t;
  21. #else // _WIN64 ][
  22. typedef _W64 unsigned int uintptr_t;
  23. #endif // _WIN64 ]
  24. #else
  25. #include <stdint.h>
  26. #endif
  27. using namespace Opcode;
  28. inline_ void Sort(udword& id0, udword& id1)
  29. {
  30. if(id0>id1) Swap(id0, id1);
  31. }
  32. class Opcode::SAP_Element
  33. {
  34. public:
  35. inline_ SAP_Element() {}
  36. inline_ SAP_Element(udword id, SAP_Element* next) : mID(id), mNext(next) {}
  37. inline_ ~SAP_Element() {}
  38. udword mID;
  39. SAP_Element* mNext;
  40. };
  41. class Opcode::SAP_Box
  42. {
  43. public:
  44. SAP_EndPoint* Min[3];
  45. SAP_EndPoint* Max[3];
  46. };
  47. class Opcode::SAP_EndPoint
  48. {
  49. public:
  50. float Value; // Min or Max value
  51. SAP_EndPoint* Previous; // Previous EndPoint whose Value is smaller than ours (or null)
  52. SAP_EndPoint* Next; // Next EndPoint whose Value is greater than ours (or null)
  53. udword Data; // Parent box ID *2 | MinMax flag
  54. inline_ void SetData(udword box_id, BOOL is_max) { Data = (box_id<<1)|is_max; }
  55. inline_ BOOL IsMax() const { return Data & 1; }
  56. inline_ udword GetBoxID() const { return Data>>1; }
  57. inline_ void InsertAfter(SAP_EndPoint* element)
  58. {
  59. if(this!=element && this!=element->Next)
  60. {
  61. // Remove
  62. if(Previous) Previous->Next = Next;
  63. if(Next) Next->Previous = Previous;
  64. // Insert
  65. Next = element->Next;
  66. if(Next) Next->Previous = this;
  67. element->Next = this;
  68. Previous = element;
  69. }
  70. }
  71. inline_ void InsertBefore(SAP_EndPoint* element)
  72. {
  73. if(this!=element && this!=element->Previous)
  74. {
  75. // Remove
  76. if(Previous) Previous->Next = Next;
  77. if(Next) Next->Previous = Previous;
  78. // Insert
  79. Previous = element->Previous;
  80. element->Previous = this;
  81. Next = element;
  82. if(Previous) Previous->Next = this;
  83. }
  84. }
  85. };
  86. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. /**
  88. * Constructor.
  89. */
  90. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  91. SAP_PairData::SAP_PairData() :
  92. mNbElements (0),
  93. mNbUsedElements (0),
  94. mElementPool (null),
  95. mFirstFree (null),
  96. mNbObjects (0),
  97. mArray (null)
  98. {
  99. }
  100. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. /**
  102. * Destructor.
  103. */
  104. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. SAP_PairData::~SAP_PairData()
  106. {
  107. Release();
  108. }
  109. void SAP_PairData::Release()
  110. {
  111. mNbElements = 0;
  112. mNbUsedElements = 0;
  113. mNbObjects = 0;
  114. DELETEARRAY(mElementPool);
  115. DELETEARRAY(mArray);
  116. }
  117. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  118. /**
  119. * Initializes.
  120. * \param nb_objects [in]
  121. * \return true if success
  122. */
  123. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  124. bool SAP_PairData::Init(udword nb_objects)
  125. {
  126. // Make sure everything has been released
  127. Release();
  128. if(!nb_objects) return false;
  129. mArray = new SAP_Element*[nb_objects];
  130. CHECKALLOC(mArray);
  131. ZeroMemory(mArray, nb_objects*sizeof(SAP_Element*));
  132. mNbObjects = nb_objects;
  133. return true;
  134. }
  135. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  136. /**
  137. * Remaps a pointer when pool gets resized.
  138. * \param element [in/out] remapped element
  139. * \param delta [in] offset in bytes
  140. */
  141. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. inline_ void Remap(SAP_Element*& element, udword delta)
  143. {
  144. if(element) element = (SAP_Element*)(element + delta);
  145. }
  146. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  147. /**
  148. * Gets a free element in the pool.
  149. * \param id [in] element id
  150. * \param next [in] next element
  151. * \param remap [out] possible remapping offset
  152. * \return the new element
  153. */
  154. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. SAP_Element* SAP_PairData::GetFreeElem(udword id, SAP_Element* next, udword* remap)
  156. {
  157. if(remap) *remap = 0;
  158. SAP_Element* FreeElem;
  159. if(mFirstFree)
  160. {
  161. // Recycle
  162. FreeElem = mFirstFree;
  163. mFirstFree = mFirstFree->mNext; // First free = next free (or null)
  164. }
  165. else
  166. {
  167. if(mNbUsedElements==mNbElements)
  168. {
  169. // Resize
  170. mNbElements = mNbElements ? (mNbElements<<1) : 2;
  171. SAP_Element* NewElems = new SAP_Element[mNbElements];
  172. if(mNbUsedElements) CopyMemory(NewElems, mElementPool, mNbUsedElements*sizeof(SAP_Element));
  173. // Remap everything
  174. {
  175. udword Delta = uintptr_t(NewElems) - uintptr_t(mElementPool);
  176. for(udword i=0;i<mNbUsedElements;i++) Remap(NewElems[i].mNext, Delta);
  177. for(udword i=0;i<mNbObjects;i++) Remap(mArray[i], Delta);
  178. Remap(mFirstFree, Delta);
  179. Remap(next, Delta);
  180. if(remap) *remap = Delta;
  181. }
  182. DELETEARRAY(mElementPool);
  183. mElementPool = NewElems;
  184. }
  185. FreeElem = &mElementPool[mNbUsedElements++];
  186. }
  187. FreeElem->mID = id;
  188. FreeElem->mNext = next;
  189. return FreeElem;
  190. }
  191. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  192. /**
  193. * Frees an element of the pool.
  194. * \param elem [in] element to free/recycle
  195. */
  196. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  197. inline_ void SAP_PairData::FreeElem(SAP_Element* elem)
  198. {
  199. elem->mNext = mFirstFree; // Next free
  200. mFirstFree = elem;
  201. }
  202. // Add a pair to the set.
  203. void SAP_PairData::AddPair(udword id1, udword id2)
  204. {
  205. // Order the ids
  206. Sort(id1, id2);
  207. ASSERT(id1<mNbObjects);
  208. if(id1>=mNbObjects) return;
  209. // Select the right list from "mArray".
  210. SAP_Element* Current = mArray[id1];
  211. if(!Current)
  212. {
  213. // Empty slot => create new element
  214. mArray[id1] = GetFreeElem(id2, null);
  215. }
  216. else if(Current->mID>id2)
  217. {
  218. // The list is not empty but all elements are greater than id2 => insert id2 in the front.
  219. mArray[id1] = GetFreeElem(id2, mArray[id1]);
  220. }
  221. else
  222. {
  223. // Else find the correct location in the sorted list (ascending order) and insert id2 there.
  224. while(Current->mNext)
  225. {
  226. if(Current->mNext->mID > id2) break;
  227. Current = Current->mNext;
  228. }
  229. if(Current->mID==id2) return; // The pair already exists
  230. // Current->mNext = GetFreeElem(id2, Current->mNext);
  231. udword Delta;
  232. SAP_Element* E = GetFreeElem(id2, Current->mNext, &Delta);
  233. if(Delta) Remap(Current, Delta);
  234. Current->mNext = E;
  235. }
  236. }
  237. // Delete a pair from the set.
  238. void SAP_PairData::RemovePair(udword id1, udword id2)
  239. {
  240. // Order the ids.
  241. Sort(id1, id2);
  242. // Exit if the pair doesn't exist in the set
  243. if(id1>=mNbObjects) return;
  244. // Otherwise, select the correct list.
  245. SAP_Element* Current = mArray[id1];
  246. // If this list is empty, the pair doesn't exist.
  247. if(!Current) return;
  248. // Otherwise, if id2 is the first element, delete it.
  249. if(Current->mID==id2)
  250. {
  251. mArray[id1] = Current->mNext;
  252. FreeElem(Current);
  253. }
  254. else
  255. {
  256. // If id2 is not the first element, start traversing the sorted list.
  257. while(Current->mNext)
  258. {
  259. // If we have moved too far away without hitting id2, then the pair doesn't exist
  260. if(Current->mNext->mID > id2) return;
  261. // Otherwise, delete id2.
  262. if(Current->mNext->mID == id2)
  263. {
  264. SAP_Element* Temp = Current->mNext;
  265. Current->mNext = Temp->mNext;
  266. FreeElem(Temp);
  267. return;
  268. }
  269. Current = Current->mNext;
  270. }
  271. }
  272. }
  273. void SAP_PairData::DumpPairs(Pairs& pairs) const
  274. {
  275. // ### Ugly and slow
  276. for(udword i=0;i<mNbObjects;i++)
  277. {
  278. SAP_Element* Current = mArray[i];
  279. while(Current)
  280. {
  281. ASSERT(Current->mID<mNbObjects);
  282. pairs.AddPair(i, Current->mID);
  283. Current = Current->mNext;
  284. }
  285. }
  286. }
  287. void SAP_PairData::DumpPairs(PairCallback callback, void* user_data) const
  288. {
  289. if(!callback) return;
  290. // ### Ugly and slow
  291. for(udword i=0;i<mNbObjects;i++)
  292. {
  293. SAP_Element* Current = mArray[i];
  294. while(Current)
  295. {
  296. ASSERT(Current->mID<mNbObjects);
  297. if(!(callback)(i, Current->mID, user_data)) return;
  298. Current = Current->mNext;
  299. }
  300. }
  301. }
  302. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  303. /**
  304. * Constructor.
  305. */
  306. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. SweepAndPrune::SweepAndPrune()
  308. {
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. /**
  312. * Destructor.
  313. */
  314. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  315. SweepAndPrune::~SweepAndPrune()
  316. {
  317. }
  318. void SweepAndPrune::GetPairs(Pairs& pairs) const
  319. {
  320. mPairs.DumpPairs(pairs);
  321. }
  322. void SweepAndPrune::GetPairs(PairCallback callback, void* user_data) const
  323. {
  324. mPairs.DumpPairs(callback, user_data);
  325. }
  326. bool SweepAndPrune::Init(udword nb_objects, const AABB** boxes)
  327. {
  328. // 1) Create sorted lists
  329. mNbObjects = nb_objects;
  330. mBoxes = new SAP_Box[nb_objects];
  331. // for(udword i=0;i<nb_objects;i++) mBoxes[i].Box = *boxes[i];
  332. float* Data = new float[nb_objects*2];
  333. for(udword Axis=0;Axis<3;Axis++)
  334. {
  335. mList[Axis] = new SAP_EndPoint[nb_objects*2];
  336. for(udword i=0;i<nb_objects;i++)
  337. {
  338. Data[i*2+0] = boxes[i]->GetMin(Axis);
  339. Data[i*2+1] = boxes[i]->GetMax(Axis);
  340. }
  341. RadixSort RS;
  342. const udword* Sorted = RS.Sort(Data, nb_objects*2).GetRanks();
  343. SAP_EndPoint* PreviousEndPoint = null;
  344. for(udword i=0;i<nb_objects*2;i++)
  345. {
  346. udword SortedIndex = *Sorted++;
  347. float SortedCoord = Data[SortedIndex];
  348. udword BoxIndex = SortedIndex>>1;
  349. ASSERT(BoxIndex<nb_objects);
  350. SAP_EndPoint* CurrentEndPoint = &mList[Axis][SortedIndex];
  351. CurrentEndPoint->Value = SortedCoord;
  352. // CurrentEndPoint->IsMax = SortedIndex&1; // ### could be implicit ?
  353. // CurrentEndPoint->ID = BoxIndex; // ### could be implicit ?
  354. CurrentEndPoint->SetData(BoxIndex, SortedIndex&1); // ### could be implicit ?
  355. CurrentEndPoint->Previous = PreviousEndPoint;
  356. CurrentEndPoint->Next = null;
  357. if(PreviousEndPoint) PreviousEndPoint->Next = CurrentEndPoint;
  358. if(CurrentEndPoint->IsMax()) mBoxes[BoxIndex].Max[Axis] = CurrentEndPoint;
  359. else mBoxes[BoxIndex].Min[Axis] = CurrentEndPoint;
  360. PreviousEndPoint = CurrentEndPoint;
  361. }
  362. }
  363. DELETEARRAY(Data);
  364. CheckListsIntegrity();
  365. // 2) Quickly find starting pairs
  366. mPairs.Init(nb_objects);
  367. {
  368. Pairs P;
  369. CompleteBoxPruning(nb_objects, boxes, P, Axes(AXES_XZY));
  370. for(udword i=0;i<P.GetNbPairs();i++)
  371. {
  372. const Pair* PP = P.GetPair(i);
  373. udword id0 = PP->id0;
  374. udword id1 = PP->id1;
  375. if(id0!=id1 && boxes[id0]->Intersect(*boxes[id1]))
  376. {
  377. mPairs.AddPair(id0, id1);
  378. }
  379. else ASSERT(0);
  380. }
  381. }
  382. return true;
  383. }
  384. bool SweepAndPrune::CheckListsIntegrity()
  385. {
  386. for(udword Axis=0;Axis<3;Axis++)
  387. {
  388. // Find list head
  389. SAP_EndPoint* Current = mList[Axis];
  390. while(Current->Previous) Current = Current->Previous;
  391. udword Nb = 0;
  392. SAP_EndPoint* Previous = null;
  393. while(Current)
  394. {
  395. Nb++;
  396. if(Previous)
  397. {
  398. ASSERT(Previous->Value <= Current->Value);
  399. if(Previous->Value > Current->Value) return false;
  400. }
  401. ASSERT(Current->Previous==Previous);
  402. if(Current->Previous!=Previous) return false;
  403. Previous = Current;
  404. Current = Current->Next;
  405. }
  406. ASSERT(Nb==mNbObjects*2);
  407. }
  408. return true;
  409. }
  410. inline_ BOOL Intersect(const AABB& a, const SAP_Box& b)
  411. {
  412. if(b.Max[0]->Value < a.GetMin(0) || a.GetMax(0) < b.Min[0]->Value
  413. || b.Max[1]->Value < a.GetMin(1) || a.GetMax(1) < b.Min[1]->Value
  414. || b.Max[2]->Value < a.GetMin(2) || a.GetMax(2) < b.Min[2]->Value) return FALSE;
  415. return TRUE;
  416. }
  417. bool SweepAndPrune::UpdateObject(udword i, const AABB& box)
  418. {
  419. for(udword Axis=0;Axis<3;Axis++)
  420. {
  421. // udword Base = (udword)&mList[Axis][0];
  422. // Update min
  423. {
  424. SAP_EndPoint* const CurrentMin = mBoxes[i].Min[Axis];
  425. ASSERT(!CurrentMin->IsMax());
  426. const float Limit = box.GetMin(Axis);
  427. if(Limit == CurrentMin->Value)
  428. {
  429. }
  430. else if(Limit < CurrentMin->Value)
  431. {
  432. CurrentMin->Value = Limit;
  433. // Min is moving left:
  434. SAP_EndPoint* NewPos = CurrentMin;
  435. ASSERT(NewPos);
  436. SAP_EndPoint* tmp;
  437. while((tmp = NewPos->Previous) && tmp->Value > Limit)
  438. {
  439. NewPos = tmp;
  440. if(NewPos->IsMax())
  441. {
  442. // Our min passed a max => start overlap
  443. //udword SortedIndex = (udword(CurrentMin) - Base)/sizeof(NS_EndPoint);
  444. const udword id0 = CurrentMin->GetBoxID();
  445. const udword id1 = NewPos->GetBoxID();
  446. if(id0!=id1 && Intersect(box, mBoxes[id1])) mPairs.AddPair(id0, id1);
  447. }
  448. }
  449. CurrentMin->InsertBefore(NewPos);
  450. }
  451. else// if(Limit > CurrentMin->Value)
  452. {
  453. CurrentMin->Value = Limit;
  454. // Min is moving right:
  455. SAP_EndPoint* NewPos = CurrentMin;
  456. ASSERT(NewPos);
  457. SAP_EndPoint* tmp;
  458. while((tmp = NewPos->Next) && tmp->Value < Limit)
  459. {
  460. NewPos = tmp;
  461. if(NewPos->IsMax())
  462. {
  463. // Our min passed a max => stop overlap
  464. const udword id0 = CurrentMin->GetBoxID();
  465. const udword id1 = NewPos->GetBoxID();
  466. if(id0!=id1) mPairs.RemovePair(id0, id1);
  467. }
  468. }
  469. CurrentMin->InsertAfter(NewPos);
  470. }
  471. }
  472. // Update max
  473. {
  474. SAP_EndPoint* const CurrentMax = mBoxes[i].Max[Axis];
  475. ASSERT(CurrentMax->IsMax());
  476. const float Limit = box.GetMax(Axis);
  477. if(Limit == CurrentMax->Value)
  478. {
  479. }
  480. else if(Limit > CurrentMax->Value)
  481. {
  482. CurrentMax->Value = Limit;
  483. // Max is moving right:
  484. SAP_EndPoint* NewPos = CurrentMax;
  485. ASSERT(NewPos);
  486. SAP_EndPoint* tmp;
  487. while((tmp = NewPos->Next) && tmp->Value < Limit)
  488. {
  489. NewPos = tmp;
  490. if(!NewPos->IsMax())
  491. {
  492. // Our max passed a min => start overlap
  493. const udword id0 = CurrentMax->GetBoxID();
  494. const udword id1 = NewPos->GetBoxID();
  495. if(id0!=id1 && Intersect(box, mBoxes[id1])) mPairs.AddPair(id0, id1);
  496. }
  497. }
  498. CurrentMax->InsertAfter(NewPos);
  499. }
  500. else// if(Limit < CurrentMax->Value)
  501. {
  502. CurrentMax->Value = Limit;
  503. // Max is moving left:
  504. SAP_EndPoint* NewPos = CurrentMax;
  505. ASSERT(NewPos);
  506. SAP_EndPoint* tmp;
  507. while((tmp = NewPos->Previous) && tmp->Value > Limit)
  508. {
  509. NewPos = tmp;
  510. if(!NewPos->IsMax())
  511. {
  512. // Our max passed a min => stop overlap
  513. const udword id0 = CurrentMax->GetBoxID();
  514. const udword id1 = NewPos->GetBoxID();
  515. if(id0!=id1) mPairs.RemovePair(id0, id1);
  516. }
  517. }
  518. CurrentMax->InsertBefore(NewPos);
  519. }
  520. }
  521. }
  522. return true;
  523. }