chipmunk 5.3.4.0-x86-mingw32 → 5.3.4.2-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +33 -13
 - data/Rakefile +20 -7
 - data/ext/chipmunk/extconf.rb +55 -12
 - data/ext/chipmunk/rb_chipmunk.c +92 -98
 - data/ext/chipmunk/rb_chipmunk.h +44 -34
 - data/ext/chipmunk/rb_cpArbiter.c +135 -98
 - data/ext/chipmunk/rb_cpBB.c +84 -101
 - data/ext/chipmunk/rb_cpBody.c +219 -241
 - data/ext/chipmunk/rb_cpConstraint.c +173 -185
 - data/ext/chipmunk/rb_cpShape.c +347 -251
 - data/ext/chipmunk/rb_cpSpace.c +376 -408
 - data/ext/chipmunk/rb_cpVect.c +132 -170
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk.h +163 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_ffi.h +59 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_private.h +49 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_types.h +151 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/chipmunk_unsafe.h +54 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpConstraint.h +105 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpDampedRotarySpring.h +46 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpDampedSpring.h +53 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpGearJoint.h +41 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpGrooveJoint.h +48 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpPinJoint.h +43 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpPivotJoint.h +42 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpRatchetJoint.h +40 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpRotaryLimitJoint.h +39 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpSimpleMotor.h +37 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/cpSlideJoint.h +44 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/constraints/util.h +134 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpArbiter.h +188 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpArray.h +49 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpBB.h +74 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpBody.h +219 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpCollision.h +28 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpHashSet.h +82 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpPolyShape.h +103 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpShape.h +177 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpSpace.h +206 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpSpaceHash.h +110 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/include/chipmunk/cpVect.h +207 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/chipmunk.c +151 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpConstraint.c +54 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpDampedRotarySpring.c +105 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpDampedSpring.c +115 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpGearJoint.c +113 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpGrooveJoint.c +161 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpPinJoint.c +116 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpPivotJoint.c +114 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpRatchetJoint.c +126 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpRotaryLimitJoint.c +120 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpSimpleMotor.c +97 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/constraints/cpSlideJoint.c +129 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpArbiter.c +280 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpArray.c +143 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpBB.c +47 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpBody.c +192 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpCollision.c +411 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpHashSet.c +253 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpPolyShape.c +240 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpShape.c +405 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpace.c +499 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceComponent.c +279 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceHash.c +534 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceQuery.c +246 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpSpaceStep.c +398 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/cpVect.c +71 -0
 - data/ext/chipmunk/vendor/chipmunk-5.3.4/src/prime.h +68 -0
 - data/lib/1.9/chipmunk.so +0 -0
 - data/lib/chipmunk.rb +19 -8
 - metadata +84 -42
 - data/lib/1.8/chipmunk.so +0 -0
 
| 
         @@ -0,0 +1,279 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* Copyright (c) 2007 Scott Lembcke
         
     | 
| 
      
 2 
     | 
    
         
            +
             * 
         
     | 
| 
      
 3 
     | 
    
         
            +
             * Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 4 
     | 
    
         
            +
             * of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 5 
     | 
    
         
            +
             * in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 6 
     | 
    
         
            +
             * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 7 
     | 
    
         
            +
             * copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 8 
     | 
    
         
            +
             * furnished to do so, subject to the following conditions:
         
     | 
| 
      
 9 
     | 
    
         
            +
             * 
         
     | 
| 
      
 10 
     | 
    
         
            +
             * The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 11 
     | 
    
         
            +
             * all copies or substantial portions of the Software.
         
     | 
| 
      
 12 
     | 
    
         
            +
             * 
         
     | 
| 
      
 13 
     | 
    
         
            +
             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 14 
     | 
    
         
            +
             * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 15 
     | 
    
         
            +
             * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 16 
     | 
    
         
            +
             * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 17 
     | 
    
         
            +
             * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 18 
     | 
    
         
            +
             * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 19 
     | 
    
         
            +
             * SOFTWARE.
         
     | 
| 
      
 20 
     | 
    
         
            +
             */
         
     | 
| 
      
 21 
     | 
    
         
            +
             
         
     | 
| 
      
 22 
     | 
    
         
            +
            #include <stdlib.h>
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            #include "chipmunk_private.h"
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            #pragma mark Sleeping Functions
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            // Chipmunk uses a data structure called a disjoint set forest.
         
     | 
| 
      
 29 
     | 
    
         
            +
            // My attempts to find a way to splice circularly linked lists in
         
     | 
| 
      
 30 
     | 
    
         
            +
            // constant time failed, and so I found this neat data structure instead.
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            static inline cpBody *
         
     | 
| 
      
 33 
     | 
    
         
            +
            componentNodeRoot(cpBody *body)
         
     | 
| 
      
 34 
     | 
    
         
            +
            {
         
     | 
| 
      
 35 
     | 
    
         
            +
            	cpBody *parent = body->node.parent;
         
     | 
| 
      
 36 
     | 
    
         
            +
            	
         
     | 
| 
      
 37 
     | 
    
         
            +
            	if(parent){
         
     | 
| 
      
 38 
     | 
    
         
            +
            		// path compression, attaches this node directly to the root
         
     | 
| 
      
 39 
     | 
    
         
            +
            		return (body->node.parent = componentNodeRoot(parent));
         
     | 
| 
      
 40 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 41 
     | 
    
         
            +
            		return body;
         
     | 
| 
      
 42 
     | 
    
         
            +
            	}
         
     | 
| 
      
 43 
     | 
    
         
            +
            }
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 46 
     | 
    
         
            +
            componentNodeMerge(cpBody *a_root, cpBody *b_root)
         
     | 
| 
      
 47 
     | 
    
         
            +
            {
         
     | 
| 
      
 48 
     | 
    
         
            +
            	if(a_root->node.rank < b_root->node.rank){
         
     | 
| 
      
 49 
     | 
    
         
            +
            		a_root->node.parent = b_root;
         
     | 
| 
      
 50 
     | 
    
         
            +
            	} else if(a_root->node.rank > b_root->node.rank){
         
     | 
| 
      
 51 
     | 
    
         
            +
            		b_root->node.parent = a_root;
         
     | 
| 
      
 52 
     | 
    
         
            +
            	} else if(a_root != b_root){
         
     | 
| 
      
 53 
     | 
    
         
            +
            		b_root->node.parent = a_root;
         
     | 
| 
      
 54 
     | 
    
         
            +
            		a_root->node.rank++;
         
     | 
| 
      
 55 
     | 
    
         
            +
            	}
         
     | 
| 
      
 56 
     | 
    
         
            +
            }
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            void
         
     | 
| 
      
 59 
     | 
    
         
            +
            cpSpaceActivateBody(cpSpace *space, cpBody *body)
         
     | 
| 
      
 60 
     | 
    
         
            +
            {
         
     | 
| 
      
 61 
     | 
    
         
            +
            	if(space->locked){
         
     | 
| 
      
 62 
     | 
    
         
            +
            		// cpSpaceActivateBody() is called again once the space is unlocked
         
     | 
| 
      
 63 
     | 
    
         
            +
            		cpArrayPush(space->rousedBodies, body);
         
     | 
| 
      
 64 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 65 
     | 
    
         
            +
            		cpArrayPush(space->bodies, body);
         
     | 
| 
      
 66 
     | 
    
         
            +
            		for(cpShape *shape=body->shapesList; shape; shape=shape->next){
         
     | 
| 
      
 67 
     | 
    
         
            +
            			cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
         
     | 
| 
      
 68 
     | 
    
         
            +
            			cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
         
     | 
| 
      
 69 
     | 
    
         
            +
            		}
         
     | 
| 
      
 70 
     | 
    
         
            +
            	}
         
     | 
| 
      
 71 
     | 
    
         
            +
            }
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 74 
     | 
    
         
            +
            componentActivate(cpBody *root)
         
     | 
| 
      
 75 
     | 
    
         
            +
            {
         
     | 
| 
      
 76 
     | 
    
         
            +
            	if(!cpBodyIsSleeping(root)) return;
         
     | 
| 
      
 77 
     | 
    
         
            +
            	
         
     | 
| 
      
 78 
     | 
    
         
            +
            	cpSpace *space = root->space;
         
     | 
| 
      
 79 
     | 
    
         
            +
            	cpAssert(space, "Trying to activate a body that was never added to a space.");
         
     | 
| 
      
 80 
     | 
    
         
            +
            	
         
     | 
| 
      
 81 
     | 
    
         
            +
            	cpBody *body = root, *next;
         
     | 
| 
      
 82 
     | 
    
         
            +
            	do {
         
     | 
| 
      
 83 
     | 
    
         
            +
            		next = body->node.next;
         
     | 
| 
      
 84 
     | 
    
         
            +
            		
         
     | 
| 
      
 85 
     | 
    
         
            +
            		cpComponentNode node = {NULL, NULL, 0, 0.0f};
         
     | 
| 
      
 86 
     | 
    
         
            +
            		body->node = node;
         
     | 
| 
      
 87 
     | 
    
         
            +
            		
         
     | 
| 
      
 88 
     | 
    
         
            +
            		cpSpaceActivateBody(space, body);
         
     | 
| 
      
 89 
     | 
    
         
            +
            	} while((body = next) != root);
         
     | 
| 
      
 90 
     | 
    
         
            +
            	
         
     | 
| 
      
 91 
     | 
    
         
            +
            	cpArrayDeleteObj(space->sleepingComponents, root);
         
     | 
| 
      
 92 
     | 
    
         
            +
            }
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            void
         
     | 
| 
      
 95 
     | 
    
         
            +
            cpBodyActivate(cpBody *body)
         
     | 
| 
      
 96 
     | 
    
         
            +
            {
         
     | 
| 
      
 97 
     | 
    
         
            +
            	componentActivate(componentNodeRoot(body));
         
     | 
| 
      
 98 
     | 
    
         
            +
            }
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 101 
     | 
    
         
            +
            mergeBodies(cpSpace *space, cpArray *components, cpArray *rogueBodies, cpBody *a, cpBody *b)
         
     | 
| 
      
 102 
     | 
    
         
            +
            {
         
     | 
| 
      
 103 
     | 
    
         
            +
            	// Ignore connections to static bodies
         
     | 
| 
      
 104 
     | 
    
         
            +
            	if(cpBodyIsStatic(a) || cpBodyIsStatic(b)) return;
         
     | 
| 
      
 105 
     | 
    
         
            +
            	
         
     | 
| 
      
 106 
     | 
    
         
            +
            	cpBody *a_root = componentNodeRoot(a);
         
     | 
| 
      
 107 
     | 
    
         
            +
            	cpBody *b_root = componentNodeRoot(b);
         
     | 
| 
      
 108 
     | 
    
         
            +
            	
         
     | 
| 
      
 109 
     | 
    
         
            +
            	cpBool a_sleep = cpBodyIsSleeping(a_root);
         
     | 
| 
      
 110 
     | 
    
         
            +
            	cpBool b_sleep = cpBodyIsSleeping(b_root);
         
     | 
| 
      
 111 
     | 
    
         
            +
            	
         
     | 
| 
      
 112 
     | 
    
         
            +
            	if(a_sleep && b_sleep){
         
     | 
| 
      
 113 
     | 
    
         
            +
            		return;
         
     | 
| 
      
 114 
     | 
    
         
            +
            	} else if(a_sleep || b_sleep){
         
     | 
| 
      
 115 
     | 
    
         
            +
            		componentActivate(a_root);
         
     | 
| 
      
 116 
     | 
    
         
            +
            		componentActivate(b_root);
         
     | 
| 
      
 117 
     | 
    
         
            +
            	} 
         
     | 
| 
      
 118 
     | 
    
         
            +
            	
         
     | 
| 
      
 119 
     | 
    
         
            +
            	// Add any rogue bodies found to the list and reset the idle time of anything they touch.
         
     | 
| 
      
 120 
     | 
    
         
            +
            	if(cpBodyIsRogue(a)){ cpArrayPush(rogueBodies, a); b->node.idleTime = 0.0f; }
         
     | 
| 
      
 121 
     | 
    
         
            +
            	if(cpBodyIsRogue(b)){ cpArrayPush(rogueBodies, b); a->node.idleTime = 0.0f; }
         
     | 
| 
      
 122 
     | 
    
         
            +
            	
         
     | 
| 
      
 123 
     | 
    
         
            +
            	componentNodeMerge(a_root, b_root);
         
     | 
| 
      
 124 
     | 
    
         
            +
            }
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
            static inline cpBool
         
     | 
| 
      
 127 
     | 
    
         
            +
            componentActive(cpBody *root, cpFloat threshold)
         
     | 
| 
      
 128 
     | 
    
         
            +
            {
         
     | 
| 
      
 129 
     | 
    
         
            +
            	cpBody *body = root, *next;
         
     | 
| 
      
 130 
     | 
    
         
            +
            	do {
         
     | 
| 
      
 131 
     | 
    
         
            +
            		next = body->node.next;
         
     | 
| 
      
 132 
     | 
    
         
            +
            		if(body->node.idleTime < threshold) return cpTrue;
         
     | 
| 
      
 133 
     | 
    
         
            +
            	} while((body = next) != root);
         
     | 
| 
      
 134 
     | 
    
         
            +
            	
         
     | 
| 
      
 135 
     | 
    
         
            +
            	return cpFalse;
         
     | 
| 
      
 136 
     | 
    
         
            +
            }
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 139 
     | 
    
         
            +
            addToComponent(cpBody *body, cpArray *components)
         
     | 
| 
      
 140 
     | 
    
         
            +
            {
         
     | 
| 
      
 141 
     | 
    
         
            +
            	// Check that the body is not already added to the component list
         
     | 
| 
      
 142 
     | 
    
         
            +
            	if(body->node.next) return;
         
     | 
| 
      
 143 
     | 
    
         
            +
            	cpBody *root = componentNodeRoot(body);
         
     | 
| 
      
 144 
     | 
    
         
            +
            	
         
     | 
| 
      
 145 
     | 
    
         
            +
            	cpBody *next = root->node.next;
         
     | 
| 
      
 146 
     | 
    
         
            +
            	if(!next){
         
     | 
| 
      
 147 
     | 
    
         
            +
            		// If the root isn't part of a list yet, then it hasn't been
         
     | 
| 
      
 148 
     | 
    
         
            +
            		// added to the components list. Do that now.
         
     | 
| 
      
 149 
     | 
    
         
            +
            		cpArrayPush(components, root);
         
     | 
| 
      
 150 
     | 
    
         
            +
            		// Start the list
         
     | 
| 
      
 151 
     | 
    
         
            +
            		body->node.next = root;
         
     | 
| 
      
 152 
     | 
    
         
            +
            		root->node.next = body;
         
     | 
| 
      
 153 
     | 
    
         
            +
            	} else if(root != body) {
         
     | 
| 
      
 154 
     | 
    
         
            +
            		// Splice in body after the root.
         
     | 
| 
      
 155 
     | 
    
         
            +
            		body->node.next = next;
         
     | 
| 
      
 156 
     | 
    
         
            +
            		root->node.next = body;
         
     | 
| 
      
 157 
     | 
    
         
            +
            	}
         
     | 
| 
      
 158 
     | 
    
         
            +
            }
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            // TODO this function needs more commenting.
         
     | 
| 
      
 161 
     | 
    
         
            +
            void
         
     | 
| 
      
 162 
     | 
    
         
            +
            cpSpaceProcessComponents(cpSpace *space, cpFloat dt)
         
     | 
| 
      
 163 
     | 
    
         
            +
            {
         
     | 
| 
      
 164 
     | 
    
         
            +
            	cpArray *bodies = space->bodies;
         
     | 
| 
      
 165 
     | 
    
         
            +
            	cpArray *newBodies = cpArrayNew(bodies->num);
         
     | 
| 
      
 166 
     | 
    
         
            +
            	cpArray *rogueBodies = cpArrayNew(16);
         
     | 
| 
      
 167 
     | 
    
         
            +
            	cpArray *arbiters = space->arbiters;
         
     | 
| 
      
 168 
     | 
    
         
            +
            	cpArray *constraints = space->constraints;
         
     | 
| 
      
 169 
     | 
    
         
            +
            	cpArray *components = cpArrayNew(space->sleepingComponents->num);
         
     | 
| 
      
 170 
     | 
    
         
            +
            	
         
     | 
| 
      
 171 
     | 
    
         
            +
            	cpFloat dv = space->idleSpeedThreshold;
         
     | 
| 
      
 172 
     | 
    
         
            +
            	cpFloat dvsq = (dv ? dv*dv : cpvdot(space->gravity, space->gravity)*dt*dt);
         
     | 
| 
      
 173 
     | 
    
         
            +
            	
         
     | 
| 
      
 174 
     | 
    
         
            +
            	// update idling
         
     | 
| 
      
 175 
     | 
    
         
            +
            	for(int i=0; i<bodies->num; i++){
         
     | 
| 
      
 176 
     | 
    
         
            +
            		cpBody *body = (cpBody*)bodies->arr[i];
         
     | 
| 
      
 177 
     | 
    
         
            +
            		
         
     | 
| 
      
 178 
     | 
    
         
            +
            		cpFloat thresh = (dvsq ? body->m*dvsq : 0.0f);
         
     | 
| 
      
 179 
     | 
    
         
            +
            		body->node.idleTime = (cpBodyKineticEnergy(body) > thresh ? 0.0f : body->node.idleTime + dt);
         
     | 
| 
      
 180 
     | 
    
         
            +
            	}
         
     | 
| 
      
 181 
     | 
    
         
            +
            	
         
     | 
| 
      
 182 
     | 
    
         
            +
            	// iterate graph edges and build forests
         
     | 
| 
      
 183 
     | 
    
         
            +
            	for(int i=0; i<arbiters->num; i++){
         
     | 
| 
      
 184 
     | 
    
         
            +
            		cpArbiter *arb = (cpArbiter*)arbiters->arr[i];
         
     | 
| 
      
 185 
     | 
    
         
            +
            		mergeBodies(space, components, rogueBodies, arb->a->body, arb->b->body);
         
     | 
| 
      
 186 
     | 
    
         
            +
            	}
         
     | 
| 
      
 187 
     | 
    
         
            +
            	for(int j=0; j<constraints->num; j++){
         
     | 
| 
      
 188 
     | 
    
         
            +
            		cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
         
     | 
| 
      
 189 
     | 
    
         
            +
            		mergeBodies(space, components, rogueBodies, constraint->a, constraint->b);
         
     | 
| 
      
 190 
     | 
    
         
            +
            	}
         
     | 
| 
      
 191 
     | 
    
         
            +
            	
         
     | 
| 
      
 192 
     | 
    
         
            +
            	// iterate bodies and add them to their components
         
     | 
| 
      
 193 
     | 
    
         
            +
            	for(int i=0; i<bodies->num; i++) addToComponent((cpBody*)bodies->arr[i], components);
         
     | 
| 
      
 194 
     | 
    
         
            +
            	for(int i=0; i<rogueBodies->num; i++) addToComponent((cpBody*)rogueBodies->arr[i], components);
         
     | 
| 
      
 195 
     | 
    
         
            +
            	
         
     | 
| 
      
 196 
     | 
    
         
            +
            	// iterate components, copy or deactivate
         
     | 
| 
      
 197 
     | 
    
         
            +
            	for(int i=0; i<components->num; i++){
         
     | 
| 
      
 198 
     | 
    
         
            +
            		cpBody *root = (cpBody*)components->arr[i];
         
     | 
| 
      
 199 
     | 
    
         
            +
            		if(componentActive(root, space->sleepTimeThreshold)){
         
     | 
| 
      
 200 
     | 
    
         
            +
            			cpBody *body = root, *next;
         
     | 
| 
      
 201 
     | 
    
         
            +
            			do {
         
     | 
| 
      
 202 
     | 
    
         
            +
            				next = body->node.next;
         
     | 
| 
      
 203 
     | 
    
         
            +
            				
         
     | 
| 
      
 204 
     | 
    
         
            +
            				if(!cpBodyIsRogue(body)) cpArrayPush(newBodies, body);
         
     | 
| 
      
 205 
     | 
    
         
            +
            				cpComponentNode node = {NULL, NULL, 0, body->node.idleTime};
         
     | 
| 
      
 206 
     | 
    
         
            +
            				body->node = node;
         
     | 
| 
      
 207 
     | 
    
         
            +
            			} while((body = next) != root);
         
     | 
| 
      
 208 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 209 
     | 
    
         
            +
            			cpBody *body = root, *next;
         
     | 
| 
      
 210 
     | 
    
         
            +
            			do {
         
     | 
| 
      
 211 
     | 
    
         
            +
            				next = body->node.next;
         
     | 
| 
      
 212 
     | 
    
         
            +
            				
         
     | 
| 
      
 213 
     | 
    
         
            +
            				for(cpShape *shape = body->shapesList; shape; shape = shape->next){
         
     | 
| 
      
 214 
     | 
    
         
            +
            					cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
         
     | 
| 
      
 215 
     | 
    
         
            +
            					cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
         
     | 
| 
      
 216 
     | 
    
         
            +
            				}
         
     | 
| 
      
 217 
     | 
    
         
            +
            			} while((body = next) != root);
         
     | 
| 
      
 218 
     | 
    
         
            +
            			
         
     | 
| 
      
 219 
     | 
    
         
            +
            			cpArrayPush(space->sleepingComponents, root);
         
     | 
| 
      
 220 
     | 
    
         
            +
            		}
         
     | 
| 
      
 221 
     | 
    
         
            +
            	}
         
     | 
| 
      
 222 
     | 
    
         
            +
            	
         
     | 
| 
      
 223 
     | 
    
         
            +
            	space->bodies = newBodies;
         
     | 
| 
      
 224 
     | 
    
         
            +
            	cpArrayFree(bodies);
         
     | 
| 
      
 225 
     | 
    
         
            +
            	cpArrayFree(rogueBodies);
         
     | 
| 
      
 226 
     | 
    
         
            +
            	cpArrayFree(components);
         
     | 
| 
      
 227 
     | 
    
         
            +
            }
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
            void
         
     | 
| 
      
 230 
     | 
    
         
            +
            cpBodySleep(cpBody *body)
         
     | 
| 
      
 231 
     | 
    
         
            +
            {
         
     | 
| 
      
 232 
     | 
    
         
            +
            	cpBodySleepWithGroup(body, NULL);
         
     | 
| 
      
 233 
     | 
    
         
            +
            }
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
            void
         
     | 
| 
      
 236 
     | 
    
         
            +
            cpBodySleepWithGroup(cpBody *body, cpBody *group){
         
     | 
| 
      
 237 
     | 
    
         
            +
            	cpAssert(!cpBodyIsStatic(body) && !cpBodyIsRogue(body), "Rogue and static bodies cannot be put to sleep.");
         
     | 
| 
      
 238 
     | 
    
         
            +
            	
         
     | 
| 
      
 239 
     | 
    
         
            +
            	cpSpace *space = body->space;
         
     | 
| 
      
 240 
     | 
    
         
            +
            	cpAssert(space, "Cannot put a body to sleep that has not been added to a space.");
         
     | 
| 
      
 241 
     | 
    
         
            +
            	cpAssert(!space->locked, "Bodies can not be put to sleep during a query or a call to cpSpaceSte(). Put these calls into a post-step callback.");
         
     | 
| 
      
 242 
     | 
    
         
            +
            	cpAssert(!group || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier.");
         
     | 
| 
      
 243 
     | 
    
         
            +
            	
         
     | 
| 
      
 244 
     | 
    
         
            +
            	if(cpBodyIsSleeping(body)) return;
         
     | 
| 
      
 245 
     | 
    
         
            +
            	
         
     | 
| 
      
 246 
     | 
    
         
            +
            	for(cpShape *shape = body->shapesList; shape; shape = shape->next){
         
     | 
| 
      
 247 
     | 
    
         
            +
            		cpShapeCacheBB(shape);
         
     | 
| 
      
 248 
     | 
    
         
            +
            		cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
         
     | 
| 
      
 249 
     | 
    
         
            +
            		cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
         
     | 
| 
      
 250 
     | 
    
         
            +
            	}
         
     | 
| 
      
 251 
     | 
    
         
            +
            	
         
     | 
| 
      
 252 
     | 
    
         
            +
            	if(group){
         
     | 
| 
      
 253 
     | 
    
         
            +
            		cpBody *root = componentNodeRoot(group);
         
     | 
| 
      
 254 
     | 
    
         
            +
            		
         
     | 
| 
      
 255 
     | 
    
         
            +
            		cpComponentNode node = {root, root->node.next, 0, 0.0f};
         
     | 
| 
      
 256 
     | 
    
         
            +
            		body->node = node;
         
     | 
| 
      
 257 
     | 
    
         
            +
            		root->node.next = body;
         
     | 
| 
      
 258 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 259 
     | 
    
         
            +
            		cpComponentNode node = {NULL, body, 0, 0.0f};
         
     | 
| 
      
 260 
     | 
    
         
            +
            		body->node = node;
         
     | 
| 
      
 261 
     | 
    
         
            +
            		
         
     | 
| 
      
 262 
     | 
    
         
            +
            		cpArrayPush(space->sleepingComponents, body);
         
     | 
| 
      
 263 
     | 
    
         
            +
            	}
         
     | 
| 
      
 264 
     | 
    
         
            +
            	
         
     | 
| 
      
 265 
     | 
    
         
            +
            	cpArrayDeleteObj(space->bodies, body);
         
     | 
| 
      
 266 
     | 
    
         
            +
            }
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
            static void
         
     | 
| 
      
 269 
     | 
    
         
            +
            activateTouchingHelper(cpShape *shape, cpContactPointSet *points, cpArray **bodies){
         
     | 
| 
      
 270 
     | 
    
         
            +
            	cpBodyActivate(shape->body);
         
     | 
| 
      
 271 
     | 
    
         
            +
            }
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
            void
         
     | 
| 
      
 274 
     | 
    
         
            +
            cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape){
         
     | 
| 
      
 275 
     | 
    
         
            +
            	cpArray *bodies = NULL;
         
     | 
| 
      
 276 
     | 
    
         
            +
            	cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)activateTouchingHelper, &bodies);
         
     | 
| 
      
 277 
     | 
    
         
            +
            }
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,534 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* Copyright (c) 2007 Scott Lembcke
         
     | 
| 
      
 2 
     | 
    
         
            +
             * 
         
     | 
| 
      
 3 
     | 
    
         
            +
             * Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 4 
     | 
    
         
            +
             * of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 5 
     | 
    
         
            +
             * in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 6 
     | 
    
         
            +
             * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 7 
     | 
    
         
            +
             * copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 8 
     | 
    
         
            +
             * furnished to do so, subject to the following conditions:
         
     | 
| 
      
 9 
     | 
    
         
            +
             * 
         
     | 
| 
      
 10 
     | 
    
         
            +
             * The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 11 
     | 
    
         
            +
             * all copies or substantial portions of the Software.
         
     | 
| 
      
 12 
     | 
    
         
            +
             * 
         
     | 
| 
      
 13 
     | 
    
         
            +
             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 14 
     | 
    
         
            +
             * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 15 
     | 
    
         
            +
             * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 16 
     | 
    
         
            +
             * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 17 
     | 
    
         
            +
             * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 18 
     | 
    
         
            +
             * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 19 
     | 
    
         
            +
             * SOFTWARE.
         
     | 
| 
      
 20 
     | 
    
         
            +
             */
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            #include <math.h>
         
     | 
| 
      
 23 
     | 
    
         
            +
            #include <stdlib.h>
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            #include "chipmunk_private.h"
         
     | 
| 
      
 26 
     | 
    
         
            +
            #include "prime.h"
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            static cpHandle*
         
     | 
| 
      
 29 
     | 
    
         
            +
            cpHandleInit(cpHandle *hand, void *obj)
         
     | 
| 
      
 30 
     | 
    
         
            +
            {
         
     | 
| 
      
 31 
     | 
    
         
            +
            	hand->obj = obj;
         
     | 
| 
      
 32 
     | 
    
         
            +
            	hand->retain = 0;
         
     | 
| 
      
 33 
     | 
    
         
            +
            	hand->stamp = 0;
         
     | 
| 
      
 34 
     | 
    
         
            +
            	
         
     | 
| 
      
 35 
     | 
    
         
            +
            	return hand;
         
     | 
| 
      
 36 
     | 
    
         
            +
            }
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            static inline void cpHandleRetain(cpHandle *hand){hand->retain++;}
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 41 
     | 
    
         
            +
            cpHandleRelease(cpHandle *hand, cpArray *pooledHandles)
         
     | 
| 
      
 42 
     | 
    
         
            +
            {
         
     | 
| 
      
 43 
     | 
    
         
            +
            	hand->retain--;
         
     | 
| 
      
 44 
     | 
    
         
            +
            	if(hand->retain == 0) cpArrayPush(pooledHandles, hand);
         
     | 
| 
      
 45 
     | 
    
         
            +
            }
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            cpSpaceHash*
         
     | 
| 
      
 48 
     | 
    
         
            +
            cpSpaceHashAlloc(void)
         
     | 
| 
      
 49 
     | 
    
         
            +
            {
         
     | 
| 
      
 50 
     | 
    
         
            +
            	return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash));
         
     | 
| 
      
 51 
     | 
    
         
            +
            }
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            // Frees the old table, and allocate a new one.
         
     | 
| 
      
 54 
     | 
    
         
            +
            static void
         
     | 
| 
      
 55 
     | 
    
         
            +
            cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
         
     | 
| 
      
 56 
     | 
    
         
            +
            {
         
     | 
| 
      
 57 
     | 
    
         
            +
            	cpfree(hash->table);
         
     | 
| 
      
 58 
     | 
    
         
            +
            	
         
     | 
| 
      
 59 
     | 
    
         
            +
            	hash->numcells = numcells;
         
     | 
| 
      
 60 
     | 
    
         
            +
            	hash->table = (cpSpaceHashBin **)cpcalloc(numcells, sizeof(cpSpaceHashBin *));
         
     | 
| 
      
 61 
     | 
    
         
            +
            }
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            // Equality function for the handleset.
         
     | 
| 
      
 64 
     | 
    
         
            +
            static int handleSetEql(void *obj, cpHandle *hand){return (obj == hand->obj);}
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            // Transformation function for the handleset.
         
     | 
| 
      
 67 
     | 
    
         
            +
            static void *
         
     | 
| 
      
 68 
     | 
    
         
            +
            handleSetTrans(void *obj, cpSpaceHash *hash)
         
     | 
| 
      
 69 
     | 
    
         
            +
            {
         
     | 
| 
      
 70 
     | 
    
         
            +
            	if(hash->pooledHandles->num == 0){
         
     | 
| 
      
 71 
     | 
    
         
            +
            		// handle pool is exhausted, make more
         
     | 
| 
      
 72 
     | 
    
         
            +
            		int count = CP_BUFFER_BYTES/sizeof(cpHandle);
         
     | 
| 
      
 73 
     | 
    
         
            +
            		cpAssert(count, "Buffer size is too small.");
         
     | 
| 
      
 74 
     | 
    
         
            +
            		
         
     | 
| 
      
 75 
     | 
    
         
            +
            		cpHandle *buffer = (cpHandle *)cpmalloc(CP_BUFFER_BYTES);
         
     | 
| 
      
 76 
     | 
    
         
            +
            		cpArrayPush(hash->allocatedBuffers, buffer);
         
     | 
| 
      
 77 
     | 
    
         
            +
            		
         
     | 
| 
      
 78 
     | 
    
         
            +
            		for(int i=0; i<count; i++) cpArrayPush(hash->pooledHandles, buffer + i);
         
     | 
| 
      
 79 
     | 
    
         
            +
            	}
         
     | 
| 
      
 80 
     | 
    
         
            +
            	
         
     | 
| 
      
 81 
     | 
    
         
            +
            	cpHandle *hand = cpHandleInit((cpHandle *) cpArrayPop(hash->pooledHandles), obj);
         
     | 
| 
      
 82 
     | 
    
         
            +
            	cpHandleRetain(hand);
         
     | 
| 
      
 83 
     | 
    
         
            +
            	
         
     | 
| 
      
 84 
     | 
    
         
            +
            	return hand;
         
     | 
| 
      
 85 
     | 
    
         
            +
            }
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            cpSpaceHash*
         
     | 
| 
      
 88 
     | 
    
         
            +
            cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBFunc bbfunc)
         
     | 
| 
      
 89 
     | 
    
         
            +
            {
         
     | 
| 
      
 90 
     | 
    
         
            +
            	cpSpaceHashAllocTable(hash, next_prime(numcells));
         
     | 
| 
      
 91 
     | 
    
         
            +
            	hash->celldim = celldim;
         
     | 
| 
      
 92 
     | 
    
         
            +
            	hash->bbfunc = bbfunc;
         
     | 
| 
      
 93 
     | 
    
         
            +
            	
         
     | 
| 
      
 94 
     | 
    
         
            +
            	hash->handleSet = cpHashSetNew(0, (cpHashSetEqlFunc)handleSetEql, (cpHashSetTransFunc)handleSetTrans);
         
     | 
| 
      
 95 
     | 
    
         
            +
            	hash->pooledHandles = cpArrayNew(0);
         
     | 
| 
      
 96 
     | 
    
         
            +
            	
         
     | 
| 
      
 97 
     | 
    
         
            +
            	hash->pooledBins = NULL;
         
     | 
| 
      
 98 
     | 
    
         
            +
            	hash->allocatedBuffers = cpArrayNew(0);
         
     | 
| 
      
 99 
     | 
    
         
            +
            	
         
     | 
| 
      
 100 
     | 
    
         
            +
            	hash->stamp = 1;
         
     | 
| 
      
 101 
     | 
    
         
            +
            	
         
     | 
| 
      
 102 
     | 
    
         
            +
            	return hash;
         
     | 
| 
      
 103 
     | 
    
         
            +
            }
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            cpSpaceHash*
         
     | 
| 
      
 106 
     | 
    
         
            +
            cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc)
         
     | 
| 
      
 107 
     | 
    
         
            +
            {
         
     | 
| 
      
 108 
     | 
    
         
            +
            	return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc);
         
     | 
| 
      
 109 
     | 
    
         
            +
            }
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 112 
     | 
    
         
            +
            recycleBin(cpSpaceHash *hash, cpSpaceHashBin *bin)
         
     | 
| 
      
 113 
     | 
    
         
            +
            {
         
     | 
| 
      
 114 
     | 
    
         
            +
            	bin->next = hash->pooledBins;
         
     | 
| 
      
 115 
     | 
    
         
            +
            	hash->pooledBins = bin;
         
     | 
| 
      
 116 
     | 
    
         
            +
            }
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 119 
     | 
    
         
            +
            clearHashCell(cpSpaceHash *hash, int idx)
         
     | 
| 
      
 120 
     | 
    
         
            +
            {
         
     | 
| 
      
 121 
     | 
    
         
            +
            	cpSpaceHashBin *bin = hash->table[idx];
         
     | 
| 
      
 122 
     | 
    
         
            +
            	while(bin){
         
     | 
| 
      
 123 
     | 
    
         
            +
            		cpSpaceHashBin *next = bin->next;
         
     | 
| 
      
 124 
     | 
    
         
            +
            		
         
     | 
| 
      
 125 
     | 
    
         
            +
            		cpHandleRelease(bin->handle, hash->pooledHandles);
         
     | 
| 
      
 126 
     | 
    
         
            +
            		recycleBin(hash, bin);
         
     | 
| 
      
 127 
     | 
    
         
            +
            		
         
     | 
| 
      
 128 
     | 
    
         
            +
            		bin = next;
         
     | 
| 
      
 129 
     | 
    
         
            +
            	}
         
     | 
| 
      
 130 
     | 
    
         
            +
            	
         
     | 
| 
      
 131 
     | 
    
         
            +
            	hash->table[idx] = NULL;
         
     | 
| 
      
 132 
     | 
    
         
            +
            }
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
            // Clear all cells in the hashtable.
         
     | 
| 
      
 135 
     | 
    
         
            +
            static void
         
     | 
| 
      
 136 
     | 
    
         
            +
            clearHash(cpSpaceHash *hash)
         
     | 
| 
      
 137 
     | 
    
         
            +
            {
         
     | 
| 
      
 138 
     | 
    
         
            +
            	for(int i=0; i<hash->numcells; i++)
         
     | 
| 
      
 139 
     | 
    
         
            +
            		clearHashCell(hash, i);
         
     | 
| 
      
 140 
     | 
    
         
            +
            }
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
            static void freeWrap(void *ptr, void *unused){cpfree(ptr);}
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            void
         
     | 
| 
      
 145 
     | 
    
         
            +
            cpSpaceHashDestroy(cpSpaceHash *hash)
         
     | 
| 
      
 146 
     | 
    
         
            +
            {
         
     | 
| 
      
 147 
     | 
    
         
            +
            	clearHash(hash);
         
     | 
| 
      
 148 
     | 
    
         
            +
            	
         
     | 
| 
      
 149 
     | 
    
         
            +
            	cpHashSetFree(hash->handleSet);
         
     | 
| 
      
 150 
     | 
    
         
            +
            	
         
     | 
| 
      
 151 
     | 
    
         
            +
            	cpArrayEach(hash->allocatedBuffers, freeWrap, NULL);
         
     | 
| 
      
 152 
     | 
    
         
            +
            	cpArrayFree(hash->allocatedBuffers);
         
     | 
| 
      
 153 
     | 
    
         
            +
            	cpArrayFree(hash->pooledHandles);
         
     | 
| 
      
 154 
     | 
    
         
            +
            	
         
     | 
| 
      
 155 
     | 
    
         
            +
            	cpfree(hash->table);
         
     | 
| 
      
 156 
     | 
    
         
            +
            }
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
            void
         
     | 
| 
      
 159 
     | 
    
         
            +
            cpSpaceHashFree(cpSpaceHash *hash)
         
     | 
| 
      
 160 
     | 
    
         
            +
            {
         
     | 
| 
      
 161 
     | 
    
         
            +
            	if(hash){
         
     | 
| 
      
 162 
     | 
    
         
            +
            		cpSpaceHashDestroy(hash);
         
     | 
| 
      
 163 
     | 
    
         
            +
            		cpfree(hash);
         
     | 
| 
      
 164 
     | 
    
         
            +
            	}
         
     | 
| 
      
 165 
     | 
    
         
            +
            }
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
            void
         
     | 
| 
      
 168 
     | 
    
         
            +
            cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)
         
     | 
| 
      
 169 
     | 
    
         
            +
            {
         
     | 
| 
      
 170 
     | 
    
         
            +
            	// Clear the hash to release the old handle locks.
         
     | 
| 
      
 171 
     | 
    
         
            +
            	clearHash(hash);
         
     | 
| 
      
 172 
     | 
    
         
            +
            	
         
     | 
| 
      
 173 
     | 
    
         
            +
            	hash->celldim = celldim;
         
     | 
| 
      
 174 
     | 
    
         
            +
            	cpSpaceHashAllocTable(hash, next_prime(numcells));
         
     | 
| 
      
 175 
     | 
    
         
            +
            }
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
            // Return true if the chain contains the handle.
         
     | 
| 
      
 178 
     | 
    
         
            +
            static inline cpBool
         
     | 
| 
      
 179 
     | 
    
         
            +
            containsHandle(cpSpaceHashBin *bin, cpHandle *hand)
         
     | 
| 
      
 180 
     | 
    
         
            +
            {
         
     | 
| 
      
 181 
     | 
    
         
            +
            	while(bin){
         
     | 
| 
      
 182 
     | 
    
         
            +
            		if(bin->handle == hand) return cpTrue;
         
     | 
| 
      
 183 
     | 
    
         
            +
            		bin = bin->next;
         
     | 
| 
      
 184 
     | 
    
         
            +
            	}
         
     | 
| 
      
 185 
     | 
    
         
            +
            	
         
     | 
| 
      
 186 
     | 
    
         
            +
            	return cpFalse;
         
     | 
| 
      
 187 
     | 
    
         
            +
            }
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            // Get a recycled or new bin.
         
     | 
| 
      
 190 
     | 
    
         
            +
            static inline cpSpaceHashBin *
         
     | 
| 
      
 191 
     | 
    
         
            +
            getEmptyBin(cpSpaceHash *hash)
         
     | 
| 
      
 192 
     | 
    
         
            +
            {
         
     | 
| 
      
 193 
     | 
    
         
            +
            	cpSpaceHashBin *bin = hash->pooledBins;
         
     | 
| 
      
 194 
     | 
    
         
            +
            	
         
     | 
| 
      
 195 
     | 
    
         
            +
            	if(bin){
         
     | 
| 
      
 196 
     | 
    
         
            +
            		hash->pooledBins = bin->next;
         
     | 
| 
      
 197 
     | 
    
         
            +
            		return bin;
         
     | 
| 
      
 198 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 199 
     | 
    
         
            +
            		// Pool is exhausted, make more
         
     | 
| 
      
 200 
     | 
    
         
            +
            		int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin);
         
     | 
| 
      
 201 
     | 
    
         
            +
            		cpAssert(count, "Buffer size is too small.");
         
     | 
| 
      
 202 
     | 
    
         
            +
            		
         
     | 
| 
      
 203 
     | 
    
         
            +
            		cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpmalloc(CP_BUFFER_BYTES);
         
     | 
| 
      
 204 
     | 
    
         
            +
            		cpArrayPush(hash->allocatedBuffers, buffer);
         
     | 
| 
      
 205 
     | 
    
         
            +
            		
         
     | 
| 
      
 206 
     | 
    
         
            +
            		// push all but the first one, return the first instead
         
     | 
| 
      
 207 
     | 
    
         
            +
            		for(int i=1; i<count; i++) recycleBin(hash, buffer + i);
         
     | 
| 
      
 208 
     | 
    
         
            +
            		return buffer;
         
     | 
| 
      
 209 
     | 
    
         
            +
            	}
         
     | 
| 
      
 210 
     | 
    
         
            +
            }
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
            // The hash function itself.
         
     | 
| 
      
 213 
     | 
    
         
            +
            static inline cpHashValue
         
     | 
| 
      
 214 
     | 
    
         
            +
            hash_func(cpHashValue x, cpHashValue y, cpHashValue n)
         
     | 
| 
      
 215 
     | 
    
         
            +
            {
         
     | 
| 
      
 216 
     | 
    
         
            +
            	return (x*1640531513ul ^ y*2654435789ul) % n;
         
     | 
| 
      
 217 
     | 
    
         
            +
            }
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
            // Much faster than (int)floor(f)
         
     | 
| 
      
 220 
     | 
    
         
            +
            // Profiling showed floor() to be a sizable performance hog
         
     | 
| 
      
 221 
     | 
    
         
            +
            static inline int
         
     | 
| 
      
 222 
     | 
    
         
            +
            floor_int(cpFloat f)
         
     | 
| 
      
 223 
     | 
    
         
            +
            {
         
     | 
| 
      
 224 
     | 
    
         
            +
            	int i = (int)f;
         
     | 
| 
      
 225 
     | 
    
         
            +
            	return (f < 0.0f && f != i ? i - 1 : i);
         
     | 
| 
      
 226 
     | 
    
         
            +
            }
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 229 
     | 
    
         
            +
            hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
         
     | 
| 
      
 230 
     | 
    
         
            +
            {
         
     | 
| 
      
 231 
     | 
    
         
            +
            	// Find the dimensions in cell coordinates.
         
     | 
| 
      
 232 
     | 
    
         
            +
            	cpFloat dim = hash->celldim;
         
     | 
| 
      
 233 
     | 
    
         
            +
            	int l = floor_int(bb.l/dim); // Fix by ShiftZ
         
     | 
| 
      
 234 
     | 
    
         
            +
            	int r = floor_int(bb.r/dim);
         
     | 
| 
      
 235 
     | 
    
         
            +
            	int b = floor_int(bb.b/dim);
         
     | 
| 
      
 236 
     | 
    
         
            +
            	int t = floor_int(bb.t/dim);
         
     | 
| 
      
 237 
     | 
    
         
            +
            	
         
     | 
| 
      
 238 
     | 
    
         
            +
            	int n = hash->numcells;
         
     | 
| 
      
 239 
     | 
    
         
            +
            	for(int i=l; i<=r; i++){
         
     | 
| 
      
 240 
     | 
    
         
            +
            		for(int j=b; j<=t; j++){
         
     | 
| 
      
 241 
     | 
    
         
            +
            			int idx = hash_func(i,j,n);
         
     | 
| 
      
 242 
     | 
    
         
            +
            			cpSpaceHashBin *bin = hash->table[idx];
         
     | 
| 
      
 243 
     | 
    
         
            +
            			
         
     | 
| 
      
 244 
     | 
    
         
            +
            			// Don't add an object twice to the same cell.
         
     | 
| 
      
 245 
     | 
    
         
            +
            			if(containsHandle(bin, hand)) continue;
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
            			cpHandleRetain(hand);
         
     | 
| 
      
 248 
     | 
    
         
            +
            			// Insert a new bin for the handle in this cell.
         
     | 
| 
      
 249 
     | 
    
         
            +
            			cpSpaceHashBin *newBin = getEmptyBin(hash);
         
     | 
| 
      
 250 
     | 
    
         
            +
            			newBin->handle = hand;
         
     | 
| 
      
 251 
     | 
    
         
            +
            			newBin->next = bin;
         
     | 
| 
      
 252 
     | 
    
         
            +
            			hash->table[idx] = newBin;
         
     | 
| 
      
 253 
     | 
    
         
            +
            		}
         
     | 
| 
      
 254 
     | 
    
         
            +
            	}
         
     | 
| 
      
 255 
     | 
    
         
            +
            }
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
            void
         
     | 
| 
      
 258 
     | 
    
         
            +
            cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB _deprecated_unused)
         
     | 
| 
      
 259 
     | 
    
         
            +
            {
         
     | 
| 
      
 260 
     | 
    
         
            +
            	cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash);
         
     | 
| 
      
 261 
     | 
    
         
            +
            	hashHandle(hash, hand, hash->bbfunc(obj));
         
     | 
| 
      
 262 
     | 
    
         
            +
            }
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
            void
         
     | 
| 
      
 265 
     | 
    
         
            +
            cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid)
         
     | 
| 
      
 266 
     | 
    
         
            +
            {
         
     | 
| 
      
 267 
     | 
    
         
            +
            	cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
         
     | 
| 
      
 268 
     | 
    
         
            +
            	
         
     | 
| 
      
 269 
     | 
    
         
            +
            	if(hand){
         
     | 
| 
      
 270 
     | 
    
         
            +
            		hand->obj = NULL;
         
     | 
| 
      
 271 
     | 
    
         
            +
            		cpHandleRelease(hand, hash->pooledHandles);
         
     | 
| 
      
 272 
     | 
    
         
            +
            		
         
     | 
| 
      
 273 
     | 
    
         
            +
            		cpSpaceHashInsert(hash, obj, hashid, cpBBNew(0.0f, 0.0f, 0.0f, 0.0f));
         
     | 
| 
      
 274 
     | 
    
         
            +
            	}
         
     | 
| 
      
 275 
     | 
    
         
            +
            }
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
            static void handleRehashHelper(cpHandle *hand, cpSpaceHash *hash){hashHandle(hash, hand, hash->bbfunc(hand->obj));}
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
            void
         
     | 
| 
      
 280 
     | 
    
         
            +
            cpSpaceHashRehash(cpSpaceHash *hash)
         
     | 
| 
      
 281 
     | 
    
         
            +
            {
         
     | 
| 
      
 282 
     | 
    
         
            +
            	clearHash(hash);
         
     | 
| 
      
 283 
     | 
    
         
            +
            	cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)handleRehashHelper, hash);
         
     | 
| 
      
 284 
     | 
    
         
            +
            }
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
            void
         
     | 
| 
      
 287 
     | 
    
         
            +
            cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid)
         
     | 
| 
      
 288 
     | 
    
         
            +
            {
         
     | 
| 
      
 289 
     | 
    
         
            +
            	cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
         
     | 
| 
      
 290 
     | 
    
         
            +
            	
         
     | 
| 
      
 291 
     | 
    
         
            +
            	if(hand){
         
     | 
| 
      
 292 
     | 
    
         
            +
            		hand->obj = NULL;
         
     | 
| 
      
 293 
     | 
    
         
            +
            		cpHandleRelease(hand, hash->pooledHandles);
         
     | 
| 
      
 294 
     | 
    
         
            +
            	}
         
     | 
| 
      
 295 
     | 
    
         
            +
            }
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
            typedef struct eachPair {
         
     | 
| 
      
 298 
     | 
    
         
            +
            	cpSpaceHashIterator func;
         
     | 
| 
      
 299 
     | 
    
         
            +
            	void *data;
         
     | 
| 
      
 300 
     | 
    
         
            +
            } eachPair;
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
            static void eachHelper(cpHandle *hand, eachPair *pair){pair->func(hand->obj, pair->data);}
         
     | 
| 
      
 303 
     | 
    
         
            +
             
     | 
| 
      
 304 
     | 
    
         
            +
            // Iterate over the objects in the spatial hash.
         
     | 
| 
      
 305 
     | 
    
         
            +
            void
         
     | 
| 
      
 306 
     | 
    
         
            +
            cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)
         
     | 
| 
      
 307 
     | 
    
         
            +
            {
         
     | 
| 
      
 308 
     | 
    
         
            +
            	eachPair pair = {func, data};
         
     | 
| 
      
 309 
     | 
    
         
            +
            	cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)eachHelper, &pair);
         
     | 
| 
      
 310 
     | 
    
         
            +
            }
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 313 
     | 
    
         
            +
            removeOrphanedHandles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr)
         
     | 
| 
      
 314 
     | 
    
         
            +
            {
         
     | 
| 
      
 315 
     | 
    
         
            +
            	cpSpaceHashBin *bin = *bin_ptr;
         
     | 
| 
      
 316 
     | 
    
         
            +
            	while(bin){
         
     | 
| 
      
 317 
     | 
    
         
            +
            		cpHandle *hand = bin->handle;
         
     | 
| 
      
 318 
     | 
    
         
            +
            		cpSpaceHashBin *next = bin->next;
         
     | 
| 
      
 319 
     | 
    
         
            +
            		
         
     | 
| 
      
 320 
     | 
    
         
            +
            		if(!hand->obj){
         
     | 
| 
      
 321 
     | 
    
         
            +
            			// orphaned handle, unlink and recycle the bin
         
     | 
| 
      
 322 
     | 
    
         
            +
            			(*bin_ptr) = bin->next;
         
     | 
| 
      
 323 
     | 
    
         
            +
            			recycleBin(hash, bin);
         
     | 
| 
      
 324 
     | 
    
         
            +
            			
         
     | 
| 
      
 325 
     | 
    
         
            +
            			cpHandleRelease(hand, hash->pooledHandles);
         
     | 
| 
      
 326 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 327 
     | 
    
         
            +
            			bin_ptr = &bin->next;
         
     | 
| 
      
 328 
     | 
    
         
            +
            		}
         
     | 
| 
      
 329 
     | 
    
         
            +
            		
         
     | 
| 
      
 330 
     | 
    
         
            +
            		bin = next;
         
     | 
| 
      
 331 
     | 
    
         
            +
            	}
         
     | 
| 
      
 332 
     | 
    
         
            +
            }
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
            // Calls the callback function for the objects in a given chain.
         
     | 
| 
      
 335 
     | 
    
         
            +
            static inline void
         
     | 
| 
      
 336 
     | 
    
         
            +
            query(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashQueryFunc func, void *data)
         
     | 
| 
      
 337 
     | 
    
         
            +
            {
         
     | 
| 
      
 338 
     | 
    
         
            +
            	restart:
         
     | 
| 
      
 339 
     | 
    
         
            +
            	for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
         
     | 
| 
      
 340 
     | 
    
         
            +
            		cpHandle *hand = bin->handle;
         
     | 
| 
      
 341 
     | 
    
         
            +
            		void *other = hand->obj;
         
     | 
| 
      
 342 
     | 
    
         
            +
            		
         
     | 
| 
      
 343 
     | 
    
         
            +
            		if(hand->stamp == hash->stamp || obj == other){
         
     | 
| 
      
 344 
     | 
    
         
            +
            			continue;
         
     | 
| 
      
 345 
     | 
    
         
            +
            		} else if(other){
         
     | 
| 
      
 346 
     | 
    
         
            +
            			func(obj, other, data);
         
     | 
| 
      
 347 
     | 
    
         
            +
            			hand->stamp = hash->stamp;
         
     | 
| 
      
 348 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 349 
     | 
    
         
            +
            			// The object for this handle has been removed
         
     | 
| 
      
 350 
     | 
    
         
            +
            			// cleanup this cell and restart the query
         
     | 
| 
      
 351 
     | 
    
         
            +
            			removeOrphanedHandles(hash, bin_ptr);
         
     | 
| 
      
 352 
     | 
    
         
            +
            			goto restart; // GCC not smart enough/able to tail call an inlined function.
         
     | 
| 
      
 353 
     | 
    
         
            +
            		}
         
     | 
| 
      
 354 
     | 
    
         
            +
            	}
         
     | 
| 
      
 355 
     | 
    
         
            +
            }
         
     | 
| 
      
 356 
     | 
    
         
            +
             
     | 
| 
      
 357 
     | 
    
         
            +
            void
         
     | 
| 
      
 358 
     | 
    
         
            +
            cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data)
         
     | 
| 
      
 359 
     | 
    
         
            +
            {
         
     | 
| 
      
 360 
     | 
    
         
            +
            	cpFloat dim = hash->celldim;
         
     | 
| 
      
 361 
     | 
    
         
            +
            	int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells);  // Fix by ShiftZ
         
     | 
| 
      
 362 
     | 
    
         
            +
            	
         
     | 
| 
      
 363 
     | 
    
         
            +
            	query(hash, &hash->table[idx], &point, func, data);
         
     | 
| 
      
 364 
     | 
    
         
            +
            	hash->stamp++;
         
     | 
| 
      
 365 
     | 
    
         
            +
            }
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
            void
         
     | 
| 
      
 368 
     | 
    
         
            +
            cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data)
         
     | 
| 
      
 369 
     | 
    
         
            +
            {
         
     | 
| 
      
 370 
     | 
    
         
            +
            	// Get the dimensions in cell coordinates.
         
     | 
| 
      
 371 
     | 
    
         
            +
            	cpFloat dim = hash->celldim;
         
     | 
| 
      
 372 
     | 
    
         
            +
            	int l = floor_int(bb.l/dim);  // Fix by ShiftZ
         
     | 
| 
      
 373 
     | 
    
         
            +
            	int r = floor_int(bb.r/dim);
         
     | 
| 
      
 374 
     | 
    
         
            +
            	int b = floor_int(bb.b/dim);
         
     | 
| 
      
 375 
     | 
    
         
            +
            	int t = floor_int(bb.t/dim);
         
     | 
| 
      
 376 
     | 
    
         
            +
            	
         
     | 
| 
      
 377 
     | 
    
         
            +
            	int n = hash->numcells;
         
     | 
| 
      
 378 
     | 
    
         
            +
            	cpSpaceHashBin **table = hash->table;
         
     | 
| 
      
 379 
     | 
    
         
            +
            	
         
     | 
| 
      
 380 
     | 
    
         
            +
            	// Iterate over the cells and query them.
         
     | 
| 
      
 381 
     | 
    
         
            +
            	for(int i=l; i<=r; i++){
         
     | 
| 
      
 382 
     | 
    
         
            +
            		for(int j=b; j<=t; j++){
         
     | 
| 
      
 383 
     | 
    
         
            +
            			query(hash, &table[hash_func(i,j,n)], obj, func, data);
         
     | 
| 
      
 384 
     | 
    
         
            +
            		}
         
     | 
| 
      
 385 
     | 
    
         
            +
            	}
         
     | 
| 
      
 386 
     | 
    
         
            +
            	
         
     | 
| 
      
 387 
     | 
    
         
            +
            	hash->stamp++;
         
     | 
| 
      
 388 
     | 
    
         
            +
            }
         
     | 
| 
      
 389 
     | 
    
         
            +
             
     | 
| 
      
 390 
     | 
    
         
            +
            // Similar to struct eachPair above.
         
     | 
| 
      
 391 
     | 
    
         
            +
            typedef struct queryRehashPair {
         
     | 
| 
      
 392 
     | 
    
         
            +
            	cpSpaceHash *hash;
         
     | 
| 
      
 393 
     | 
    
         
            +
            	cpSpaceHashQueryFunc func;
         
     | 
| 
      
 394 
     | 
    
         
            +
            	void *data;
         
     | 
| 
      
 395 
     | 
    
         
            +
            } queryRehashPair;
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
            // Hashset iterator func used with cpSpaceHashQueryRehash().
         
     | 
| 
      
 398 
     | 
    
         
            +
            static void
         
     | 
| 
      
 399 
     | 
    
         
            +
            handleQueryRehashHelper(void *elt, void *data)
         
     | 
| 
      
 400 
     | 
    
         
            +
            {
         
     | 
| 
      
 401 
     | 
    
         
            +
            	cpHandle *hand = (cpHandle *)elt;
         
     | 
| 
      
 402 
     | 
    
         
            +
            	
         
     | 
| 
      
 403 
     | 
    
         
            +
            	// Unpack the user callback data.
         
     | 
| 
      
 404 
     | 
    
         
            +
            	queryRehashPair *pair = (queryRehashPair *)data;
         
     | 
| 
      
 405 
     | 
    
         
            +
            	cpSpaceHash *hash = pair->hash;
         
     | 
| 
      
 406 
     | 
    
         
            +
            	cpSpaceHashQueryFunc func = pair->func;
         
     | 
| 
      
 407 
     | 
    
         
            +
             
     | 
| 
      
 408 
     | 
    
         
            +
            	cpFloat dim = hash->celldim;
         
     | 
| 
      
 409 
     | 
    
         
            +
            	int n = hash->numcells;
         
     | 
| 
      
 410 
     | 
    
         
            +
             
     | 
| 
      
 411 
     | 
    
         
            +
            	void *obj = hand->obj;
         
     | 
| 
      
 412 
     | 
    
         
            +
            	cpBB bb = hash->bbfunc(obj);
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
      
 414 
     | 
    
         
            +
            	int l = floor_int(bb.l/dim);
         
     | 
| 
      
 415 
     | 
    
         
            +
            	int r = floor_int(bb.r/dim);
         
     | 
| 
      
 416 
     | 
    
         
            +
            	int b = floor_int(bb.b/dim);
         
     | 
| 
      
 417 
     | 
    
         
            +
            	int t = floor_int(bb.t/dim);
         
     | 
| 
      
 418 
     | 
    
         
            +
            	
         
     | 
| 
      
 419 
     | 
    
         
            +
            	cpSpaceHashBin **table = hash->table;
         
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
            	for(int i=l; i<=r; i++){
         
     | 
| 
      
 422 
     | 
    
         
            +
            		for(int j=b; j<=t; j++){
         
     | 
| 
      
 423 
     | 
    
         
            +
            			int idx = hash_func(i,j,n);
         
     | 
| 
      
 424 
     | 
    
         
            +
            			cpSpaceHashBin *bin = table[idx];
         
     | 
| 
      
 425 
     | 
    
         
            +
            			
         
     | 
| 
      
 426 
     | 
    
         
            +
            			if(containsHandle(bin, hand)) continue;
         
     | 
| 
      
 427 
     | 
    
         
            +
            			
         
     | 
| 
      
 428 
     | 
    
         
            +
            			cpHandleRetain(hand); // this MUST be done first in case the object is removed in func()
         
     | 
| 
      
 429 
     | 
    
         
            +
            			query(hash, &bin, obj, func, pair->data);
         
     | 
| 
      
 430 
     | 
    
         
            +
            			
         
     | 
| 
      
 431 
     | 
    
         
            +
            			cpSpaceHashBin *newBin = getEmptyBin(hash);
         
     | 
| 
      
 432 
     | 
    
         
            +
            			newBin->handle = hand;
         
     | 
| 
      
 433 
     | 
    
         
            +
            			newBin->next = bin;
         
     | 
| 
      
 434 
     | 
    
         
            +
            			table[idx] = newBin;
         
     | 
| 
      
 435 
     | 
    
         
            +
            		}
         
     | 
| 
      
 436 
     | 
    
         
            +
            	}
         
     | 
| 
      
 437 
     | 
    
         
            +
            	
         
     | 
| 
      
 438 
     | 
    
         
            +
            	// Increment the stamp for each object hashed.
         
     | 
| 
      
 439 
     | 
    
         
            +
            	hash->stamp++;
         
     | 
| 
      
 440 
     | 
    
         
            +
            }
         
     | 
| 
      
 441 
     | 
    
         
            +
             
     | 
| 
      
 442 
     | 
    
         
            +
            void
         
     | 
| 
      
 443 
     | 
    
         
            +
            cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)
         
     | 
| 
      
 444 
     | 
    
         
            +
            {
         
     | 
| 
      
 445 
     | 
    
         
            +
            	clearHash(hash);
         
     | 
| 
      
 446 
     | 
    
         
            +
            	
         
     | 
| 
      
 447 
     | 
    
         
            +
            	queryRehashPair pair = {hash, func, data};
         
     | 
| 
      
 448 
     | 
    
         
            +
            	cpHashSetEach(hash->handleSet, &handleQueryRehashHelper, &pair);
         
     | 
| 
      
 449 
     | 
    
         
            +
            }
         
     | 
| 
      
 450 
     | 
    
         
            +
             
     | 
| 
      
 451 
     | 
    
         
            +
            static inline cpFloat
         
     | 
| 
      
 452 
     | 
    
         
            +
            segmentQuery(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashSegmentQueryFunc func, void *data)
         
     | 
| 
      
 453 
     | 
    
         
            +
            {
         
     | 
| 
      
 454 
     | 
    
         
            +
            	cpFloat t = 1.0f;
         
     | 
| 
      
 455 
     | 
    
         
            +
            	 
         
     | 
| 
      
 456 
     | 
    
         
            +
            	restart:
         
     | 
| 
      
 457 
     | 
    
         
            +
            	for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
         
     | 
| 
      
 458 
     | 
    
         
            +
            		cpHandle *hand = bin->handle;
         
     | 
| 
      
 459 
     | 
    
         
            +
            		void *other = hand->obj;
         
     | 
| 
      
 460 
     | 
    
         
            +
            		
         
     | 
| 
      
 461 
     | 
    
         
            +
            		// Skip over certain conditions
         
     | 
| 
      
 462 
     | 
    
         
            +
            		if(hand->stamp == hash->stamp){
         
     | 
| 
      
 463 
     | 
    
         
            +
            			continue;
         
     | 
| 
      
 464 
     | 
    
         
            +
            		} else if(other){
         
     | 
| 
      
 465 
     | 
    
         
            +
            			t = cpfmin(t, func(obj, other, data));
         
     | 
| 
      
 466 
     | 
    
         
            +
            			hand->stamp = hash->stamp;
         
     | 
| 
      
 467 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 468 
     | 
    
         
            +
            			// The object for this handle has been removed
         
     | 
| 
      
 469 
     | 
    
         
            +
            			// cleanup this cell and restart the query
         
     | 
| 
      
 470 
     | 
    
         
            +
            			removeOrphanedHandles(hash, bin_ptr);
         
     | 
| 
      
 471 
     | 
    
         
            +
            			goto restart; // GCC not smart enough/able to tail call an inlined function.
         
     | 
| 
      
 472 
     | 
    
         
            +
            		}
         
     | 
| 
      
 473 
     | 
    
         
            +
            	}
         
     | 
| 
      
 474 
     | 
    
         
            +
            	
         
     | 
| 
      
 475 
     | 
    
         
            +
            	return t;
         
     | 
| 
      
 476 
     | 
    
         
            +
            }
         
     | 
| 
      
 477 
     | 
    
         
            +
             
     | 
| 
      
 478 
     | 
    
         
            +
            // modified from http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
         
     | 
| 
      
 479 
     | 
    
         
            +
            void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpaceHashSegmentQueryFunc func, void *data)
         
     | 
| 
      
 480 
     | 
    
         
            +
            {
         
     | 
| 
      
 481 
     | 
    
         
            +
            	a = cpvmult(a, 1.0f/hash->celldim);
         
     | 
| 
      
 482 
     | 
    
         
            +
            	b = cpvmult(b, 1.0f/hash->celldim);
         
     | 
| 
      
 483 
     | 
    
         
            +
            	
         
     | 
| 
      
 484 
     | 
    
         
            +
            	int cell_x = floor_int(a.x), cell_y = floor_int(a.y);
         
     | 
| 
      
 485 
     | 
    
         
            +
             
     | 
| 
      
 486 
     | 
    
         
            +
            	cpFloat t = 0;
         
     | 
| 
      
 487 
     | 
    
         
            +
             
     | 
| 
      
 488 
     | 
    
         
            +
            	int x_inc, y_inc;
         
     | 
| 
      
 489 
     | 
    
         
            +
            	cpFloat temp_v, temp_h;
         
     | 
| 
      
 490 
     | 
    
         
            +
             
     | 
| 
      
 491 
     | 
    
         
            +
            	if (b.x > a.x){
         
     | 
| 
      
 492 
     | 
    
         
            +
            		x_inc = 1;
         
     | 
| 
      
 493 
     | 
    
         
            +
            		temp_h = (cpffloor(a.x + 1.0f) - a.x);
         
     | 
| 
      
 494 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 495 
     | 
    
         
            +
            		x_inc = -1;
         
     | 
| 
      
 496 
     | 
    
         
            +
            		temp_h = (a.x - cpffloor(a.x));
         
     | 
| 
      
 497 
     | 
    
         
            +
            	}
         
     | 
| 
      
 498 
     | 
    
         
            +
             
     | 
| 
      
 499 
     | 
    
         
            +
            	if (b.y > a.y){
         
     | 
| 
      
 500 
     | 
    
         
            +
            		y_inc = 1;
         
     | 
| 
      
 501 
     | 
    
         
            +
            		temp_v = (cpffloor(a.y + 1.0f) - a.y);
         
     | 
| 
      
 502 
     | 
    
         
            +
            	} else {
         
     | 
| 
      
 503 
     | 
    
         
            +
            		y_inc = -1;
         
     | 
| 
      
 504 
     | 
    
         
            +
            		temp_v = (a.y - cpffloor(a.y));
         
     | 
| 
      
 505 
     | 
    
         
            +
            	}
         
     | 
| 
      
 506 
     | 
    
         
            +
            	
         
     | 
| 
      
 507 
     | 
    
         
            +
            	// Division by zero is *very* slow on ARM
         
     | 
| 
      
 508 
     | 
    
         
            +
            	cpFloat dx = cpfabs(b.x - a.x), dy = cpfabs(b.y - a.y);
         
     | 
| 
      
 509 
     | 
    
         
            +
            	cpFloat dt_dx = (dx ? 1.0f/dx : INFINITY), dt_dy = (dy ? 1.0f/dy : INFINITY);
         
     | 
| 
      
 510 
     | 
    
         
            +
            	
         
     | 
| 
      
 511 
     | 
    
         
            +
            	// fix NANs in horizontal directions
         
     | 
| 
      
 512 
     | 
    
         
            +
            	cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx);
         
     | 
| 
      
 513 
     | 
    
         
            +
            	cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy);
         
     | 
| 
      
 514 
     | 
    
         
            +
            	
         
     | 
| 
      
 515 
     | 
    
         
            +
            	cpSpaceHashBin **table = hash->table;
         
     | 
| 
      
 516 
     | 
    
         
            +
             
     | 
| 
      
 517 
     | 
    
         
            +
            	int n = hash->numcells;
         
     | 
| 
      
 518 
     | 
    
         
            +
            	while(t < t_exit){
         
     | 
| 
      
 519 
     | 
    
         
            +
            		int idx = hash_func(cell_x, cell_y, n);
         
     | 
| 
      
 520 
     | 
    
         
            +
            		t_exit = cpfmin(t_exit, segmentQuery(hash, &table[idx], obj, func, data));
         
     | 
| 
      
 521 
     | 
    
         
            +
             
     | 
| 
      
 522 
     | 
    
         
            +
            		if (next_v < next_h){
         
     | 
| 
      
 523 
     | 
    
         
            +
            			cell_y += y_inc;
         
     | 
| 
      
 524 
     | 
    
         
            +
            			t = next_v;
         
     | 
| 
      
 525 
     | 
    
         
            +
            			next_v += dt_dy;
         
     | 
| 
      
 526 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 527 
     | 
    
         
            +
            			cell_x += x_inc;
         
     | 
| 
      
 528 
     | 
    
         
            +
            			t = next_h;
         
     | 
| 
      
 529 
     | 
    
         
            +
            			next_h += dt_dx;
         
     | 
| 
      
 530 
     | 
    
         
            +
            		}
         
     | 
| 
      
 531 
     | 
    
         
            +
            	}
         
     | 
| 
      
 532 
     | 
    
         
            +
            	
         
     | 
| 
      
 533 
     | 
    
         
            +
            	hash->stamp++;
         
     | 
| 
      
 534 
     | 
    
         
            +
            }
         
     |