OPC_SweepAndPrune.cpp 17 KB

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