/* * Copyright (c) 2008-2009 Bill Whitacre http://rampancy.g0dsoft.com * * 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 "body_manager_array_table.h" #include "world.h" static void add_arbiter(rat_body_manager_array_table *mgr,rat_arbiter *arbiter) { register unsigned int maxarbs=mgr->maxarbs>(mgr->numarbs+1)?mgr->maxarbs:(mgr->numarbs+1); if (mgr->maxarbs==0) { mgr->maxarbs=1; mgr->arbiters=(rat_arbiter **)rat_alloc(sizeof(rat_arbiter *)); } else if (maxarbs>mgr->maxarbs) { mgr->maxarbs=maxarbs; mgr->arbiters=(rat_arbiter **)rat_realloc(mgr->arbiters,sizeof(rat_arbiter *)*mgr->maxarbs); } mgr->arbiters[mgr->numarbs++]=arbiter; } static void remove_arbiter(rat_body_manager_array_table *mgr,unsigned int i) { register unsigned int j; rat_arbiter_destroy(mgr->arbiters[i]); mgr->numarbs--; if (mgr->numarbs>0) { for (j=i+1; jnumarbs+1; j++) mgr->arbiters[j-1]=mgr->arbiters[j]; } } static void remove_arbiter_dat(rat_body_manager_array_table *mgr,rat_arbiter *arb) { register unsigned int i; for (i=0; inumarbs; i++) { if (mgr->arbiters[i]==arb) { remove_arbiter(mgr,i); break; } } } rat_body_manager *rat_body_manager_array_table_create(rat_world *world_ref) { rat_body_manager_array_table *table=(rat_body_manager_array_table *)rat_alloc(sizeof(rat_body_manager_array_table)); table->type=rat_body_manager_type_array_table; table->clas=&rat_array_table_class; table->world_ref=world_ref; table->numbods=table->numbodsrmv= table->numbodsrmvdel= table->numstatic=table->numdynamic= table->numarbs= table->maxarbs=0; table->bodies=NULL; table->static_bodies=NULL; table->dynamic_bodies=NULL; table->arbiters=NULL; return (rat_body_manager *)table; } void rat_body_manager_array_table_destroy(rat_body_manager *table) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; if (mgr->arbiters&&mgr->maxarbs) { register unsigned int i; for (i=0; inumarbs; i++) rat_arbiter_destroy(mgr->arbiters[i]); rat_dealloc((void *)mgr->arbiters); } if (mgr->numbods) rat_dealloc((void *)mgr->bodies); if (mgr->numstatic) rat_dealloc((void *)mgr->static_bodies); if (mgr->numdynamic) rat_dealloc((void *)mgr->dynamic_bodies); if (mgr->numbodsrmv) rat_dealloc((void *)mgr->bodiestoremove); if (mgr->numbodsrmvdel) rat_dealloc((void *)mgr->bodiestodel); rat_dealloc((void *)mgr); } void rat_body_manager_array_table_add_body(rat_body_manager *table,rat_body *body) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; if (mgr->numbods==0) mgr->bodies=(rat_body **)rat_alloc(sizeof(rat_body *)); else mgr->bodies=(rat_body **)rat_realloc(mgr->bodies,sizeof(rat_body *)*(mgr->numbods+1)); mgr->bodies[mgr->numbods]=body; mgr->numbods++; if (body->mass==0.0) { if (mgr->numstatic==0) mgr->static_bodies=(rat_body **)rat_alloc(sizeof(rat_body *)); else mgr->static_bodies=(rat_body **)rat_realloc(mgr->static_bodies,sizeof(rat_body *)*(mgr->numstatic+1)); mgr->static_bodies[mgr->numstatic]=body; mgr->numstatic++; } else { if (mgr->numdynamic==0) mgr->dynamic_bodies=(rat_body **)rat_alloc(sizeof(rat_body *)); else mgr->dynamic_bodies=(rat_body **)rat_realloc(mgr->dynamic_bodies,sizeof(rat_body *)*(mgr->numdynamic+1)); mgr->dynamic_bodies[mgr->numdynamic]=body; mgr->numdynamic++; } } void rat_body_manager_array_table_remove_body(rat_body_manager *table,rat_body *body) { register unsigned int i; rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; for (i=0; inumbodsrmv; i++) { if (mgr->bodiestoremove[i]==body) return; } if (mgr->numbodsrmv==0) mgr->bodiestoremove=(rat_body **)rat_alloc(sizeof(rat_body *)); else mgr->bodiestoremove=(rat_body **)rat_realloc(mgr->bodiestoremove,sizeof(rat_body *)*(mgr->numbodsrmv+1)); mgr->bodiestoremove[mgr->numbodsrmv]=body; mgr->numbodsrmv++; // delete any associated arbiters for (i=0; inumarbs; i++) { if (mgr->arbiters[i]->body_a==body||mgr->arbiters[i]->body_b==body) { remove_arbiter(mgr,i); i--; } } } void rat_body_manager_array_table_remove_and_destroy_body(rat_body_manager *table,rat_body *body) { register unsigned int i; rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; for (i=0; inumbodsrmvdel; i++) { if (mgr->bodiestodel[i]==body) return; } if (mgr->numbodsrmvdel==0) mgr->bodiestodel=(rat_body **)rat_alloc(sizeof(rat_body *)); else mgr->bodiestodel=(rat_body **)rat_realloc(mgr->bodiestodel,sizeof(rat_body *)*(mgr->numbodsrmvdel+1)); mgr->bodiestodel[mgr->numbodsrmvdel]=body; mgr->numbodsrmvdel++; // delete any associated arbiters for (i=0; inumarbs; i++) { if (mgr->arbiters[i]->body_a==body||mgr->arbiters[i]->body_b==body) { remove_arbiter(mgr,i); i--; } } } void really_remove_body(rat_body_manager *table,rat_body *body) { register unsigned int i,j; rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; // dereference from associated springs for (i=0; inumsprings; i++) { if (body->springs[i]->body_a==body) body->springs[i]->body_a=NULL; else body->springs[i]->body_b=NULL; } // dereference from associated constraints for (i=0; inumconsts; i++) { if (body->constraints[i]->body_a==body) body->constraints[i]->body_a=NULL; else body->constraints[i]->body_b=NULL; } // delete the body from it's lists if (body->mass==0.0) { for (i=0; inumstatic; i++) { if (mgr->static_bodies[i]==body) { for (j=i+1; jnumstatic; j++) mgr->static_bodies[j-1]=mgr->static_bodies[j]; mgr->numstatic--; if (mgr->numstatic) mgr->static_bodies=(rat_body **)rat_realloc(mgr->static_bodies,mgr->numstatic*sizeof(rat_body *)); else rat_dealloc((void *)mgr->static_bodies); break; } } } else { for (i=0; inumdynamic; i++) { if (mgr->dynamic_bodies[i]==body) { for (j=i+1; jnumdynamic; j++) mgr->dynamic_bodies[j-1]=mgr->dynamic_bodies[j]; mgr->numdynamic--; if (mgr->numdynamic) mgr->dynamic_bodies=(rat_body **)rat_realloc(mgr->dynamic_bodies,mgr->numdynamic*sizeof(rat_body *)); else rat_dealloc((void *)mgr->dynamic_bodies); break; } } } for (i=0; inumbods; i++) { if (mgr->bodies[i]==body) { for (j=i+1; jnumbods; j++) mgr->bodies[j-1]=mgr->bodies[j]; mgr->numbods--; if (mgr->numbods) mgr->bodies=(rat_body **)rat_realloc(mgr->bodies,mgr->numbods*sizeof(rat_body *)); else rat_dealloc((void *)mgr->bodies); break; } } } void rat_body_manager_array_table_clear_bodies(rat_body_manager *table) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; if (mgr->numbods) { rat_dealloc((void *)mgr->bodies); if (mgr->numstatic) rat_dealloc((void *)mgr->static_bodies); if (mgr->numdynamic) rat_dealloc((void *)mgr->dynamic_bodies); } mgr->numbods=mgr->numstatic=mgr->numdynamic=0; } void rat_body_manager_array_table_free_bodies(rat_body_manager *table) { register unsigned int i; rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; if (mgr->arbiters&&mgr->maxarbs) { register unsigned int i; for (i=0; inumarbs; i++) rat_arbiter_destroy(mgr->arbiters[i]); mgr->numarbs=0; } if (mgr->numstatic) rat_dealloc((void *)mgr->static_bodies); if (mgr->numdynamic) rat_dealloc((void *)mgr->dynamic_bodies); if (mgr->numbodsrmv) rat_dealloc((void *)mgr->bodiestoremove); if (mgr->numbodsrmvdel) rat_dealloc((void *)mgr->bodiestodel); if (mgr->numbods>0) { for (i=0; inumbods; i++) rat_body_destroy(mgr->bodies[i]); rat_dealloc((void *)mgr->bodies); } mgr->numbods=mgr->numstatic=mgr->numdynamic=mgr->numarbs=mgr->numbodsrmv=mgr->numbodsrmvdel=0; } static int is_colliding_helper(rat_world *world,rat_body *a,rat_body *b,rat_contact_array **cons) { register unsigned int i; if (!aabb_is_aabb_overlapping(a->hull->cached_bb,b->hull->cached_bb)) return 0; if (rat_collision_filter_list_hit(world->filters,a->filtertag,b->filtertag)) return 0; if (rat_body_is_adjacency_filter_enabled(a)) { for (i=0; inumconsts; i++) { rat_body *other=a->constraints[i]->body_a==a?a->constraints[i]->body_b:a->constraints[i]->body_a; if (other==b) return 0; } for (i=0; inumsprings; i++) { rat_body *other=a->springs[i]->body_a==a?a->springs[i]->body_b:a->springs[i]->body_a; if (other==b) return 0; } } else if (rat_body_is_adjacency_filter_enabled(b)) { for (i=0; inumconsts; i++) { rat_body *other=b->constraints[i]->body_a==b?b->constraints[i]->body_b:b->constraints[i]->body_a; if (other==a) return 0; } for (i=0; inumsprings; i++) { rat_body *other=b->springs[i]->body_a==b?b->springs[i]->body_b:b->springs[i]->body_a; if (other==a) return 0; } } return rat_query_collision(world->bal,a->hull,b->hull,cons); } void rat_body_manager_array_table_build_spatial_index(rat_body_manager *table) { // nothing to do here because there is no spatial // indexing; this is just the brute force collider } void rat_body_manager_array_table_collide_bodies(rat_body_manager *table) { register unsigned int i,j,k; register int skip; rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; // remove all bodies with requested removal if (mgr->numbodsrmv) { for (i=0; inumbodsrmv; i++) { skip=0; for (j=0; jnumbodsrmvdel; j++) { if (mgr->bodiestodel[j]==mgr->bodiestoremove[i]) { skip=1; break; } } if (!skip) really_remove_body((rat_body_manager *)mgr,mgr->bodiestoremove[i]); } rat_dealloc((void *)mgr->bodiestoremove); mgr->numbodsrmv=0; } // remove and delete all bodies with requested deletion if (mgr->numbodsrmvdel) { for (i=0; inumbodsrmvdel; i++) { rat_body *bodtodel=mgr->bodiestodel[i]; really_remove_body((rat_body_manager *)mgr,bodtodel); rat_body_destroy(bodtodel); } rat_dealloc((void *)mgr->bodiestodel); mgr->numbodsrmvdel=0; } // collide static to dynamic for (i=0; inumstatic; i++) { for (j=0; jnumdynamic; j++) { rat_contact_array *cons=NULL; int collided=is_colliding_helper(mgr->world_ref,mgr->static_bodies[i],mgr->dynamic_bodies[j],&cons); // bingo,this is a collision! if (collided) { // check if this is a persistent collision unsigned int is_persistent=0; for (k=0; knumarbs; k++) { if (mgr->arbiters[k]->body_a==mgr->static_bodies[i]&&mgr->arbiters[k]->body_b==mgr->dynamic_bodies[j]) { // if so, we merge this contact information with the old rat_arbiter_update_contacts(mgr->arbiters[k],cons); mgr->world_ref->callbacks->collision_persists(mgr->world_ref,mgr->arbiters[k],mgr->world_ref->callbacks->collision_persists_userdata); is_persistent=1; break; } else if (mgr->arbiters[k]->body_a==mgr->dynamic_bodies[j]&&mgr->arbiters[k]->body_b==mgr->static_bodies[i]) { // we must reverse the hull order in order to update the contact info right rat_free_contact_array(cons); is_colliding_helper(mgr->world_ref,mgr->dynamic_bodies[j],mgr->dynamic_bodies[i],&cons); rat_arbiter_update_contacts(mgr->arbiters[k],cons); mgr->world_ref->callbacks->collision_persists(mgr->world_ref,mgr->arbiters[k],mgr->world_ref->callbacks->collision_persists_userdata); is_persistent=1; break; } } // if not,we create a new arbiter if (!is_persistent) { rat_arbiter *newarbiter=rat_arbiter_create(mgr->world_ref->bal,mgr->static_bodies[i],mgr->dynamic_bodies[j],cons); add_arbiter(mgr,newarbiter); mgr->world_ref->callbacks->collision_occurs(mgr->world_ref,newarbiter,mgr->world_ref->callbacks->collision_occurs_userdata); } rat_free_contact_array(cons); } else // not colliding. if exists, destroy old arbiter { for (k=0; knumarbs; k++) { if ((mgr->arbiters[k]->body_a==mgr->static_bodies[i]&&mgr->arbiters[k]->body_b==mgr->dynamic_bodies[j]) ||(mgr->arbiters[k]->body_a==mgr->dynamic_bodies[j]&&mgr->arbiters[k]->body_b==mgr->static_bodies[i])) { mgr->world_ref->callbacks->collision_ending(mgr->world_ref,mgr->arbiters[k],mgr->world_ref->callbacks->collision_ending_userdata); remove_arbiter(mgr,k); break; } } } } } // collide dynamic to dynamic for (i=0; inumdynamic; i++) { for (j=i+1; jnumdynamic; j++) { rat_contact_array *cons=NULL; int collided=is_colliding_helper(mgr->world_ref,mgr->dynamic_bodies[i],mgr->dynamic_bodies[j],&cons); // bingo,this is a collision! if (collided) { // check if this is a persistent collision unsigned int is_persistent=0; for (k=0; knumarbs; k++) { if (mgr->arbiters[k]->body_a==mgr->dynamic_bodies[i]&&mgr->arbiters[k]->body_b==mgr->dynamic_bodies[j]) { // if so, we merge this contact information with the old rat_arbiter_update_contacts(mgr->arbiters[k],cons); mgr->world_ref->callbacks->collision_persists(mgr->world_ref,mgr->arbiters[k],mgr->world_ref->callbacks->collision_persists_userdata); is_persistent=1; break; } else if (mgr->arbiters[k]->body_a==mgr->dynamic_bodies[j]&&mgr->arbiters[k]->body_b==mgr->dynamic_bodies[i]) { // we must reverse the hull order in order to update the contact info right rat_free_contact_array(cons); is_colliding_helper(mgr->world_ref,mgr->dynamic_bodies[j],mgr->dynamic_bodies[i],&cons); rat_arbiter_update_contacts(mgr->arbiters[k],cons); mgr->world_ref->callbacks->collision_persists(mgr->world_ref,mgr->arbiters[k],mgr->world_ref->callbacks->collision_persists_userdata); is_persistent=1; break; } } // if not,we create a new arbiter if (!is_persistent) { rat_arbiter *newarbiter=rat_arbiter_create(mgr->world_ref->bal,mgr->dynamic_bodies[i],mgr->dynamic_bodies[j],cons); add_arbiter(mgr,newarbiter); mgr->world_ref->callbacks->collision_occurs(mgr->world_ref,newarbiter,mgr->world_ref->callbacks->collision_occurs_userdata); } rat_free_contact_array(cons); } else // not colliding. if exists, destroy old arbiter { for (k=0; knumarbs; k++) { if ((mgr->arbiters[k]->body_a==mgr->dynamic_bodies[i]&&mgr->arbiters[k]->body_b==mgr->dynamic_bodies[j]) ||(mgr->arbiters[k]->body_a==mgr->dynamic_bodies[j]&&mgr->arbiters[k]->body_b==mgr->dynamic_bodies[i])) { mgr->world_ref->callbacks->collision_ending(mgr->world_ref,mgr->arbiters[k],mgr->world_ref->callbacks->collision_ending_userdata); remove_arbiter(mgr,k); break; } } } } } } unsigned int rat_body_manager_array_table_count_all_bodies(rat_body_manager *table) { return ((rat_body_manager_array_table *)table)->numbods; } unsigned int rat_body_manager_array_table_count_static_bodies(rat_body_manager *table) { return ((rat_body_manager_array_table *)table)->numstatic; } unsigned int rat_body_manager_array_table_count_dynamic_bodies(rat_body_manager *table) { return ((rat_body_manager_array_table *)table)->numdynamic; } unsigned int rat_body_manager_array_table_count_arbiters(rat_body_manager *table) { return ((rat_body_manager_array_table *)table)->numarbs; } rat_iterator *rat_body_manager_array_table_all_bodies_iterator(rat_body_manager *table) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; rat_body_array_iterator *arr=(rat_body_array_iterator *)rat_alloc(sizeof(rat_body_array_iterator)); arr->clas=(rat_iterator_class *)rat_alloc(sizeof(rat_iterator_class)); arr->clas->next=rat_body_array_next; arr->clas->finished=rat_body_array_finished; arr->clas->value=rat_body_array_value; arr->clas->destroy=rat_body_array_destroy; arr->i=0; arr->bodies=mgr->bodies; arr->numbods=mgr->numbods; return (rat_iterator *)arr; } rat_iterator *rat_body_manager_array_table_static_bodies_iterator(rat_body_manager *table) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; rat_body_array_iterator *arr=(rat_body_array_iterator *)rat_alloc(sizeof(rat_body_array_iterator)); arr->clas=(rat_iterator_class *)rat_alloc(sizeof(rat_iterator_class)); arr->clas->next=rat_body_array_next; arr->clas->finished=rat_body_array_finished; arr->clas->value=rat_body_array_value; arr->clas->destroy=rat_body_array_destroy; arr->i=0; arr->bodies=mgr->static_bodies; arr->numbods=mgr->numstatic; return (rat_iterator *)arr; } rat_iterator *rat_body_manager_array_table_dynamic_bodies_iterator(rat_body_manager *table) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; rat_body_array_iterator *arr=(rat_body_array_iterator *)rat_alloc(sizeof(rat_body_array_iterator)); arr->clas=(rat_iterator_class *)rat_alloc(sizeof(rat_iterator_class)); arr->clas->next=rat_body_array_next; arr->clas->finished=rat_body_array_finished; arr->clas->value=rat_body_array_value; arr->clas->destroy=rat_body_array_destroy; arr->i=0; arr->bodies=mgr->dynamic_bodies; arr->numbods=mgr->numdynamic; return (rat_iterator *)arr; } rat_iterator *rat_body_manager_array_table_arbiters_iterator(rat_body_manager *table) { rat_body_manager_array_table *mgr=(rat_body_manager_array_table *)table; rat_arbiter_array_iterator *arr=(rat_arbiter_array_iterator *)rat_alloc(sizeof(rat_arbiter_array_iterator)); arr->clas=(rat_iterator_class *)rat_alloc(sizeof(rat_iterator_class)); arr->clas->next=rat_arbiter_array_next; arr->clas->finished=rat_arbiter_array_finished; arr->clas->value=rat_arbiter_array_value; arr->clas->destroy=rat_arbiter_array_destroy; arr->i=0; arr->arbiters=mgr->arbiters; arr->numarbs=mgr->numarbs; return (rat_iterator *)arr; }