/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "chipmunk.h"
int cp_contact_persistence = 1;
#pragma mark Contact Set Helpers
// Equal function for contactSet.
static int
contactSetEql(cpShape **shapes, cpArbiter *arb)
{
cpShape *a = shapes[0];
cpShape *b = shapes[1];
return ((a == arb->private_a && b == arb->private_b) || (b == arb->private_a && a == arb->private_b));
}
// Transformation function for contactSet.
static void *
contactSetTrans(cpShape **shapes, cpSpace *space)
{
if(space->pooledArbiters->num == 0){
// arbiter pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(cpArbiter);
cpAssert(count, "Buffer size too small.");
cpArbiter *buffer = (cpArbiter *)cpmalloc(CP_BUFFER_BYTES);
cpArrayPush(space->allocatedBuffers, buffer);
for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);
}
return cpArbiterInit( (cpArbiter *)cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);
}
#pragma mark Collision Pair Function Helpers
// Equals function for collFuncSet.
static int
collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
{
return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b));
}
// Transformation function for collFuncSet.
static void *
collFuncSetTrans(cpCollisionHandler *handler, void *unused)
{
cpCollisionHandler *copy = (cpCollisionHandler *)cpmalloc(sizeof(cpCollisionHandler));
(*copy) = (*handler);
return copy;
}
#pragma mark Post Step Function Helpers
typedef struct postStepCallback {
cpPostStepFunc func;
void *obj;
void *data;
} postStepCallback;
static int
postStepFuncSetEql(postStepCallback *a, postStepCallback *b){
return a->obj == b->obj;
}
static void *
postStepFuncSetTrans(postStepCallback *callback, void *ignored)
{
postStepCallback *value = (postStepCallback *)cpmalloc(sizeof(postStepCallback));
(*value) = (*callback);
return value;
}
#pragma mark Misc Helper Funcs
// Default collision functions.
static int alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
static void nothing(cpArbiter *arb, cpSpace *space, void *data){}
// BBfunc callback for the spatial hash.
static cpBB shapeBBFunc(cpShape *shape){return shape->bb;}
// Iterator functions for destructors.
static void freeWrap(void *ptr, void *unused){ cpfree(ptr);}
static void shapeFreeWrap(cpShape *ptr, void *unused){ cpShapeFree(ptr);}
static void bodyFreeWrap(cpBody *ptr, void *unused){ cpBodyFree(ptr);}
static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFree(ptr);}
#pragma mark Memory Management Functions
#define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(cpContact))
typedef struct cpContactBuffer {
cpContactBufferHeader header;
cpContact contacts[CP_CONTACTS_BUFFER_SIZE];
} cpContactBuffer;
static cpContactBufferHeader *
cpSpaceAllocContactBuffer(cpSpace *space)
{
cpContactBuffer *buffer = (cpContactBuffer *)malloc(sizeof(cpContactBuffer));
cpArrayPush(space->allocatedBuffers, buffer);
return (cpContactBufferHeader *)buffer;
}
static cpContactBufferHeader *
cpContactBufferHeaderInit(cpContactBufferHeader *header, cpSpace *space)
{
header->stamp = space->stamp;
header->next = space->contactBuffersTail;
header->numContacts = 0;
return header;
}
cpSpace *
cpSpaceAlloc(void)
{
return (cpSpace *)cpcalloc(1, sizeof(cpSpace));
}
#define DEFAULT_DIM_SIZE 100.0f
#define DEFAULT_COUNT 1000
#define DEFAULT_ITERATIONS 10
#define DEFAULT_ELASTIC_ITERATIONS 0
#define MAX_CONTACTS 10000
cpCollisionHandler defaultHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL};
cpSpace*
cpSpaceInit(cpSpace *space)
{
space->iterations = DEFAULT_ITERATIONS;
space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;
// space->sleepTicks = 300;
space->gravity = cpvzero;
space->damping = 1.0f;
space->locked = 0;
space->stamp = 0;
space->staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
space->allocatedBuffers = cpArrayNew(0);
space->bodies = cpArrayNew(0);
space->arbiters = cpArrayNew(0);
space->pooledArbiters = cpArrayNew(0);
cpContactBufferHeader *header = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), space);
space->contactBuffersHead = header;
space->contactBuffersTail = header;
header->next = header; // Buffers will form a ring, start the ring explicitly
space->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);
space->constraints = cpArrayNew(0);
space->defaultHandler = defaultHandler;
space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);
space->collFuncSet->default_value = &space->defaultHandler;
space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql, (cpHashSetTransFunc)postStepFuncSetTrans);
return space;
}
cpSpace*
cpSpaceNew(void)
{
return cpSpaceInit(cpSpaceAlloc());
}
void
cpSpaceDestroy(cpSpace *space)
{
cpSpaceHashFree(space->staticShapes);
cpSpaceHashFree(space->activeShapes);
cpArrayFree(space->bodies);
cpArrayFree(space->constraints);
cpHashSetFree(space->contactSet);
cpArrayFree(space->arbiters);
cpArrayFree(space->pooledArbiters);
if(space->allocatedBuffers){
cpArrayEach(space->allocatedBuffers, freeWrap, NULL);
cpArrayFree(space->allocatedBuffers);
}
if(space->postStepCallbacks){
cpHashSetEach(space->postStepCallbacks, freeWrap, NULL);
cpHashSetFree(space->postStepCallbacks);
}
if(space->collFuncSet){
cpHashSetEach(space->collFuncSet, freeWrap, NULL);
cpHashSetFree(space->collFuncSet);
}
}
void
cpSpaceFree(cpSpace *space)
{
if(space){
cpSpaceDestroy(space);
cpfree(space);
}
}
void
cpSpaceFreeChildren(cpSpace *space)
{
cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL);
cpArrayEach(space->constraints, (cpArrayIter)&constraintFreeWrap, NULL);
}
#pragma mark Collision Handler Function Management
void
cpSpaceAddCollisionHandler(
cpSpace *space,
cpCollisionType a, cpCollisionType b,
cpCollisionBeginFunc begin,
cpCollisionPreSolveFunc preSolve,
cpCollisionPostSolveFunc postSolve,
cpCollisionSeparateFunc separate,
void *data
){
// Remove any old function so the new one will get added.
cpSpaceRemoveCollisionHandler(space, a, b);
cpCollisionHandler handler = {
a, b,
begin ? begin : alwaysCollide,
preSolve ? preSolve : alwaysColli
- 1
- 2
前往页