2626 */
2727package org .spout .physics .collision .broadphase ;
2828
29+ import gnu .trove .iterator .TObjectIntIterator ;
30+ import gnu .trove .list .TIntList ;
31+ import gnu .trove .list .array .TIntArrayList ;
2932import gnu .trove .map .TObjectIntMap ;
3033import gnu .trove .map .hash .TObjectIntHashMap ;
31- import gnu .trove .stack .TIntStack ;
32- import gnu .trove .stack .array .TIntArrayStack ;
3334
3435import org .spout .physics .body .CollisionBody ;
3536import org .spout .physics .collision .CollisionDetection ;
@@ -47,7 +48,7 @@ public class SweepAndPruneAlgorithm extends BroadPhaseAlgorithm {
4748 private final EndPoint [][] mEndPoints = {null , null , null };
4849 private int mNbBoxes = 0 ;
4950 private int mNbMaxBoxes = 0 ;
50- private final TIntStack mFreeBoxIndices = new TIntArrayStack ();
51+ private final TIntList mFreeBoxIndices = new TIntArrayList ();
5152 private final TObjectIntMap <CollisionBody > mMapBodyToBoxIndex = new TObjectIntHashMap <>();
5253
5354 /**
@@ -82,7 +83,7 @@ public void addObject(CollisionBody body, AABB aabb) {
8283 }
8384 final int boxIndex ;
8485 if (mFreeBoxIndices .size () != 0 ) {
85- boxIndex = mFreeBoxIndices .pop ( );
86+ boxIndex = mFreeBoxIndices .removeAt ( mFreeBoxIndices . size () - 1 );
8687 } else {
8788 if (mNbBoxes == mNbMaxBoxes ) {
8889 resizeArrays ();
@@ -151,12 +152,15 @@ public void removeObject(CollisionBody body) {
151152 final EndPoint newMaxLimitEndPoint = mEndPoints [axis ][indexLimitEndPoint - 2 ];
152153 newMaxLimitEndPoint .setValues (maxLimitEndPoint .getBoxID (), maxLimitEndPoint .isMin (), maxLimitEndPoint .getValue ());
153154 }
154- mFreeBoxIndices .push (boxIndex );
155+ mFreeBoxIndices .add (boxIndex );
155156 mMapBodyToBoxIndex .remove (body );
156157 mNbBoxes --;
158+ final int nextPowerOf2 = PairManager .computeNextPowerOfTwo ((mNbBoxes - 1 ) / 100 );
159+ if (nextPowerOf2 * 100 < mNbMaxBoxes ) {
160+ shrinkArrays ();
161+ }
157162 }
158163
159-
160164 @ Override
161165 public void updateObject (CollisionBody body , AABB aabb ) {
162166 final AABBInt aabbInt = new AABBInt (aabb );
@@ -340,6 +344,75 @@ private void resizeArrays() {
340344 mNbMaxBoxes = newNbMaxBoxes ;
341345 }
342346
347+ // Shrinks the boxes and end-points arrays when too much memory is allocated.
348+ private void shrinkArrays () {
349+ final int nextPowerOf2 = PairManager .computeNextPowerOfTwo ((mNbBoxes - 1 ) / 100 );
350+ final int newNbMaxBoxes = mNbBoxes > 100 ? nextPowerOf2 * 100 : 100 ;
351+ final int nbEndPoints = mNbBoxes * 2 + NB_SENTINELS ;
352+ final int newNbEndPoints = newNbMaxBoxes * 2 + NB_SENTINELS ;
353+ if (newNbMaxBoxes >= mNbMaxBoxes ) {
354+ throw new IllegalStateException ("The new maximum number of boxes can't be greater or equal to the old one" );
355+ }
356+ mFreeBoxIndices .sort ();
357+ final TObjectIntMap <CollisionBody > newMapBodyToBoxIndex = new TObjectIntHashMap <>();
358+ final TObjectIntIterator <CollisionBody > it = mMapBodyToBoxIndex .iterator ();
359+ while (it .hasNext ()) {
360+ it .advance ();
361+ final CollisionBody body = it .key ();
362+ final int boxIndex = it .value ();
363+ if (boxIndex >= mNbBoxes ) {
364+ if (mFreeBoxIndices .isEmpty ()) {
365+ throw new IllegalStateException ("The list of free box indices can't be empty" );
366+ }
367+ final int newBoxIndex = mFreeBoxIndices .removeAt (0 );
368+ if (newBoxIndex >= mNbBoxes ) {
369+ throw new IllegalStateException ("The new box index can't be greater or equal to number of boxes" );
370+ }
371+ final BoxAABB oldBox = mBoxes [boxIndex ];
372+ final BoxAABB newBox = mBoxes [newBoxIndex ];
373+ if (oldBox .getBody ().getID () != body .getID ()) {
374+ throw new IllegalStateException ("The old box body ID can't be equal to body ID" );
375+ }
376+ newBox .setBody (oldBox .getBody ());
377+ for (int axis = 0 ; axis < 3 ; axis ++) {
378+ newBox .setMin (axis , oldBox .getMin ()[axis ]);
379+ newBox .setMax (axis , oldBox .getMax ()[axis ]);
380+ final EndPoint minimumEndPoint = mEndPoints [axis ][newBox .getMin ()[axis ]];
381+ final EndPoint maximumEndPoint = mEndPoints [axis ][newBox .getMax ()[axis ]];
382+ if (minimumEndPoint .getBoxID () != boxIndex ) {
383+ throw new IllegalStateException ("The minimum end point box ID can't be equal to box index" );
384+ }
385+ if (maximumEndPoint .getBoxID () != boxIndex ) {
386+ throw new IllegalStateException ("The maximum end point box ID can't be equal to box index" );
387+ }
388+ minimumEndPoint .setBoxID (newBoxIndex );
389+ maximumEndPoint .setBoxID (newBoxIndex );
390+ }
391+ newMapBodyToBoxIndex .put (body , newBoxIndex );
392+ } else {
393+ newMapBodyToBoxIndex .put (body , boxIndex );
394+ }
395+ }
396+ if (newMapBodyToBoxIndex .size () != mMapBodyToBoxIndex .size ()) {
397+ throw new IllegalStateException ("The size of the new map from body to box index must be the same as the old one" );
398+ }
399+ mMapBodyToBoxIndex .clear ();
400+ mMapBodyToBoxIndex .putAll (newMapBodyToBoxIndex );
401+ final BoxAABB [] newBoxesArray = new BoxAABB [newNbMaxBoxes ];
402+ final EndPoint [] newEndPointsXArray = new EndPoint [newNbEndPoints ];
403+ final EndPoint [] newEndPointsYArray = new EndPoint [newNbEndPoints ];
404+ final EndPoint [] newEndPointsZArray = new EndPoint [newNbEndPoints ];
405+ System .arraycopy (mBoxes , 0 , newBoxesArray , 0 , mNbBoxes );
406+ System .arraycopy (mEndPoints [0 ], 0 , newEndPointsXArray , 0 , nbEndPoints );
407+ System .arraycopy (mEndPoints [1 ], 0 , newEndPointsYArray , 0 , nbEndPoints );
408+ System .arraycopy (mEndPoints [2 ], 0 , newEndPointsZArray , 0 , nbEndPoints );
409+ mBoxes = newBoxesArray ;
410+ mEndPoints [0 ] = newEndPointsXArray ;
411+ mEndPoints [1 ] = newEndPointsYArray ;
412+ mEndPoints [2 ] = newEndPointsZArray ;
413+ mNbMaxBoxes = newNbMaxBoxes ;
414+ }
415+
343416 // Encodes a floating value into a integer value in order to work with integer
344417 // comparisons in the Sweep-And-Prune algorithm, for performance.
345418 // The main issue when encoding a floating number into an integer is keeping
@@ -380,6 +453,10 @@ private int getBoxID() {
380453 return boxID ;
381454 }
382455
456+ private void setBoxID (int boxID ) {
457+ this .boxID = boxID ;
458+ }
459+
383460 private boolean isMin () {
384461 return isMin ;
385462 }
@@ -404,7 +481,7 @@ public String toString() {
404481 }
405482 }
406483
407- // Represents an AABB in the Sweep-And-Prune algorithm
484+ // Represents an AABB in the Sweep-And-Prune algorithm.
408485 private static class BoxAABB {
409486 private final int [] min = new int [3 ];
410487 private final int [] max = new int [3 ];
@@ -414,10 +491,18 @@ private int[] getMin() {
414491 return min ;
415492 }
416493
494+ private void setMin (int i , int v ) {
495+ min [i ] = v ;
496+ }
497+
417498 private int [] getMax () {
418499 return max ;
419500 }
420501
502+ private void setMax (int i , int v ) {
503+ max [i ] = v ;
504+ }
505+
421506 private CollisionBody getBody () {
422507 return body ;
423508 }
0 commit comments