2025-01-26 18:33:45 +01:00

4103 lines
113 KiB
C

/*
Raydium - CQFD Corp.
http://raydium.org/
License: GPL - GNU General Public License, see "gpl.txt" file.
*/
#ifndef DONT_INCLUDE_HEADERS
#include "index.h"
#else
#include "headers/ode.h"
#endif
// TODO:
// load object from file
// delete callbaks (objects, motors, ... ?) (done for joints, elements)
// parametric frictions
// other joints
// allow full RayODE reset (almost done now)
// multiple grounds
// bugfix for rotation friction
#include "ode.h"
void raydium_ode_name_auto(char *prefix, char *dest)
{
static int counter;
sprintf(dest,"%s_ode_%i",prefix,counter);
counter++;
}
void raydium_ode_init_object(int i)
{
raydium_ode_object[i].id=i;
raydium_ode_object[i].name[0]=0;
raydium_ode_object[i].state=0;
raydium_ode_object[i].colliding=0;
raydium_ode_object[i].group=NULL;
}
void raydium_ode_init_element(int i)
{
int j;
raydium_ode_element[i].id=i;
raydium_ode_element[i].name[0]=0;
raydium_ode_element[i].state=0;
raydium_ode_element[i].object=-1;
raydium_ode_element[i].mesh=-1;
raydium_ode_element[i]._touched=0;
raydium_ode_element[i]._movesfrom=-1;
raydium_ode_element[i].isplayer=0;
raydium_ode_element[i].playerangle=0;
raydium_ode_element[i].slip=0;
raydium_ode_element[i].rotfriction=0;
raydium_ode_element[i].geom=NULL;
raydium_ode_element[i].body=NULL;
raydium_ode_element[i].erp=0;
raydium_ode_element[i].cfm=0;
raydium_ode_element[i].user_data=NULL;
raydium_ode_element[i].user_tag=0;
// I consider every fixed element is already free()
for(j=0;j<RAYDIUM_ODE_ELEMENT_MAX_FIXING;j++)
raydium_ode_element[i].fixed_elements[j]=NULL;
raydium_ode_element[i].nid=-1;
raydium_ode_element[i].distant=0;
raydium_ode_element[i].distant_owner=-1;
raydium_ode_element[i].OnBlow=NULL;
raydium_ode_element[i].OnDelete=NULL;
raydium_ode_element[i].ttl=-1; // infinite
raydium_ode_element[i].particle=-1;
memset(raydium_ode_element[i].particle_offset,0,sizeof(dReal)*3);
raydium_ode_element[i].ground_texture=0;
memset(raydium_ode_element[i].net_last_pos1,0,sizeof(dReal)*3);
memset(raydium_ode_element[i].net_last_pos2,0,sizeof(dReal)*3);
//raydium_ode_element[i].net_last_time=raydium_timecall_clock();
raydium_ode_element[i].net_last_time=0; // no previous update
raydium_ode_element[i].net_last_interval=0;
memset(raydium_ode_element[i].netvel,0,sizeof(dReal)*3);
raydium_ode_element[i].marked_as_deleted=0;
raydium_ode_element[i].ray.state=0;
}
void raydium_ode_init_joint(int i)
{
raydium_ode_joint[i].id=i;
raydium_ode_joint[i].name[0]=0;
raydium_ode_joint[i].state=0;
raydium_ode_joint[i].mesh=-1;
raydium_ode_joint[i].joint=NULL;
//raydium_ode_joint[i].hinge2correct=0;
raydium_ode_joint[i].breakableforce=0;
raydium_ode_joint[i].breaking=0;
raydium_ode_joint[i].OnDelete=NULL;
}
void raydium_ode_init_motor(int i)
{
int j;
raydium_ode_motor[i].id=i;
raydium_ode_motor[i].name[0]=0;
raydium_ode_motor[i].state=0;
raydium_ode_motor[i].object=-1;
raydium_ode_motor[i].speed=0;
raydium_ode_motor[i].force=0;
raydium_ode_motor[i].angle=0;
raydium_ode_motor[i].rocket_element=-1;
raydium_ode_motor[i].rocket_playermovement=0;
for(j=0;j<3;j++)
{
raydium_ode_motor[i].rocket_direction[j]=0;
raydium_ode_motor[i].rocket_position[j]=0;
raydium_ode_motor[i].rocket_orientation[j]=0;
}
for(j=0;j<RAYDIUM_ODE_MOTOR_MAX_JOINTS;j++)
{
raydium_ode_motor[i].joints[j]=-1;
raydium_ode_motor[i].joints_axe[j]=0;
}
raydium_ode_motor[i].gears[0]=1.f;
raydium_ode_motor[i].gear=0;
raydium_ode_motor[i].gear_max=0;
}
void raydium_ode_init_explosion(int e)
{
int j;
raydium_ode_explosion[e].id=e;
raydium_ode_explosion[e].name[0]=0;
raydium_ode_explosion[e].state=0;
raydium_ode_explosion[e].config_radius=0;
raydium_ode_explosion[e].config_propag=0;
raydium_ode_explosion[e].radius=0;
raydium_ode_explosion[e].element=-1;
for(j=0;j<3;j++)
raydium_ode_explosion[e].position[j]=0;
}
void raydium_ode_init(void)
{
int i;
if(sizeof(dReal) != sizeof(float))
{
raydium_log("physics: FAILED");
raydium_log("physics: You need SINGLE precision for ODE");
exit(34);
}
raydium_ode_ExplosionCallback=NULL;
raydium_ode_CollideCallback=NULL;
raydium_ode_RayCallback=NULL;
raydium_ode_StepCallback=NULL;
raydium_ode_BeforeElementDrawCallback=NULL;
raydium_ode_AfterElementDrawCallback=NULL;
raydium_ode_ObjectNearCollide=NULL;
raydium_ode_world=dWorldCreate();
raydium_ode_space=dHashSpaceCreate(0);
raydium_ode_contactgroup=dJointGroupCreate(0);
dWorldSetGravity(raydium_ode_world,0,0,-1.0);
raydium_ode_ground_mesh=-1;
raydium_ode_network_distant_create=0;
raydium_ode_network_next_local_only=0;
raydium_ode_network_explosion_create=0;
raydium_ode_element_delete_LOCK=0;
for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
raydium_ode_init_object(i);
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
raydium_ode_init_element(i);
raydium_ode_init_element(RAYDIUM_ODE_MAX_ELEMENTS);
raydium_ode_element[RAYDIUM_ODE_MAX_ELEMENTS].state=1;
strcpy(raydium_ode_element[RAYDIUM_ODE_MAX_ELEMENTS].name,"! dummy !");
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
raydium_ode_init_joint(i);
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
raydium_ode_init_motor(i);
for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
raydium_ode_init_explosion(i);
#ifndef ODE_MANUAL_CALLBACK
raydium_ode_timecall=raydium_timecall_add(&raydium_ode_callback,RAYDIUM_ODE_PHYSICS_FREQ);
#endif
#ifdef ODE_QUICKSTEP
dWorldSetQuickStepNumIterations (raydium_ode_world,10);
//dWorldSetAutoDisableFlag (raydium_ode_world,1);
//dWorldSetContactMaxCorrectingVel (raydium_ode_world,0.1);
//dWorldSetContactSurfaceLayer (raydium_ode_world,0.001);
#endif
// must adjust this value /!!!/
dWorldSetContactMaxCorrectingVel(raydium_ode_world,10);
// wow ! This is my first init dependance ;)
raydium_ode_object_create("GLOBAL");
raydium_ode_network_init();
raydium_log("physics: ODE Net: %i element(s)/packet",raydium_ode_network_MaxElementsPerPacket());
raydium_log("physics: OK");
}
signed char raydium_ode_object_isvalid(int i)
{
if(i>=0 && i<RAYDIUM_ODE_MAX_OBJECTS &&
raydium_ode_object[i].state)
return 1;
return 0;
}
signed char raydium_ode_element_isvalid(int i)
{
if(i>=0 && i<=RAYDIUM_ODE_MAX_ELEMENTS && /* "<=" is important, see ode.h ! */
raydium_ode_element[i].state)
return 1;
return 0;
}
signed char raydium_ode_joint_isvalid(int i)
{
if(i>=0 && i<RAYDIUM_ODE_MAX_JOINTS &&
raydium_ode_joint[i].state)
return 1;
return 0;
}
signed char raydium_ode_motor_isvalid(int i)
{
if(i>=0 && i<RAYDIUM_ODE_MAX_MOTORS &&
raydium_ode_motor[i].state)
return 1;
return 0;
}
signed char raydium_ode_explosion_isvalid(int i)
{
if(i>=0 && i<RAYDIUM_ODE_MAX_EXPLOSIONS &&
raydium_ode_explosion[i].state)
return 1;
return 0;
}
void raydium_ode_ground_dTriArrayCallback (
dGeomID TriMesh, dGeomID RefObject,
const int* TriIndices, int TriCount)
{
int offset;
int max_index;
GLfloat max_val,tmp;
dReal *pos;
int i;
raydium_ode_Element *e;
e=dGeomGetData(RefObject);
pos=(dReal *)dGeomGetPosition(RefObject);
if(!e) return;
// add ground object offset:
offset=raydium_object_start[raydium_ode_ground_mesh];
//one=0;
//one+=(TriIndices[0]*3);
//printf("%i %s\n",TriCount,e->name);
//printf("%i\n",one);
//e->ground_texture=raydium_vertex_texture[one];
max_val=
((pos[0]-raydium_vertex_x[TriIndices[0]*3+offset]) +
(pos[1]-raydium_vertex_y[TriIndices[0]*3+offset]) +
(pos[2]-raydium_vertex_z[TriIndices[0]*3+offset]) );
max_index=0;
for(i=1;i<TriCount;i++)
{
tmp=
((pos[0]-raydium_vertex_x[TriIndices[i]*3+offset]) +
(pos[1]-raydium_vertex_y[TriIndices[i]*3+offset]) +
(pos[2]-raydium_vertex_z[TriIndices[i]*3+offset]) );
if(tmp<=max_val)
{
max_index=i;
max_val=tmp;
}
}
//printf("%i %s %i %i\n",TriCount,e->name,TriIndices[0],TriIndices[1]);
e->ground_texture=raydium_vertex_texture[TriIndices[max_index]*3+offset];
raydium_vertex_tag[TriIndices[max_index]*3+offset]=1;
}
int raydium_ode_ground_dTriCallback(
dGeomID TriMesh,
dGeomID RefObject,
int TriangleIndex)
{
//printf("%i\n",TriangleIndex);
raydium_vertex_tag[TriangleIndex*3]=1;
return 1;
}
void raydium_ode_ground_set_name(char *name)
{
int i,j,k;
int obj,size;
static dTriMeshDataID Data;
static int *Indices;
static dReal *Vertices;
static dGeomID geom;
int global;
char replace=0;
if(raydium_ode_ground_mesh>=0)
{
//raydium_log("ODE: Error: Cannot change ground at runtime");
//return;
// OR
replace=1;
dGeomDestroy(geom);
dGeomTriMeshDataDestroy(Data);
/*
Data=dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle(Data,&Vertices[0],sizeof(dReal)*3,size,&Indices[0],size,3*sizeof(int));
geom=dCreateTriMesh(raydium_ode_space, Data, 0, 0, 0);
*/
free(Indices);
free(Vertices);
}
obj=raydium_object_find_load(name);
if(obj<0)
{
raydium_log("ODE: Error: cannot load ground (%s)",name);
return;
}
// let's transform tri file format to ODE format ...
size=raydium_object_end[obj]-raydium_object_start[obj];
Indices=malloc(size*sizeof(int));
Vertices=malloc(size*sizeof(dReal)*3);
raydium_ode_ground_mesh=obj;
for(i=raydium_object_start[obj],j=k=0;i<raydium_object_end[obj];i+=3,j+=3)
{
Indices[j]=j;
Vertices[k++]=raydium_vertex_x[i];
Vertices[k++]=raydium_vertex_y[i];
Vertices[k++]=raydium_vertex_z[i];
Indices[j+1]=j+1;
Vertices[k++]=raydium_vertex_x[i+1];
Vertices[k++]=raydium_vertex_y[i+1];
Vertices[k++]=raydium_vertex_z[i+1];
Indices[j+2]=j+2;
Vertices[k++]=raydium_vertex_x[i+2];
Vertices[k++]=raydium_vertex_y[i+2];
Vertices[k++]=raydium_vertex_z[i+2];
}
// There is NO way to delete the ground, yet ...
Data=dGeomTriMeshDataCreate();
// with newer ODE versions, use the following:
dGeomTriMeshDataBuildSingle(Data,&Vertices[0],sizeof(dReal)*3,size,&Indices[0],size,3*sizeof(int));
// and the following with ODE .039:
//dGeomTriMeshDataBuild(Data,&Vertices[0],sizeof(dReal)*3,size,&Indices[0], size, 3*sizeof(int));
geom=dCreateTriMesh(raydium_ode_space, Data, 0, 0, 0);
//if(!replace)
// global=raydium_ode_object_create("GLOBAL");
//else
global=raydium_ode_object_find("GLOBAL");
raydium_ode_object_colliding(global,1);
raydium_ode_init_element(0);
raydium_ode_element[0].object=global;
strcpy(raydium_ode_element[0].name,"ground");
raydium_ode_element[0].state=RAYDIUM_ODE_STATIC;
raydium_ode_element[0].mesh=obj;
raydium_ode_element[0].geom=geom;
raydium_ode_element[0].user_tag=RAYDIUM_ODE_TAG_GROUND;
raydium_ode_element_material(0,RAYDIUM_ODE_MATERIAL_DEFAULT);
raydium_ode_element_slip(0,RAYDIUM_ODE_SLIP_DEFAULT);
dGeomSetData(geom,&raydium_ode_element[0]);
// sets Tri[Array]Callback: (no usable yet !)
//dGeomTriMeshSetArrayCallback(geom,raydium_ode_ground_dTriArrayCallback);
//dGeomTriMeshSetCallback(geom,raydium_ode_ground_dTriCallback);
raydium_shadow_ground_change(obj); // send new ground to shadow system
}
int raydium_ode_object_find(char *name)
{
int i;
for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
if(!strcmp(name,raydium_ode_object[i].name) && raydium_ode_object_isvalid(i))
return i;
return -1;
}
int raydium_ode_element_find(char *name)
{
int i;
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(!strcmp(name,raydium_ode_element[i].name) && raydium_ode_element_isvalid(i))
return i;
return -1;
}
int raydium_ode_joint_find(char *name)
{
int i;
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(!strcmp(name,raydium_ode_joint[i].name) && raydium_ode_joint_isvalid(i))
return i;
return -1;
}
int raydium_ode_motor_find(char *name)
{
int i;
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
if(!strcmp(name,raydium_ode_motor[i].name) && raydium_ode_motor_isvalid(i))
return i;
return -1;
}
int raydium_ode_explosion_find(char *name)
{
int i;
for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
if(!strcmp(name,raydium_ode_explosion[i].name))
return i;
return -1;
}
int raydium_ode_object_create(char *name)
{
int i;
if(raydium_ode_object_find(name)>=0)
{
raydium_log("ODE: Error: Cannot add object \"%s\": name already exists",name);
return -1;
}
for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
if(!raydium_ode_object[i].state)
{
strcpy(raydium_ode_object[i].name,name);
raydium_ode_object[i].state=1;
// raydium_ode_object[i].group=dCreateGeomGroup(raydium_ode_space);
raydium_ode_object[i].group=dSimpleSpaceCreate(raydium_ode_space);
dSpaceSetCleanup(raydium_ode_object[i].group,0);
dGeomSetData((dGeomID)raydium_ode_object[i].group,&raydium_ode_object[i]);
return i;
}
raydium_log("ODE: Error: No more object slots ! aborting \"%s\" creation",name);
return -1;
}
signed char raydium_ode_object_rename(int o, char *newname)
{
int elem;
if(!raydium_ode_object_isvalid(o))
{
raydium_log("ODE: Error: cannot rename object: invalid name or index");
return 0;
}
elem=raydium_ode_object_find(newname);
if(elem>=0)
{
raydium_log("ODE: Error: cannot rename '%s' to '%s': name already exists");
return 0;
}
strcpy(raydium_ode_object[o].name,newname);
return 1;
}
signed char raydium_ode_object_rename_name(char *o, char *newname)
{
return raydium_ode_object_rename(raydium_ode_object_find(o),newname);
}
signed char raydium_ode_object_colliding(int o, signed char colliding)
{
if(!raydium_ode_object_isvalid(o))
{
raydium_log("ODE: Error: cannot set object internal colliding flag: invalid name or index");
return 0;
}
raydium_ode_object[o].colliding=colliding;
return 1;
}
signed char raydium_ode_object_colliding_name(char *o, signed char colliding)
{
return raydium_ode_object_colliding(raydium_ode_object_find(o),colliding);
}
void raydium_ode_object_linearvelocity_set(int o, dReal *vect)
{
int i;
if(!raydium_ode_object_isvalid(o))
{
raydium_log("ODE: Error: cannot set object linear velocity: invalid name or index");
return;
}
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if( (raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD ||
raydium_ode_element[i].state==RAYDIUM_ODE_STATIC) &&
raydium_ode_element[i].object==o)
dBodySetLinearVel(raydium_ode_element[i].body,vect[0],vect[1],vect[2]);
}
void raydium_ode_object_linearvelocity_set_name(char *o, dReal *vect)
{
raydium_ode_object_linearvelocity_set(raydium_ode_object_find(o),vect);
}
void raydium_ode_object_linearvelocity_set_name_3f(char *o, dReal vx, dReal vy, dReal vz)
{
dReal vect[3];
vect[0]=vx;
vect[1]=vy;
vect[2]=vz;
raydium_ode_object_linearvelocity_set_name(o,vect);
}
void raydium_ode_object_addforce(int o, dReal *vect)
{
int i;
if(!raydium_ode_object_isvalid(o))
{
raydium_log("ODE: Error: cannot add force to object: invalid name or index");
return;
}
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if( raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD &&
raydium_ode_element[i].object==o)
dBodyAddForce(raydium_ode_element[i].body,vect[0],vect[1],vect[2]);
}
void raydium_ode_object_addforce_name(char *o, dReal *vect)
{
raydium_ode_object_addforce(raydium_ode_object_find(o),vect);
}
void raydium_ode_object_addforce_name_3f(char *o, dReal vx, dReal vy, dReal vz)
{
dReal vect[3];
vect[0]=vx;
vect[1]=vy;
vect[2]=vz;
raydium_ode_object_addforce_name(o,vect);
}
void raydium_ode_element_addforce(int e, dReal *vect)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot add force to element: invalid name or index");
return;
}
if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: cannot add force to a static element");
return;
}
dBodyAddForce(raydium_ode_element[e].body,vect[0],vect[1],vect[2]);
}
void raydium_ode_element_addforce_name(char *e, dReal *vect)
{
raydium_ode_element_addforce(raydium_ode_element_find(e),vect);
}
void raydium_ode_element_addforce_name_3f(char *e, dReal vx, dReal vy, dReal vz)
{
dReal vect[3];
vect[0]=vx;
vect[1]=vy;
vect[2]=vz;
raydium_ode_element_addforce_name(e,vect);
}
void raydium_ode_element_addtorque(int e, dReal *vect)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot add torque to element: invalid name or index");
return;
}
if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: cannot add torque to a static element");
return;
}
dBodyAddTorque(raydium_ode_element[e].body,vect[0],vect[1],vect[2]);
}
void raydium_ode_element_addtorque_name(char *e, dReal *vect)
{
raydium_ode_element_addtorque(raydium_ode_element_find(e),vect);
}
void raydium_ode_element_addtorque_name_3f(char *e, dReal vx, dReal vy, dReal vz)
{
dReal vect[3];
vect[0]=vx;
vect[1]=vy;
vect[2]=vz;
raydium_ode_element_addtorque_name(e,vect);
}
signed char raydium_ode_element_material(int e, dReal erp, dReal cfm)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set element material: invalid name or index");
return 0;
}
raydium_ode_element[e].erp=erp;
raydium_ode_element[e].cfm=cfm;
return 1;
}
signed char raydium_ode_element_material_name(char *name, dReal erp, dReal cfm)
{
return raydium_ode_element_material(raydium_ode_element_find(name),erp,cfm);
}
signed char raydium_ode_element_slip(int e, dReal slip)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set element slip coef: invalid name or index");
return 0;
}
raydium_ode_element[e].slip=slip;
return 1;
}
signed char raydium_ode_element_slip_name(char *e, dReal slip)
{
return raydium_ode_element_slip(raydium_ode_element_find(e),slip);
}
signed char raydium_ode_element_rotfriction(int e, dReal rotfriction)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set element rotation friction: invalid name or index");
return 0;
}
raydium_ode_element[e].rotfriction=rotfriction;
return 1;
}
signed char raydium_ode_element_rotfriction_name(char *e, dReal rotfriction)
{
return raydium_ode_element_rotfriction(raydium_ode_element_find(e),rotfriction);
}
dReal *raydium_ode_element_linearvelocity_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot get element linear velocity: invalid name or index");
return NULL;
}
if(raydium_ode_element[e].state!=RAYDIUM_ODE_STANDARD)
{
raydium_log("ODE: Error: cannot get element linear velocity: not a standard object");
return NULL;
}
return (dReal *)dBodyGetLinearVel(raydium_ode_element[e].body);
}
dReal *raydium_ode_element_linearvelocity_get_name(char *e)
{
return raydium_ode_element_linearvelocity_get(raydium_ode_element_find(e));
}
void raydium_ode_element_OnBlow(int e, void *OnBlow)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set OnBlow callback: invalid name or index");
return;
}
raydium_ode_element[e].OnBlow=OnBlow;
}
void raydium_ode_element_OnBlow_name(char *e, void *OnBlow)
{
raydium_ode_element_OnBlow(raydium_ode_element_find(e),OnBlow);
}
void raydium_ode_element_OnDelete(int e, void *OnDelete)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set OnDelete callback: invalid name or index");
return;
}
raydium_ode_element[e].OnDelete=OnDelete;
}
void raydium_ode_element_OnDelete_name(char *e, void *OnDelete)
{
raydium_ode_element_OnDelete(raydium_ode_element_find(e),OnDelete);
}
void raydium_ode_element_gravity(int e, signed char enable)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set gravity mode: invalid name or index");
return;
}
if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: cannot set gravity mode on a static element");
return;
}
dBodySetGravityMode(raydium_ode_element[e].body,enable);
}
void raydium_ode_element_gravity_name(char *e, signed char enable)
{
raydium_ode_element_gravity(raydium_ode_element_find(e),enable);
}
void raydium_ode_element_ttl_set(int e, int ttl)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set ttl: invalid name or index");
return;
}
raydium_ode_element[e].ttl=ttl;
}
void raydium_ode_element_ttl_set_name(char *e, int ttl)
{
raydium_ode_element_ttl_set(raydium_ode_element_find(e),ttl);
}
// aabb is dReal[6]
signed char raydium_ode_element_aabb_get(int element, dReal *aabb)
{
if(!raydium_ode_element_isvalid(element))
{
raydium_log("ODE: Error: cannot get AABB: invalid name or index");
return 0;
}
dGeomGetAABB(raydium_ode_element[element].geom,aabb);
return 1;
}
signed char raydium_ode_element_aabb_get_name(char *element, dReal *aabb)
{
return raydium_ode_element_aabb_get(raydium_ode_element_find(element),aabb);
}
int raydium_ode_element_touched_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot get 'touched' flag: invalid name or index");
return 0;
}
return raydium_ode_element[e]._touched;
}
int raydium_ode_element_touched_get_name(char *e)
{
return raydium_ode_element_touched_get(raydium_ode_element_find(e));
}
signed char raydium_ode_element_player_set(int e, signed char isplayer)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set player flag: invalid name or index");
return 0;
}
raydium_ode_element[e].isplayer=isplayer;
if(isplayer)
raydium_ode_element_slip(e,RAYDIUM_ODE_SLIP_PLAYER);
else
raydium_ode_element_slip(e,RAYDIUM_ODE_SLIP_DEFAULT);
return 1;
}
signed char raydium_ode_element_player_set_name(char *name, signed char isplayer)
{
return raydium_ode_element_player_set(raydium_ode_element_find(name),isplayer);
}
signed char raydium_ode_element_player_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot get player flag: invalid name or index");
return 0;
}
return raydium_ode_element[e].isplayer;
}
signed char raydium_ode_element_player_get_name(char *name)
{
return raydium_ode_element_player_get(raydium_ode_element_find(name));
}
signed char raydium_ode_element_player_angle(int e, dReal angle)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set player angle: invalid name or index");
return 0;
}
raydium_ode_element[e].playerangle=angle;
return 1;
}
signed char raydium_ode_element_player_angle_name(char *e, dReal angle)
{
return raydium_ode_element_player_angle(raydium_ode_element_find(e),angle);
}
int raydium_ode_element_ground_texture_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot get ground texture: invalid name or index");
return 0;
}
return raydium_ode_element[e].ground_texture;
}
int raydium_ode_element_ground_texture_get_name(char *e)
{
return raydium_ode_element_ground_texture_get(raydium_ode_element_find(e));
}
int raydium_ode_element_object_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot get element's owner: invalid name or index");
return 0;
}
return raydium_ode_element[e].object;
}
int raydium_ode_element_object_get_name(char *e)
{
return raydium_ode_element_object_get(raydium_ode_element_find(e));
}
int raydium_ode_object_sphere_add(char *name, int group, dReal mass, dReal radius, signed char type, int tag, char *mesh)
{
int i;
dMass m;
if(raydium_ode_element_find(name)>=0)
{
raydium_log("ODE: Error: Cannot add element \"%s\": name already exists",name);
return -1;
}
if(!raydium_ode_object_isvalid(group))
{
raydium_log("ODE: Error: object not found while adding \"%s\"",name);
return -1;
}
if(tag<0)
{
raydium_log("ODE: Error: Element creation failed: negative tags are forbidden");
return -1;
}
// First element is reserved
for(i=1;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(!raydium_ode_element[i].state)
{
strcpy(raydium_ode_element[i].name,name);
raydium_ode_element[i].object=group;
raydium_ode_element[i].user_tag=tag;
if(strlen(mesh))
{
raydium_ode_element[i].mesh=raydium_object_find_load(mesh);
if(radius<0) // AUTODETECT
radius=raydium_object_find_dist_max(raydium_ode_element[i].mesh)*-radius;
}
if(type==RAYDIUM_ODE_STANDARD)
{
raydium_ode_element[i].body=dBodyCreate(raydium_ode_world);
dMassSetSphere(&m,1,radius);
dMassAdjust(&m,mass);
dBodySetMass(raydium_ode_element[i].body,&m);
dBodySetData(raydium_ode_element[i].body,&raydium_ode_element[i]);
// dBodySetAutoDisableSF1(raydium_ode_element[i].body,1);
}
else raydium_ode_element[i].body=0;
raydium_ode_element[i].geom=dCreateSphere(0,radius);
raydium_ode_element[i].state=type;
dGeomSetBody(raydium_ode_element[i].geom,raydium_ode_element[i].body);
dGeomSetData(raydium_ode_element[i].geom,&raydium_ode_element[i]);
dSpaceAdd(raydium_ode_object[group].group,raydium_ode_element[i].geom);
raydium_ode_element_material(i,RAYDIUM_ODE_MATERIAL_DEFAULT);
raydium_ode_element_slip(i,RAYDIUM_ODE_SLIP_DEFAULT);
raydium_ode_element[i].distant=raydium_ode_network_distant_create;
raydium_ode_network_distant_create=0;
if(!raydium_ode_network_next_local_only)
raydium_ode_network_element_new(i);
raydium_ode_network_next_local_only=0;
return i;
}
raydium_log("ODE: No more element slots ! aborting \"%s\" creation",name);
return -1;
}
int raydium_ode_object_box_add(char *name, int group, dReal mass, dReal tx, dReal ty, dReal tz, signed char type, int tag, char *mesh)
{
int i;
dMass m;
if(raydium_ode_element_find(name)>=0)
{
raydium_log("ODE: Cannot add element \"%s\": name already exists",name);
return -1;
}
if(!raydium_ode_object_isvalid(group))
{
raydium_log("ODE: Error: object not found while adding \"%s\"",name);
return -1;
}
if(tag<0)
{
raydium_log("ODE: Error: Element creation failed: negative tags are forbidden");
return -1;
}
// First element is reserved
for(i=1;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(!raydium_ode_element[i].state)
{
strcpy(raydium_ode_element[i].name,name);
raydium_ode_element[i].object=group;
raydium_ode_element[i].user_tag=tag;
if(strlen(mesh))
{
raydium_ode_element[i].mesh=raydium_object_find_load(mesh);
if(tx<0) // AUTODETECT
{
int ratio=tx;
raydium_object_find_axes_max(raydium_ode_element[i].mesh,&tx,&ty,&tz);
tx*=(-ratio);
ty*=(-ratio);
tz*=(-ratio);
}
}
if(type==RAYDIUM_ODE_STANDARD)
{
raydium_ode_element[i].body=dBodyCreate(raydium_ode_world);
dMassSetBox(&m,1,tx,ty,tz);
dMassAdjust(&m,mass);
dBodySetMass(raydium_ode_element[i].body,&m);
dBodySetData(raydium_ode_element[i].body,&raydium_ode_element[i]);
// dBodySetAutoDisableSF1(raydium_ode_element[i].body,1);
}
else raydium_ode_element[i].body=0;
raydium_ode_element[i].geom=dCreateBox(0,tx,ty,tz);
raydium_ode_element[i].state=type;
dGeomSetBody(raydium_ode_element[i].geom,raydium_ode_element[i].body);
dGeomSetData(raydium_ode_element[i].geom,&raydium_ode_element[i]);
dSpaceAdd(raydium_ode_object[group].group,raydium_ode_element[i].geom);
raydium_ode_element_material(i,RAYDIUM_ODE_MATERIAL_DEFAULT);
raydium_ode_element_slip(i,RAYDIUM_ODE_SLIP_DEFAULT);
raydium_ode_element[i].distant=raydium_ode_network_distant_create;
raydium_ode_network_distant_create=0;
if(!raydium_ode_network_next_local_only)
raydium_ode_network_element_new(i);
raydium_ode_network_next_local_only=0;
return i;
}
raydium_log("ODE: No more element slots ! aborting \"%s\" creation",name);
return -1;
}
signed char raydium_ode_element_ray_attach(int element, dReal length, dReal dirx, dReal diry, dReal dirz)
{
raydium_ode_Element *e;
if(!raydium_ode_element_isvalid(element))
{
raydium_log("ODE: Error: Cannot attach ray to element: element is not valid");
return 0;
}
if(raydium_ode_element[element].state!=RAYDIUM_ODE_STANDARD)
{
raydium_log("ODE: Error: Cannot attach ray to non standard elements");
return 0;
}
e=&raydium_ode_element[element];
// There's no problem with any previous ray, we only update it
if(!e->ray.state)
{
e->ray.geom=dCreateRay(raydium_ode_object[raydium_ode_object_find("GLOBAL")].group,length);
dGeomSetData(e->ray.geom,e);
e->ray.state=1;
}
dGeomRaySetLength(e->ray.geom,length);
e->ray.rel_dir[0]=dirx;
e->ray.rel_dir[1]=diry;
e->ray.rel_dir[2]=dirz;
return 1;
}
signed char raydium_ode_element_ray_attach_name(char *element, dReal length, dReal dirx, dReal diry, dReal dirz)
{
return raydium_ode_element_ray_attach(raydium_ode_element_find(element),length,dirx,diry,dirz);
}
signed char raydium_ode_element_ray_delete(int element)
{
raydium_ode_Element *e;
if(!raydium_ode_element_isvalid(element))
{
raydium_log("ODE: Error: Cannot delete ray from element: element is not valid");
return 0;
}
e=&raydium_ode_element[element];
if(!e->ray.state)
{
raydium_log("ODE: Error: Cannot delete ray from element: there's no ray");
return 0;
}
dGeomDestroy(e->ray.geom);
e->ray.state=0;
return 1;
}
signed char raydium_ode_element_ray_delete_name(char *element)
{
return raydium_ode_element_ray_delete(raydium_ode_element_find(element));
}
signed char raydium_ode_element_ray_get(int element, raydium_ode_Ray *result)
{
raydium_ode_Element *e;
if(!raydium_ode_element_isvalid(element))
{
raydium_log("ODE: Error: Cannot get ray informations: element is not valid");
return 0;
}
e=&raydium_ode_element[element];
if(!e->ray.state)
{
raydium_log("ODE: Error: Cannot get ray informations: there's no ray");
return 0;
}
memcpy(result,&e->ray,sizeof(raydium_ode_Ray));
return 1;
}
signed char raydium_ode_element_ray_get_name(char *element, raydium_ode_Ray *result)
{
return raydium_ode_element_ray_get(raydium_ode_element_find(element),result);
}
int raydium_ode_element_fix(char *name, int *elem, int nelems, signed char keepgeoms)
{
dReal aabb[6];
dReal aabbR[6];
dReal bounding[3];
dReal position[3];
int group;
int elemN;
int i,j;
int done;
dReal *data;
dMass m;
dReal mass;
if(keepgeoms)
raydium_log("ODE: element_fix: keepgeoms not implemented yet !");
if(raydium_ode_element_find(name)>=0)
{
raydium_log("ODE: Error: Cannot fix elements as \"%s\": name already exists",name);
return -1;
}
if(nelems<1)
{
raydium_log("ODE: Error: Must fix at least one element");
return -1;
}
for(i=0;i<nelems;i++)
if(!raydium_ode_element_isvalid(elem[i]))
{
raydium_log("ODE: Error: Cannot fix elements: one element is not valid");
return -1;
}
for(i=0;i<nelems;i++)
if(raydium_ode_element[elem[i]].state!=RAYDIUM_ODE_STANDARD)
{
raydium_log("ODE: Error: Cannot fix non standard elements");
return -1;
}
group=raydium_ode_element[elem[0]].object;
for(i=1;i<nelems;i++)
if(raydium_ode_element[elem[i]].object!=group)
{
raydium_log("ODE: Error: Cannot fix elements: not owned by the same object");
return -1;
}
// 2 - create new element (using AABB from elements)
dGeomGetAABB(raydium_ode_element[elem[0]].geom,aabbR);
for(i=1;i<nelems;i++)
{
dGeomGetAABB(raydium_ode_element[elem[i]].geom,aabb);
for(j=0;j<6;j+=2)
{
aabbR[j ]=raydium_trigo_min(aabb[j ],aabbR[j ]);
aabbR[j+1]=raydium_trigo_max(aabb[j+1],aabbR[j+1]);
}
}
bounding[0]=aabbR[1]-aabbR[0];
bounding[1]=aabbR[3]-aabbR[2];
bounding[2]=aabbR[5]-aabbR[4];
position[0]=aabbR[0]+(bounding[0]/2.f);
position[1]=aabbR[2]+(bounding[1]/2.f);
position[2]=aabbR[4]+(bounding[2]/2.f);
// Now, we can create an new box element with some dummy values:
elemN=raydium_ode_object_box_add(name,group,0.f,bounding[0],bounding[1],bounding[2],RAYDIUM_ODE_STANDARD,0,"");
raydium_ode_element[elemN].state=RAYDIUM_ODE_FIXING;
raydium_ode_element_move(elemN,position);
// 3 - save elements to new element
done=0;
mass=0;
for(i=0;i<nelems;i++)
for(j=0;j<RAYDIUM_ODE_ELEMENT_MAX_FIXING;j++)
if(raydium_ode_element[elemN].fixed_elements[j]==NULL)
{
raydium_ode_element[elemN].fixed_elements[j]=malloc(sizeof(raydium_ode_ElementInternalSave));
strcpy(raydium_ode_element[elemN].fixed_elements[j]->name,raydium_ode_element[elem[i]].name);
raydium_ode_element[elemN].fixed_elements[j]->type=dGeomGetClass(raydium_ode_element[elem[i]].geom);
dGeomBoxGetLengths(raydium_ode_element[elem[i]].geom,raydium_ode_element[elemN].fixed_elements[j]->box_sizes);
raydium_ode_element[elemN].fixed_elements[j]->sphere_radius=dGeomSphereGetRadius(raydium_ode_element[elem[i]].geom);
dBodyGetMass(raydium_ode_element[elem[i]].body,&m);
raydium_ode_element[elemN].fixed_elements[j]->mass=m.mass;
raydium_ode_element[elemN].fixed_elements[j]->object=raydium_ode_element[elem[i]].object;
raydium_ode_element[elemN].fixed_elements[j]->mesh=raydium_ode_element[elem[i]].mesh;
raydium_ode_element[elemN].fixed_elements[j]->slip=raydium_ode_element[elem[i]].slip;
raydium_ode_element[elemN].fixed_elements[j]->cfm=raydium_ode_element[elem[i]].cfm;
raydium_ode_element[elemN].fixed_elements[j]->erp=raydium_ode_element[elem[i]].erp;
data=(dReal *)dGeomGetPosition(raydium_ode_element[elem[i]].geom);
memcpy(raydium_ode_element[elemN].fixed_elements[j]->rel_pos,data,sizeof(dReal)*3);
raydium_ode_element[elemN].fixed_elements[j]->rel_pos[0]-=position[0];
raydium_ode_element[elemN].fixed_elements[j]->rel_pos[1]-=position[1];
raydium_ode_element[elemN].fixed_elements[j]->rel_pos[2]-=position[2];
dGeomGetQuaternion(raydium_ode_element[elem[i]].geom,raydium_ode_element[elemN].fixed_elements[j]->rel_rot);
raydium_ode_element[elemN].fixed_elements[j]->user_data=raydium_ode_element[elem[i]].user_data;
raydium_ode_element[elemN].fixed_elements[j]->user_tag=raydium_ode_element[elem[i]].user_tag;
dBodyGetMass(raydium_ode_element[elem[i]].body,&m);
raydium_ode_element[elemN].fixed_elements[j]->OnBlow=raydium_ode_element[elem[i]].OnBlow;
raydium_ode_element[elemN].fixed_elements[j]->OnDelete=raydium_ode_element[elem[i]].OnDelete;
mass+=m.mass;
done++;
j=RAYDIUM_ODE_ELEMENT_MAX_FIXING; // jump to next element to save
}
if(done!=nelems)
raydium_log("ODE: Error: only %i/%i elems were fixed to %s ! Continue anyway...",done,nelems,name);
// 4 - delete elements
for(i=0;i<nelems;i++)
raydium_ode_element_delete(elem[i],1); // delete joints, too /!\ (must fix this)
// 5 - compute new mass
dMassSetBox(&m,1,bounding[0],bounding[1],bounding[2]);
dMassAdjust(&m,mass);
dBodySetMass(raydium_ode_element[elemN].body,&m);
return elemN;
}
void raydium_ode_element_unfix(int e)
{
int i;
raydium_log("ODE: unfix unimplemented !");
return;
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: Cannot unfix element: element is not valid");
return;
}
if(raydium_ode_element[e].state!=RAYDIUM_ODE_FIXING)
{
raydium_log("ODE: Error: Cannot unfix a non-fixing element");
return;
}
for(i=0;i<RAYDIUM_ODE_ELEMENT_MAX_FIXING;i++)
if(raydium_ode_element[e].fixed_elements[i])
{
// TODO:
// test type
// create element (using name)
// move/rotate
// restor params (erp, cfm, ...)
}
raydium_ode_element_delete(e,1);
}
void raydium_ode_element_mass(int elem, dReal mass)
{
dMass m;
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot change mass of element: invalid index or name");
return;
}
if(raydium_ode_element[elem].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: Cannot change mass of a static element");
return;
}
if(dGeomGetClass(raydium_ode_element[elem].geom)==dBoxClass)
{
dMassSetSphere(&m,1,dGeomSphereGetRadius(raydium_ode_element[elem].geom));
}
else
{
dVector3 size;
dGeomBoxGetLengths(raydium_ode_element[elem].geom,size);
dMassSetBox(&m,1,size[0],size[1],size[2]);
}
dMassAdjust(&m,mass);
dBodySetMass(raydium_ode_element[elem].body,&m);
}
void raydium_ode_element_mass_name(char *elem, dReal mass)
{
raydium_ode_element_mass(raydium_ode_element_find(elem),mass);
}
void raydium_ode_element_move(int elem, dReal *pos)
{
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot move element: invalid index or name");
return;
}
dGeomSetPosition(raydium_ode_element[elem].geom,pos[0],pos[1],pos[2]);
}
void raydium_ode_element_move_3f(int elem, dReal x,dReal y, dReal z)
{
dReal pos[3];
pos[0]=x;
pos[1]=y;
pos[2]=z;
raydium_ode_element_move(elem,pos);
}
void raydium_ode_element_move_name(char *name, dReal *pos)
{
raydium_ode_element_move(raydium_ode_element_find(name),pos);
}
void raydium_ode_element_move_name_3f(char *name, dReal x,dReal y, dReal z)
{
raydium_ode_element_move_3f(raydium_ode_element_find(name),x,y,z);
}
void raydium_ode_element_rotate(int elem, dReal *rot)
{
dMatrix3 R;
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot rotate element: invalid index or name");
return;
}
dRFromEulerAngles(R,rot[0],rot[1],rot[2]);
dGeomSetRotation(raydium_ode_element[elem].geom,R);
}
void raydium_ode_element_rotate_3f(int elem, dReal rx, dReal ry, dReal rz)
{
dReal rot[3];
rot[0]=rx;
rot[1]=ry;
rot[2]=rz;
raydium_ode_element_rotate(elem,rot);
}
void raydium_ode_element_rotate_name(char *name, dReal *rot)
{
raydium_ode_element_rotate(raydium_ode_element_find(name),rot);
}
void raydium_ode_element_rotateq(int elem, dReal *rot)
{
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot rotate element: invalid index or name");
return;
}
dGeomSetQuaternion(raydium_ode_element[elem].geom,rot);
}
void raydium_ode_element_rotateq_name(char *name, dReal * rot)
{
raydium_ode_element_rotateq(raydium_ode_element_find(name),rot);
}
void raydium_ode_element_rotate_name_3f(char *name, dReal rx, dReal ry, dReal rz)
{
raydium_ode_element_rotate_3f(raydium_ode_element_find(name),rx,ry,rz);
}
void raydium_ode_element_rotate_direction(int elem, signed char Force0OrVel1)
{
dReal *vel;
dMatrix3 R;
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot align element: invalid index or name");
return;
}
if(raydium_ode_element[elem].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: Cannot align a static element");
return;
}
if(!Force0OrVel1)
vel=(dReal *)dBodyGetForce(raydium_ode_element[elem].body);
else
vel=(dReal *)dBodyGetLinearVel(raydium_ode_element[elem].body);
dRFrom2Axes(R,vel[0],vel[1],vel[2], vel[0],vel[1],vel[2]*0); // 1 0 0
dBodySetRotation(raydium_ode_element[elem].body,R);
}
void raydium_ode_element_rotate_direction_name(char *e, signed char Force0OrVel1)
{
raydium_ode_element_rotate_direction(raydium_ode_element_find(e),Force0OrVel1);
}
void raydium_ode_element_data_set(int e, void *data)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: Cannot set element data: invalid index or name");
return;
}
raydium_ode_element[e].user_data=data;
}
void raydium_ode_element_data_set_name(char *e, void *data)
{
raydium_ode_element_data_set(raydium_ode_element_find(e),data);
}
void *raydium_ode_element_data_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: Cannot get element data: invalid index or name");
return NULL;
}
return raydium_ode_element[e].user_data;
}
void *raydium_ode_element_data_get_name(char *e)
{
return raydium_ode_element_data_get(raydium_ode_element_find(e));
}
int raydium_ode_element_tag_get(int e)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: Cannot get element tag: invalid index or name");
return 0;
}
return raydium_ode_element[e].user_tag;
}
int raydium_ode_element_tag_get_name(char *e)
{
return raydium_ode_element_tag_get(raydium_ode_element_find(e));
}
// move object elements to pos (pos is used for the LAST element of your object)
void raydium_ode_object_move(int obj, dReal *pos)
{
int i,n;
raydium_ode_Element *e;
dReal *refp;
dReal *act;
dReal diff[3];
dReal ref[3];
if(!raydium_ode_object_isvalid(obj))
{
raydium_log("ODE: Error: Cannot move object: invalid index or name");
return;
}
//n=dGeomGroupGetNumGeoms(raydium_ode_object[obj].group);
n=dSpaceGetNumGeoms(raydium_ode_object[obj].group);
if(!n) return;
//refp=(dReal *)dGeomGetPosition(dGeomGroupGetGeom(raydium_ode_object[obj].group,0));
refp=(dReal *)dGeomGetPosition(dSpaceGetGeom(raydium_ode_object[obj].group,0));
ref[0]=refp[0];
ref[1]=refp[1];
ref[2]=refp[2];
e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,0));
raydium_ode_element_move(e->id,pos);
for(i=1;i<n;i++)
{
act=(dReal *)dGeomGetPosition(dSpaceGetGeom(raydium_ode_object[obj].group,i));
diff[0]=pos[0]+(act[0]-ref[0]);
diff[1]=pos[1]+(act[1]-ref[1]);
diff[2]=pos[2]+(act[2]-ref[2]);
//raydium_log("%f %f %f",act[0],act[1],act[2]);
e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,i));
raydium_ode_element_move(e->id,diff);
}
}
void raydium_ode_object_move_name(char *name, dReal *pos)
{
raydium_ode_object_move(raydium_ode_object_find(name),pos);
}
void raydium_ode_object_move_name_3f(char *name, dReal x,dReal y, dReal z)
{
dReal pos[3];
pos[0]=x;
pos[1]=y;
pos[2]=z;
raydium_ode_object_move_name(name,pos);
}
// rotate object (rotation is done around LAST element of obj)
void raydium_ode_object_rotateq(int obj, dReal *rot)
{
int i,n;
raydium_ode_Element *e;
raydium_ode_Element *ref;
dBodyID body;
dReal *pos;
dReal *epos; // allocated by raydium_ode_element_pos_get(), see below
//dReal vect[3];
dVector3 res;
//raydium_log("obj rotate unimplemented"); return;
if(!raydium_ode_object_isvalid(obj))
{
raydium_log("ODE: Error: Cannot rotateq object: invalid index or name");
return;
}
n=dSpaceGetNumGeoms(raydium_ode_object[obj].group);
if(!n) return;
// 1 - rotate elements (THIS IS NOT THE CORRECT WAY TO DO IT !)
for(i=1;i<n;i++)
{
e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,i));
raydium_ode_element_rotateq(e->id,rot);
}
// 2 - create a temporary body (based on reference element)
body=dBodyCreate(raydium_ode_world);
ref=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,0));
pos=raydium_ode_element_pos_get(ref->id);
dBodySetPosition(body,pos[0],pos[1],pos[2]);
dBodySetQuaternion(body,rot);
// 3 - replace rotated elements
for(i=1;i<n;i++)
{
// 3 - 1 - Get relative point from real body
e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,i));
epos=raydium_ode_element_pos_get(e->id);
dBodyGetPosRelPoint(ref->body,epos[0],epos[1],epos[2],res);
//printf("---> %s %f %f %f\n",e->name,res[0],res[1],res[2]);
// 3 - 2 - Apply relative point to world with "fake" body
dBodyGetRelPointPos(body,res[0],res[1],res[2],epos);
// 3 - 3 - Change position
raydium_ode_element_move(e->id,epos);
}
dBodyDestroy(body);
raydium_ode_element_rotateq(ref->id,rot);
}
void raydium_ode_object_rotateq_name(char *obj, dReal *rot)
{
raydium_ode_object_rotateq(raydium_ode_object_find(obj),rot);
}
void raydium_ode_object_rotate(int obj, dReal *rot)
{
dMatrix3 R;
dQuaternion Q;
dRFromEulerAngles(R,rot[0],rot[1],rot[2]);
dRtoQ(R,Q);
raydium_ode_object_rotateq(obj,Q);
}
void raydium_ode_object_rotate_name(char *obj, dReal *rot)
{
raydium_ode_object_rotate(raydium_ode_object_find(obj),rot);
}
void raydium_ode_object_rotate_name_3f(char *obj, dReal rx, dReal ry, dReal rz)
{
dReal r[3];
r[0]=rx;
r[1]=ry;
r[2]=rz;
raydium_ode_object_rotate_name(obj,r);
}
void raydium_ode_joint_suspension(int j, dReal erp, dReal cfm)
{
void (*f)(dJointID,int,dReal);
int type;
if(!raydium_ode_joint_isvalid(j))
{
raydium_log("ODE: Cannot set ERP and CFM for this joint: invalid name or index");
return;
}
type=dJointGetType(raydium_ode_joint[j].joint);
switch(type)
{
case dJointTypeHinge2:
f=dJointSetHinge2Param;
break;
case dJointTypeHinge:
f=dJointSetHingeParam;
break;
default: raydium_log("ODE: ERROR: suspension: joint type not supported!");
}
f(raydium_ode_joint[j].joint,dParamSuspensionERP,erp);
f(raydium_ode_joint[j].joint,dParamSuspensionCFM,cfm);
}
void raydium_ode_joint_suspension_name(char *j, dReal erp, dReal cfm)
{
raydium_ode_joint_suspension(raydium_ode_joint_find(j),erp,cfm);
}
int raydium_ode_joint_attach_hinge2(char *name, int elem1, int elem2, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
{
int i;
const dReal *a;
if(raydium_ode_joint_find(name)>=0)
{
raydium_log("ODE: Cannot add (hinge2) joint \"%s\": name already exists",name);
return -1;
}
if(elem1==RAYDIUM_ODE_JOINT_FIXED)
elem1=RAYDIUM_ODE_MAX_ELEMENTS;
if(elem2==RAYDIUM_ODE_JOINT_FIXED)
elem2=RAYDIUM_ODE_MAX_ELEMENTS;
if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
{
raydium_log("ODE: Error: Cannot attach hinge2: one element is not valid");
return -1;
}
if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
{
raydium_log("ODE: Error: Cannot attach a static element");
return -1;
}
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(!raydium_ode_joint[i].state)
{
dJointFeedback *jf;
strcpy(raydium_ode_joint[i].name,name);
raydium_ode_joint[i].joint=dJointCreateHinge2(raydium_ode_world,0);
dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
a=dBodyGetPosition(raydium_ode_element[elem2].body);
dJointSetHinge2Anchor(raydium_ode_joint[i].joint,a[0],a[1],a[2]);
dJointSetHinge2Axis1(raydium_ode_joint[i].joint,axe1x,axe1y,axe1z);
dJointSetHinge2Axis2(raydium_ode_joint[i].joint,axe2x,axe2y,axe2z);
dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
dJointSetFeedback(raydium_ode_joint[i].joint,jf);
raydium_ode_joint[i].state=1;
dJointSetHinge2Param (raydium_ode_joint[i].joint,dParamSuspensionERP,0.1);
dJointSetHinge2Param (raydium_ode_joint[i].joint,dParamSuspensionCFM,0.9);
return i;
}
raydium_log("ODE: No more joint slots ! aborting \"%s\" (hinge2) creation",name);
return -1;
}
int raydium_ode_joint_attach_hinge2_name(char *name, char *elem1, char *elem2, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
{
int e1,e2;
e1=raydium_ode_element_find(elem1);
e2=raydium_ode_element_find(elem2);
return raydium_ode_joint_attach_hinge2(name,e1,e2,axe1x,axe1y,axe1z,axe2x,axe2y,axe2z);
}
int raydium_ode_joint_attach_universal(char *name, int elem1, int elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
{
int i;
if(raydium_ode_joint_find(name)>=0)
{
raydium_log("ODE: Cannot add (universal) joint \"%s\": name already exists",name);
return -1;
}
if(elem1==RAYDIUM_ODE_JOINT_FIXED)
elem1=RAYDIUM_ODE_MAX_ELEMENTS;
if(elem2==RAYDIUM_ODE_JOINT_FIXED)
elem2=RAYDIUM_ODE_MAX_ELEMENTS;
if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
{
raydium_log("ODE: Error: Cannot attach universal: one element is not valid");
return -1;
}
if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
{
raydium_log("ODE: Error: Cannot attach a static element");
return -1;
}
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(!raydium_ode_joint[i].state)
{
dJointFeedback *jf;
strcpy(raydium_ode_joint[i].name,name);
raydium_ode_joint[i].joint=dJointCreateUniversal(raydium_ode_world,0);
dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
dJointSetUniversalAnchor(raydium_ode_joint[i].joint,posx,posy,posz);
dJointSetUniversalAxis1(raydium_ode_joint[i].joint,axe1x,axe1y,axe1z);
dJointSetUniversalAxis2(raydium_ode_joint[i].joint,axe2x,axe2y,axe2z);
dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
dJointSetFeedback(raydium_ode_joint[i].joint,jf);
raydium_ode_joint[i].state=1;
return i;
}
raydium_log("ODE: No more joint slots ! aborting \"%s\" (universal) creation",name);
return -1;
}
int raydium_ode_joint_attach_universal_name(char *name, char *elem1, char *elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
{
int e1,e2;
e1=raydium_ode_element_find(elem1);
e2=raydium_ode_element_find(elem2);
return raydium_ode_joint_attach_universal(name,e1,e2,posx,posy,posz,axe1x,axe1y,axe1z,axe2x,axe2y,axe2z);
}
int raydium_ode_joint_attach_hinge(char *name, int elem1, int elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z)
{
int i;
if(raydium_ode_joint_find(name)>=0)
{
raydium_log("ODE: Cannot add (hinge) joint \"%s\": name already exists",name);
return -1;
}
if(elem1==RAYDIUM_ODE_JOINT_FIXED)
elem1=RAYDIUM_ODE_MAX_ELEMENTS;
if(elem2==RAYDIUM_ODE_JOINT_FIXED)
elem2=RAYDIUM_ODE_MAX_ELEMENTS;
if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
{
raydium_log("ODE: Error: Cannot attach hinge: one element is not valid");
return -1;
}
if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
{
raydium_log("ODE: Error: Cannot attach a static element");
return -1;
}
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(!raydium_ode_joint[i].state)
{
dJointFeedback *jf;
strcpy(raydium_ode_joint[i].name,name);
raydium_ode_joint[i].joint=dJointCreateHinge(raydium_ode_world,0);
dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
dJointSetHingeAnchor(raydium_ode_joint[i].joint,posx,posy,posz);
dJointSetHingeAxis(raydium_ode_joint[i].joint,axe1x,axe1y,axe1z);
dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
dJointSetFeedback(raydium_ode_joint[i].joint,jf);
raydium_ode_joint[i].state=1;
return i;
}
raydium_log("ODE: No more joint slots ! aborting \"%s\" (hinge) creation",name);
return -1;
}
int raydium_ode_joint_attach_hinge_name(char *name, char *elem1, char *elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z)
{
int e1,e2;
e1=raydium_ode_element_find(elem1);
e2=raydium_ode_element_find(elem2);
return raydium_ode_joint_attach_hinge(name,e1,e2,posx,posy,posz,axe1x,axe1y,axe1z);
}
int raydium_ode_joint_attach_fixed(char *name, int elem1, int elem2)
{
int i;
if(raydium_ode_joint_find(name)>=0)
{
raydium_log("ODE: Cannot add (fixed) joint \"%s\": name already exists",name);
return -1;
}
if(elem1==RAYDIUM_ODE_JOINT_FIXED)
elem1=RAYDIUM_ODE_MAX_ELEMENTS;
if(elem2==RAYDIUM_ODE_JOINT_FIXED)
elem2=RAYDIUM_ODE_MAX_ELEMENTS;
if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
{
raydium_log("ODE: Error: Cannot attach fixed: one element is not valid");
return -1;
}
if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
{
raydium_log("ODE: Error: Cannot attach a static element");
return -1;
}
//raydium_log("ODE: Warning: fixed joint slows down physics !");
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(!raydium_ode_joint[i].state)
{
dJointFeedback *jf;
strcpy(raydium_ode_joint[i].name,name);
raydium_ode_joint[i].joint=dJointCreateFixed(raydium_ode_world,0);
dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
dJointSetFixed(raydium_ode_joint[i].joint);
dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
dJointSetFeedback(raydium_ode_joint[i].joint,jf);
raydium_ode_joint[i].state=1;
return i;
}
raydium_log("ODE: No more joint slots ! aborting \"%s\" (fixed) creation",name);
return -1;
}
int raydium_ode_joint_attach_fixed_name(char *name, char *elem1, char *elem2)
{
return raydium_ode_joint_attach_fixed(name,raydium_ode_element_find(elem1),raydium_ode_element_find(elem2));
}
void raydium_ode_joint_hinge_limits(int j, dReal lo, dReal hi)
{
if(raydium_ode_joint_isvalid(j))
{
dJointSetHingeParam(raydium_ode_joint[j].joint,dParamLoStop,lo);
dJointSetHingeParam(raydium_ode_joint[j].joint,dParamHiStop,hi);
dJointSetHingeParam(raydium_ode_joint[j].joint,dParamLoStop,lo); // ODE "feature" :)
return;
}
raydium_log("ODE: Error: cannot set joint limits: invalid index or name");
}
void raydium_ode_joint_hinge_limits_name(char *j, dReal lo, dReal hi)
{
return raydium_ode_joint_hinge_limits(raydium_ode_joint_find(j),lo,hi);
}
void raydium_ode_joint_universal_limits(int j, dReal lo1, dReal hi1, dReal lo2, dReal hi2)
{
if(raydium_ode_joint_isvalid(j))
{
dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop ,lo1);
dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamHiStop ,hi1);
dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop ,lo1);
dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop2,lo2);
dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamHiStop2,hi2);
dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop2,lo2);
return;
}
raydium_log("ODE: Error: cannot set joint limits: invalid index or name");
}
void raydium_ode_joint_universal_limits_name(char *j, dReal lo1, dReal hi1, dReal lo2, dReal hi2)
{
return raydium_ode_joint_universal_limits(raydium_ode_joint_find(j),lo1,hi1,lo2,hi2);
}
void raydium_ode_joint_hinge2_block(int j, signed char block)
{
// TODO: test if joint is hinge2 type
if(raydium_ode_joint_isvalid(j))
{
// raydium_ode_joint[j].hinge2correct=block;
if(!block)
{
dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,-dInfinity);
dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamHiStop,dInfinity);
dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,-dInfinity);
}
else
{
dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,0);
dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamHiStop,0);
dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,0);
}
return;
}
raydium_log("ODE: Error: cannot block: invalid index or name");
}
void raydium_ode_joint_hinge2_block_name(char *name, signed char block)
{
raydium_ode_joint_hinge2_block(raydium_ode_joint_find(name),block);
}
void raydium_ode_joint_delete_callback(int j, void (*f)(int))
{
if(!raydium_ode_joint_isvalid(j))
{
raydium_log("ODE: Error: Cannot set joint \"OnDelete\" callback: invalid index/name");
return;
}
raydium_ode_joint[j].OnDelete=f;
}
void raydium_ode_joint_delete_callback_name(char *name, void (*f)(int))
{
raydium_ode_joint_delete_callback(raydium_ode_joint_find(name),f);
}
void raydium_ode_joint_break_force(int j, dReal maxforce)
{
if(!raydium_ode_joint_isvalid(j))
{
raydium_log("ODE: Error: Cannot set break limit force: invalid index/name");
return;
}
raydium_ode_joint[j].breakableforce=maxforce;
}
void raydium_ode_joint_break_force_name(char *name, dReal maxforce)
{
raydium_ode_joint_break_force(raydium_ode_joint_find(name),maxforce);
}
void raydium_ode_joint_elements_get(int j, int *e1, int *e2)
{
raydium_ode_Element *elem1;
raydium_ode_Element *elem2;
if(!raydium_ode_joint_isvalid(j))
{
raydium_log("ODE: Error: Cannot get joint's attached elements: invalid index/name");
return;
}
// may crash if joint is disconnected at one of his ends !
elem1=dBodyGetData(dJointGetBody(raydium_ode_joint[j].joint,0));
elem2=dBodyGetData(dJointGetBody(raydium_ode_joint[j].joint,1));
*e1=elem1->id;
*e2=elem2->id;
}
void raydium_ode_joint_elements_get_name(char *j, int *e1, int *e2)
{
raydium_ode_joint_elements_get(raydium_ode_joint_find(j),e1,e2);
}
void raydium_ode_motor_update_joints_data_internal(int j)
{
int i;
if(raydium_ode_motor_isvalid(j))
{
if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ROCKET)
{
dReal speed;
// test if element is attached:
if(raydium_ode_motor[j].rocket_element<0)
return;
speed=raydium_ode_motor[j].speed;
if(raydium_ode_motor[j].rocket_playermovement &&
!raydium_ode_element[raydium_ode_motor[j].rocket_element]._touched )
speed=0;
if(speed!=0.f)
dBodyAddRelForceAtRelPos(raydium_ode_element[raydium_ode_motor[j].rocket_element].body,
raydium_ode_motor[j].rocket_direction[0],
raydium_ode_motor[j].rocket_direction[1],
raydium_ode_motor[j].rocket_direction[2],
raydium_ode_motor[j].rocket_position[0],
raydium_ode_motor[j].rocket_position[1],
raydium_ode_motor[j].rocket_position[2]);
return;
}
// if motor is anything else than a rocket:
for(i=0;i<RAYDIUM_ODE_MOTOR_MAX_JOINTS;i++)
if(raydium_ode_motor[j].joints[i]>=0)
{
void (*SetParam)(dJointID,int,dReal);
dReal (*GetAngle)(dJointID);
int vel;
int fmax;
int type;
char cancel=0;
switch(raydium_ode_motor[j].joints_axe[i])
{
case 0:
vel=dParamVel;
fmax=dParamFMax;
break;
case 1:
vel=dParamVel2;
fmax=dParamFMax2;
break;
case 2:
vel=dParamVel3;
fmax=dParamFMax3;
break;
default:
cancel=1;
raydium_log("ODE: Motor: Invalid axe for this joint (%s, motor is %s)",raydium_ode_joint[raydium_ode_motor[j].joints[i]].name,raydium_ode_motor[j].name);
}
type=dJointGetType(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint);
switch(type)
{
case dJointTypeHinge2:
SetParam=dJointSetHinge2Param;
GetAngle=dJointGetHinge2Angle1;
if(raydium_ode_motor[j].joints_axe[i]!=0 && raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ANGULAR)
{
cancel=1;
raydium_log("ODE: Only axe Hinge2 axe 0 is supported with angular motors (%s, motor is %s)",raydium_ode_joint[raydium_ode_motor[j].joints[i]].name,raydium_ode_motor[j].name);
}
break;
case dJointTypeHinge:
SetParam=dJointSetHingeParam;
GetAngle=dJointGetHingeAngle;
break;
default:
cancel=1;
raydium_log("ODE: Motor: Invalid joint type (%s, motor is %s)",raydium_ode_joint[raydium_ode_motor[j].joints[i]].name,raydium_ode_motor[j].name);
}
if(cancel) continue; // previous tests failed
if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ENGINE)
{
dReal speed;
dReal force;
speed=raydium_ode_motor[j].speed*raydium_ode_motor[j].gears[raydium_ode_motor[j].gear];
if(raydium_ode_motor[j].gears[raydium_ode_motor[j].gear]==0.0)
force=0;
else
force=raydium_ode_motor[j].force*(1/raydium_ode_motor[j].gears[raydium_ode_motor[j].gear]);
// force=raydium_ode_motor[j].force;
// raydium_log("speed=%f force=%f",speed,force);
SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,vel,speed);
SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,fmax,force);
}
if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ANGULAR)
{
dReal v;
SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,fmax,raydium_ode_motor[j].force);
v = raydium_ode_motor[j].angle -
GetAngle(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint);
SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,vel,v*10);
}
}
return;
}
raydium_log("ODE: Error (internal): motor update failed: not found");
}
void raydium_ode_motor_speed(int j, dReal force)
{
if(raydium_ode_motor_isvalid(j))
{
raydium_ode_motor[j].speed=force;
// refresh direction using direction and speed:
if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ROCKET)
raydium_ode_motor_rocket_orientation(j,raydium_ode_motor[j].rocket_orientation[0],raydium_ode_motor[j].rocket_orientation[1],raydium_ode_motor[j].rocket_orientation[2]);
return;
}
raydium_log("ODE: Error: cannot set motor's speed: invalid index or name");
}
void raydium_ode_motor_speed_name(char *name, dReal force)
{
raydium_ode_motor_speed(raydium_ode_motor_find(name),force);
}
// power = 0 means motor has no effect on joints (free moves)
void raydium_ode_motor_power_max(int j, dReal power)
{
if(raydium_ode_motor_isvalid(j))
{
raydium_ode_motor[j].force=power;
return;
}
raydium_log("ODE: Error: cannot set max motor's power: invalid index or name");
}
void raydium_ode_motor_power_max_name(char *name, dReal power)
{
raydium_ode_motor_power_max(raydium_ode_motor_find(name),power);
}
void raydium_ode_motor_angle(int j, dReal angle)
{
if(raydium_ode_motor_isvalid(j))
{
raydium_ode_motor[j].angle=angle;
return;
}
raydium_log("ODE: Error: cannot set motor's angle: invalid index or name");
}
void raydium_ode_motor_angle_name(char *motor, dReal angle)
{
raydium_ode_motor_angle(raydium_ode_motor_find(motor),angle);
}
void raydium_ode_motor_gears_set(int m,dReal *gears, int n_gears)
{
if(raydium_ode_motor_isvalid(m))
{
if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ENGINE)
{
raydium_log("ODE: Error: cannot use a gearbox with a non-engine motor");
return;
}
memcpy(raydium_ode_motor[m].gears,gears,sizeof(dReal)*n_gears);
raydium_ode_motor[m].gear_max=n_gears-1;
return;
}
raydium_log("ODE: Error: cannot configure motor's gears: invalid index or name");
}
void raydium_ode_motor_gears_set_name(char *m,dReal *gears,int n_gears)
{
raydium_ode_motor_gears_set(raydium_ode_motor_find(m),gears,n_gears);
}
void raydium_ode_motor_gear_change(int m, int gear)
{
if(raydium_ode_motor_isvalid(m))
{
if(gear<0 || gear>raydium_ode_motor[m].gear_max)
{
raydium_log("ODE: Error: invalid gear (%i)",gear);
return;
}
raydium_ode_motor[m].gear=gear;
return;
}
raydium_log("ODE: Error: cannot set motor's gear: invalid index or name");
}
void raydium_ode_motor_gear_change_name(char *m, int gear)
{
raydium_ode_motor_gear_change(raydium_ode_motor_find(m),gear);
}
dReal *raydium_ode_element_pos_get(int j)
{
if(raydium_ode_element_isvalid(j))
{
return (dReal *)dGeomGetPosition(raydium_ode_element[j].geom);
}
raydium_log("ODE: Error: cannot get element position: invalid index or name");
return NULL;
}
dReal *raydium_ode_element_pos_get_name(char *name)
{
return raydium_ode_element_pos_get(raydium_ode_element_find(name));
}
signed char raydium_ode_element_rotq_get(int j, dReal * res)
{
if(raydium_ode_element_isvalid(j))
{
dGeomGetQuaternion(raydium_ode_element[j].geom,res);
return 1;
}
raydium_log("ODE: Error: cannot get element rotation (quaternion): invalid index or name");
return 0;
}
signed char raydium_ode_element_rotq_get_name(char *name, dReal * res)
{
return raydium_ode_element_rotq_get(raydium_ode_element_find(name),res);
}
/*
signed char raydium_ode_element_rot_get(int e, dReal *rx, dReal *ry, dReal *rz)
{
// From Andrzej Szombierski <qq@kuku.eu.org> (ODE ML)
// patched by Daniel Monteiro Basso <dmbasso@inf.ufrgs.br> (ODE ML)
// but it's not what i want, again.. arrrgh ;)
const dReal epsilon=0.0000001;
dReal *matrix;
dReal c;
if(raydium_ode_element_isvalid(e))
{
matrix=(dReal *)dGeomGetRotation(raydium_ode_element[e].geom);
if(matrix[2] < 1-epsilon && matrix[2] > -1+epsilon)
{
*ry=-asin(matrix[2]);
c=cos(*ry);
*rx= atan2(matrix[6]/c,matrix[10]/c);
*rz= atan2(matrix[1]/c,matrix[0]/c);
}
else
{
*rz=0;
*ry=-atan2(matrix[2],0);
*rx= atan2(-matrix[9],matrix[5]);
}
// rad to deg
//(*rx)*=180/PI;
//(*ry)*=180/PI;
//(*rz)*=180/PI;
return 1;
}
raydium_log("ODE: Error: cannot get element rotation (3f): invalid index or name");
return 0;
}
*/
signed char raydium_ode_element_rot_get(int e, dReal *rx, dReal *ry, dReal *rz)
{
// From Andrzej Szombierski <qq@kuku.eu.org> (ODE ML)
// Original code version: "absolute" angles
// Do not apply back returned angles ! (not ODE "formated")
const dReal epsilon=0.0000001;
dReal *matrix;
dReal c;
if(raydium_ode_element_isvalid(e))
{
matrix=(dReal *)dGeomGetRotation(raydium_ode_element[e].geom);
if(matrix[8] < 1-epsilon && matrix[8] > -1+epsilon)
{
*ry=-asin(matrix[8]);
c=cos(*ry);
*rx= atan2(matrix[9]/c,matrix[10]/c);
*rz= atan2(matrix[4]/c,matrix[0]/c);
}
else
{
*rz=0;
*ry=-atan2(matrix[8],0);
*rx= atan2(-matrix[6],matrix[5]);
}
// rad to deg
//(*rx)*=180/PI;
//(*ry)*=180/PI;
//(*rz)*=180/PI;
return 1;
}
raydium_log("ODE: Error: cannot get element rotation (3f): invalid index or name");
return 0;
}
signed char raydium_ode_element_rot_get_name(char *e, dReal *rx, dReal *ry, dReal *rz)
{
return raydium_ode_element_rot_get(raydium_ode_element_find(e),rx,ry,rz);
}
void raydium_ode_element_sound_update(int e, int source)
{
if(raydium_ode_element_isvalid(e))
{
dReal *pos;
pos=raydium_ode_element_pos_get(e);
raydium_sound_SetSourcePos(source,pos);
return;
}
raydium_log("ODE: Error: cannot update source: invalid index or name");
return;
}
void raydium_ode_element_sound_update_name(char *e, int source)
{
raydium_ode_element_sound_update(raydium_ode_element_find(e),source);
}
void raydium_ode_element_RelPointPos(int e, dReal px, dReal py, dReal pz, dReal *res)
{
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot get RelPointPos: invalid index or name");
return;
}
if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: Cannot get RelPointPos on a static element");
return;
}
dBodyGetRelPointPos(raydium_ode_element[e].body,px,py,pz,res);
}
void raydium_ode_element_RelPointPos_name(char *e, dReal px, dReal py, dReal pz, dReal *res)
{
raydium_ode_element_RelPointPos(raydium_ode_element_find(e),px,py,pz,res);
}
int raydium_ode_motor_create(char *name, int obj, signed char type)
{
int i;
if(raydium_ode_motor_find(name)>=0)
{
raydium_log("ODE: Cannot add motor \"%s\": name already exists",name);
return -1;
}
if(!raydium_ode_object_isvalid(obj))
{
raydium_log("ODE: Cannot add motor \"%s\": parent object is invalid",name);
return -1;
}
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
if(!raydium_ode_motor[i].state)
{
strcpy(raydium_ode_motor[i].name,name);
raydium_ode_motor[i].state=type;
raydium_ode_motor[i].object=obj;
return i;
}
raydium_log("ODE: No more motor slots ! aborting \"%s\" creation",name);
return -1;
}
void raydium_ode_motor_attach(int motor, int joint, int joint_axe)
{
int i;
int e1,e2;
raydium_ode_Element *elem1;
raydium_ode_Element *elem2;
if(raydium_ode_motor_isvalid(motor) && raydium_ode_joint_isvalid(joint))
{
// may crash if joint is disconnected at one of its ends !
elem1=dBodyGetData(dJointGetBody(raydium_ode_joint[joint].joint,0));
elem2=dBodyGetData(dJointGetBody(raydium_ode_joint[joint].joint,1));
e1=elem1->id;
e2=elem2->id;
if(raydium_ode_motor[motor].object!=raydium_ode_element[e1].object &&
raydium_ode_motor[motor].object!=raydium_ode_element[e2].object )
{
raydium_log("ODE: Cannot attach motor: joint must be attached to at least one element from motor's object");
return;
}
for(i=0;i<RAYDIUM_ODE_MOTOR_MAX_JOINTS;i++)
if(raydium_ode_motor[motor].joints[i]<0)
{
raydium_ode_motor[motor].joints[i]=joint;
raydium_ode_motor[motor].joints_axe[i]=joint_axe;
return;
}
raydium_log("ODE: Error: no more joint slots for motor \"%s\" (while adding %s)", raydium_ode_motor[motor].name,raydium_ode_joint[joint].name);
return;
}
raydium_log("ODE: Error: cannot attach joint to motor: invalid index or name");
}
void raydium_ode_motor_attach_name(char *motor, char *joint, int joint_axe)
{
raydium_ode_motor_attach(raydium_ode_motor_find(motor),raydium_ode_joint_find(joint),joint_axe);
}
dReal raydium_ode_motor_speed_get(int m, int gears)
{
dReal *vel;
dReal velf=0;
int i,n=0;
dBodyID body;
if(!raydium_ode_motor_isvalid(m))
{
raydium_log("ODE: Error: Cannot get motor speed: invalid name or index");
return 0;
}
if(raydium_ode_motor[m].state==RAYDIUM_ODE_MOTOR_ROCKET)
return raydium_ode_motor[m].speed;
for(i=0;i<RAYDIUM_ODE_MOTOR_MAX_JOINTS;i++)
if(raydium_ode_motor[m].joints[i]>=0)
{
body=dJointGetBody(raydium_ode_joint[raydium_ode_motor[m].joints[i]].joint,raydium_ode_motor[m].joints_axe[i]);
vel=(dReal *)dBodyGetAngularVel(body);
velf+=sqrt(vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]);
n++;
}
if(n)
{
velf/=n;
if(gears) velf*=(1/raydium_trigo_abs(raydium_ode_motor[m].gears[raydium_ode_motor[m].gear]));
}
else velf=0;
return velf;
}
dReal raydium_ode_motor_speed_get_name(char *name, int gears)
{
return raydium_ode_motor_speed_get(raydium_ode_motor_find(name),gears);
}
void raydium_ode_motor_rocket_set(int m, int element, dReal x, dReal y, dReal z)
{
if(!raydium_ode_motor_isvalid(m) || !raydium_ode_element_isvalid(element))
{
raydium_log("ODE: Error: Cannot set rocket element: invalid name or index");
return;
}
if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ROCKET)
{
raydium_log("ODE: Error: Cannot set rocket element: motor is not a rocket");
return;
}
raydium_ode_motor[m].rocket_element=element;
raydium_ode_motor[m].rocket_position[0]=x;
raydium_ode_motor[m].rocket_position[1]=y;
raydium_ode_motor[m].rocket_position[2]=z;
}
void raydium_ode_motor_rocket_set_name(char *motor,char *element, dReal x, dReal y, dReal z)
{
raydium_ode_motor_rocket_set(raydium_ode_motor_find(motor),raydium_ode_element_find(element),x,y,z);
}
void raydium_ode_motor_rocket_orientation(int m, dReal rx, dReal ry, dReal rz)
{
GLfloat res[3];
GLfloat dir[3]={0,0,1};
if(!raydium_ode_motor_isvalid(m))
{
raydium_log("ODE: Error: Cannot set rocket orientation: invalid name or index");
return;
}
if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ROCKET)
{
raydium_log("ODE: Error: Cannot set rocket orientation: motor is not a rocket");
return;
}
raydium_ode_motor[m].rocket_orientation[0]=rx;
raydium_ode_motor[m].rocket_orientation[1]=ry;
raydium_ode_motor[m].rocket_orientation[2]=rz;
raydium_trigo_rotate(dir,rx,ry,rz,res);
res[0]*=raydium_ode_motor[m].speed;
res[1]*=raydium_ode_motor[m].speed;
res[2]*=raydium_ode_motor[m].speed;
raydium_ode_motor[m].rocket_direction[0]=res[0];
raydium_ode_motor[m].rocket_direction[1]=res[1];
raydium_ode_motor[m].rocket_direction[2]=res[2];
}
void raydium_ode_motor_rocket_orientation_name(char *name, dReal rx, dReal ry, dReal rz)
{
raydium_ode_motor_rocket_orientation(raydium_ode_motor_find(name),rx,ry,rz);
}
void raydium_ode_motor_rocket_playermovement(int m, signed char isplayermovement)
{
if(!raydium_ode_motor_isvalid(m))
{
raydium_log("ODE: Error: Cannot set rocket type (player movement): invalid name or index");
return;
}
if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ROCKET)
{
raydium_log("ODE: Error: Cannot set rocket type (player movement): motor is not a rocket");
return;
}
raydium_ode_motor[m].rocket_playermovement=isplayermovement;
}
void raydium_ode_motor_rocket_playermovement_name(char *m, signed char isplayermovement)
{
return raydium_ode_motor_rocket_playermovement(raydium_ode_motor_find(m),isplayermovement);
}
signed char raydium_ode_motor_delete(int e)
{
if(!raydium_ode_motor_isvalid(e))
{
raydium_log("ODE: Error: Cannot delete motor: invalid name or index");
return 0;
}
raydium_ode_init_motor(e);
return 1;
}
signed char raydium_ode_motor_delete_name(char *name)
{
return raydium_ode_motor_delete(raydium_ode_motor_find(name));
}
signed char raydium_ode_joint_delete(int joint)
{
int i,j;
void (*f)(int);
if(!raydium_ode_joint_isvalid(joint))
{
raydium_log("ODE: Error: Cannot delete joint: invalid name or index");
return 0;
}
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
for(j=0;j<RAYDIUM_ODE_MOTOR_MAX_JOINTS;j++)
if(raydium_ode_motor[i].joints[j]==joint)
{
raydium_ode_motor[i].joints[j]=-1;
raydium_ode_motor[i].joints_axe[j]=0;
}
free(dJointGetFeedback(raydium_ode_joint[joint].joint));
dJointDestroy(raydium_ode_joint[joint].joint);
f=raydium_ode_joint[joint].OnDelete;
if(f) f(joint);
raydium_ode_init_joint(joint);
return 1;
}
signed char raydium_ode_joint_delete_name(char *name)
{
return raydium_ode_joint_delete(raydium_ode_joint_find(name));
}
signed char raydium_ode_element_delete(int e, signed char deletejoints)
{
int i;
int (*f)(int);
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: Cannot delete element: invalid name or index");
return 0;
}
// Only for "first pass"
if(!raydium_ode_element[e].marked_as_deleted)
{
f=raydium_ode_element[e].OnDelete;
if(f && !f(e)) return 0; // user cancel
}
if(raydium_ode_element_delete_LOCK)
{
//raydium_log("ODE: Warning: deleting of elements is locked !");
// element will be delete at the end of the current collide test loop (but
// is ignored for all future collisions in this test)
raydium_ode_element[e].marked_as_deleted=1;
return 1;
}
// verify element state after user callback (element may be already deleted ! :)
// note : this test is bad.. an new element may have taken the free slot ...
// in facts, a user must not delete an element during his own OnDelete callback
if(!raydium_ode_element_isvalid(e))
return 1; // delete is successfull thru user callback
raydium_ode_network_element_delete(e);
if(deletejoints && raydium_ode_element[e].state!=RAYDIUM_ODE_STATIC)
{
raydium_ode_Joint *j;
int *to_delete;
int n_joints;
n_joints=dBodyGetNumJoints(raydium_ode_element[e].body);
if(n_joints)
{
// create a list of joint to delete ...
to_delete=malloc(n_joints*sizeof(int));
for(i=0;i<n_joints;i++)
{
j=dJointGetData(dBodyGetJoint(raydium_ode_element[e].body,i));
if(j)
to_delete[i]=j->id;
else
to_delete[i]=-1;
}
// ... and delete joints
for(i=0;i<n_joints;i++)
if(to_delete[i]>=0)
raydium_ode_joint_delete(to_delete[i]);
free(to_delete);
}
}
if(raydium_ode_element[e].ray.state)
raydium_ode_element_ray_delete(e);
dGeomSetData(raydium_ode_element[e].geom,NULL); // no more linked to this structure
dGeomDestroy(raydium_ode_element[e].geom);
if(raydium_ode_element[e].body)
dBodyDestroy(raydium_ode_element[e].body);
for(i=0;i<RAYDIUM_ODE_ELEMENT_MAX_FIXING;i++)
if(raydium_ode_element[e].fixed_elements[i])
{
free(raydium_ode_element[e].fixed_elements[i]);
raydium_ode_element[e].fixed_elements[i]=NULL;
}
// linked rockets
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
if(raydium_ode_motor[i].state==RAYDIUM_ODE_MOTOR_ROCKET &&
raydium_ode_motor[i].rocket_element==e)
raydium_ode_motor_delete(i);
if(raydium_ode_element[e].particle>=0)
raydium_particle_generator_delete(raydium_ode_element[e].particle);
raydium_ode_init_element(e);
return 1;
}
signed char raydium_ode_element_delete_name(char *name, signed char deletejoints)
{
return raydium_ode_element_delete(raydium_ode_element_find(name),deletejoints);
}
signed char raydium_ode_object_delete(int obj)
{
int i;
//raydium_ode_Element *e;
if(!raydium_ode_object_isvalid(obj))
{
raydium_log("ODE: Error: Cannot delete object: invalid name or index");
return 0;
}
if(obj == raydium_ode_object_find("GLOBAL"))
{
raydium_log("ODE: Error: Cannot delete special \"GLOBAL\" object");
return 0;
}
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
if(raydium_ode_motor[i].state &&
raydium_ode_motor[i].object==obj)
raydium_ode_motor_delete(i);
// Wow... group indices are unstable while deleting group's bodies !
//for(i=0;i<dGeomGroupGetNumGeoms(raydium_ode_object[obj].group);i++)
// {
// e=dGeomGetData(dGeomGroupGetGeom(raydium_ode_object[obj].group,i));
// raydium_ode_element_delete(e->id,1);
// }
// So i'll search for bodies in my own structures
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].object==obj)
raydium_ode_element_delete(i,1);
dSpaceDestroy(raydium_ode_object[obj].group);
raydium_ode_init_object(obj);
return 1;
}
signed char raydium_ode_object_delete_name(char *name)
{
return raydium_ode_object_delete(raydium_ode_object_find(name));
}
signed char raydium_ode_explosion_delete(int e)
{
if(!raydium_ode_explosion_isvalid(e))
{
raydium_log("ODE: Error: Cannot delete explosion: invalid name or index");
return 0;
}
if(raydium_ode_explosion[e].element>=0)
raydium_ode_element_delete(raydium_ode_explosion[e].element,0);
raydium_ode_init_explosion(e);
return 1;
}
signed char raydium_ode_element_moveto(int element, int object, signed char deletejoints)
{
int i;
raydium_ode_Joint *j;
dBodyID e1,e2;
if(!raydium_ode_element_isvalid(element) ||
!raydium_ode_object_isvalid(object) )
{
raydium_log("ODE: Error: Cannot move element to object: invalid index/name");
return 0;
}
for(i=0;i<dBodyGetNumJoints(raydium_ode_element[element].body);i++)
{
j=dJointGetData(dBodyGetJoint(raydium_ode_element[element].body,i));
if(deletejoints)
raydium_ode_joint_delete(j->id);
else
{
e1=dJointGetBody(j->joint,0);
e2=dJointGetBody(j->joint,1);
if(e1==raydium_ode_element[element].body) e1=0;
if(e2==raydium_ode_element[element].body) e2=0;
dJointAttach(j->joint,e1,e2);
}
}
// Well well well.. donno if dGeomGroupAdd removes body from previous
// GeomGroup, so i do it myself.
raydium_ode_element[element]._movesfrom=raydium_ode_element[element].object;
dSpaceRemove(raydium_ode_object[raydium_ode_element[element].object].group,
raydium_ode_element[element].geom);
raydium_ode_element[element].object=object;
dSpaceAdd(raydium_ode_object[raydium_ode_element[element].object].group,
raydium_ode_element[element].geom);
return 1;
}
signed char raydium_ode_element_moveto_name(char *element, char *object, char signed deletejoints)
{
return raydium_ode_element_moveto(raydium_ode_element_find(element),raydium_ode_object_find(object),deletejoints);
}
void raydium_ode_joint_break(int j)
{
dJointFeedback *jf;
dReal force=0;
if(!raydium_ode_joint[j].breakableforce) return;
if(!raydium_ode_joint_isvalid(j))
{
raydium_log("ODE: Error: cannot test joint breaking: invalid index/name");
return;
}
jf=dJointGetFeedback(raydium_ode_joint[j].joint);
if(!jf) return;
force+=raydium_trigo_abs(jf->f1[0]);
force+=raydium_trigo_abs(jf->f1[1]);
force+=raydium_trigo_abs(jf->f1[2]);
force+=raydium_trigo_abs(jf->f2[0]);
force+=raydium_trigo_abs(jf->f2[1]);
force+=raydium_trigo_abs(jf->f2[2]);
//raydium_log("%f %s",force,raydium_ode_joint[j].name);
if(force>raydium_ode_joint[j].breakableforce)
{
raydium_ode_joint[j].breaking=1;
raydium_ode_joint_delete(j);
}
}
signed char raydium_ode_launcher(int element, int from_element, dReal *rot, dReal force)
{
dReal res[3];
dReal *initial;
dVector3 final;
dReal dir[3]={0,0,1};
if(!raydium_ode_element_isvalid(element) ||
!raydium_ode_element_isvalid(from_element) )
{
raydium_log("ODE: Cannot launch element: invalid name or index");
return 0;
}
if( raydium_ode_element[from_element].state==RAYDIUM_ODE_STATIC ||
raydium_ode_element[element].state==RAYDIUM_ODE_STATIC )
{
raydium_log("ODE: Cannot launch element: you must use non-static elements");
return 0;
}
raydium_trigo_rotate(dir,rot[0],rot[1],rot[2],res);
res[0]*=force;
res[1]*=force;
res[2]*=force;
dBodyVectorToWorld(raydium_ode_element[from_element].body,res[0],res[1],res[2],final);
initial=(dReal *)dBodyGetLinearVel(raydium_ode_element[from_element].body);
final[0]+=initial[0];
final[1]+=initial[1];
final[2]+=initial[2];
dBodyAddForce(raydium_ode_element[element].body,final[0],final[1],final[2]);
return 1;
}
signed char raydium_ode_launcher_name(char *element, char *from_element, dReal *rot, dReal force)
{
return raydium_ode_launcher(raydium_ode_element_find(element),raydium_ode_element_find(from_element),rot,force);
}
signed char raydium_ode_launcher_name_3f(char *element, char *from_element, dReal rx, dReal ry, dReal rz, dReal force)
{
dReal tmp[3];
tmp[0]=rx;
tmp[1]=ry;
tmp[2]=rz;
return raydium_ode_launcher_name(element,from_element,tmp,force);
}
signed char raydium_ode_launcher_simple(int element, int from_element, dReal *lrot, dReal force)
{
dReal *pos;
dQuaternion rot;
if(!raydium_ode_element_isvalid(element) ||
!raydium_ode_element_isvalid(from_element) )
{
raydium_log("ODE: Cannot (simple) launch element: invalid name or index");
return 0;
}
// test if element and from_element are from the same objet
if(raydium_ode_element[element].object!=raydium_ode_element[from_element].object)
{
raydium_log("ODE: Cannot (simple) launch element: element and from_element are not from the same object");
return 0;
}
pos=raydium_ode_element_pos_get(from_element);
raydium_ode_element_rotq_get(from_element,rot);
raydium_ode_element_move(element,pos);
raydium_ode_element_rotateq(element,rot);
raydium_ode_launcher(element,from_element,lrot,force);
raydium_ode_element_moveto(element,raydium_ode_object_find("GLOBAL"),0);
return 1;
}
signed char raydium_ode_launcher_simple_name(char *element, char *from_element, dReal *rot, dReal force)
{
return raydium_ode_launcher_simple(raydium_ode_element_find(element),raydium_ode_element_find(from_element),rot,force);
}
signed char raydium_ode_launcher_simple_name_3f(char *element, char *from_element, dReal rx, dReal ry, dReal rz, dReal force)
{
dReal tmp[3];
tmp[0]=rx;
tmp[1]=ry;
tmp[2]=rz;
return raydium_ode_launcher_simple_name(element,from_element,tmp,force);
}
void raydium_ode_explosion_blow_rand(dReal radius, dReal max_force, dReal rand_factor, dReal *pos)
{
int i;
void (*f)(signed char, dReal, dReal, dReal *);
void (*g)(int, dReal, dReal);
float rmx[3];
float minrandtorq, maxrandtorq;
if(raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT && !raydium_ode_network_explosion_create)
{
// propag over network
raydium_ode_network_Explosion exp;
exp.type=RAYDIUM_ODE_NETWORK_EXPLOSION_BLOW;
exp.radius=radius;
memcpy(exp.pos,pos,sizeof(dReal)*3);
exp.force=max_force;
raydium_ode_network_explosion_send(&exp);
return;
}
raydium_ode_network_explosion_create=0;
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD)
{
dReal vect[3];
dReal *elp;
dReal len;
dReal force;
elp=(dReal *)dGeomGetPosition(raydium_ode_element[i].geom);
//raydium_log("Blow: %s",raydium_ode_element[i].name);
// explosion to element vector
vect[0]=elp[0]-pos[0];
vect[1]=elp[1]-pos[1];
vect[2]=elp[2]-pos[2];
// distance from explosion
len=sqrt(vect[0]*vect[0] + vect[1]*vect[1] + vect[2]*vect[2]);
if(len==0.f) continue;
// raydium_log("dist from core: %f (radius=%f)",len,radius);
// normalize vector
vect[0]/=len;
vect[1]/=len;
vect[2]/=len;
if(len>radius) continue;
force = ((radius*radius) - (len*len)) / (radius * radius) * max_force;
// raydium_log("resulting force: %f (max force at core=%f)",force,max_force);
vect[0]*=force;
vect[1]*=force;
vect[2]*=force;
// raydium_log("resulting impulse vector: [%f %f %f]",vect[0],vect[1],vect[2]);
dBodyAddForce(raydium_ode_element[i].body,vect[0],vect[1],vect[2]);
if(rand_factor)
{
//ugly way of get a random float array
minrandtorq=-rand_factor;
maxrandtorq= rand_factor;
rmx[0]=raydium_random_f(minrandtorq,maxrandtorq)*force;
rmx[1]=raydium_random_f(minrandtorq,maxrandtorq)*force;
rmx[2]=raydium_random_f(minrandtorq,maxrandtorq)*force;
//added random torque to the pieces
dBodyAddTorque(raydium_ode_element[i].body,rmx[0],rmx[1],rmx[2]);
}
g=raydium_ode_element[i].OnBlow;
if(g) g(i,force,max_force);
}
f=raydium_ode_ExplosionCallback;
if(f)
f(RAYDIUM_ODE_NETWORK_EXPLOSION_BLOW,radius,max_force,pos);
}
void raydium_ode_explosion_blow(dReal radius, dReal max_force, dReal *pos)
{
raydium_ode_explosion_blow_rand(radius,max_force,0,pos);
}
void raydium_ode_explosion_blow_3f(dReal radius, dReal max_force, dReal px, dReal py, dReal pz)
{
dReal pos[3];
pos[0]=px;
pos[1]=py;
pos[2]=pz;
raydium_ode_explosion_blow(radius,max_force,pos);
}
void raydium_ode_explosion_blow_rand_3f(dReal radius, dReal max_force, dReal rand_factor, dReal px, dReal py, dReal pz)
{
dReal pos[3];
pos[0]=px;
pos[1]=py;
pos[2]=pz;
raydium_ode_explosion_blow_rand(radius,max_force,rand_factor,pos);
}
int raydium_ode_explosion_create(char *name, dReal final_radius, dReal propag, dReal *pos)
{
int i;
void (*f)(signed char, dReal, dReal, dReal *);
if(raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT && !raydium_ode_network_explosion_create)
{
// propag over network
raydium_ode_network_Explosion exp;
exp.type=RAYDIUM_ODE_NETWORK_EXPLOSION_EXPL;
exp.radius=final_radius;
memcpy(exp.pos,pos,sizeof(dReal)*3);
exp.propag=propag;
raydium_ode_network_explosion_send(&exp);
return -1; // WARNING: During networked games, this function always returns -1
}
raydium_ode_network_explosion_create=0;
if(raydium_ode_explosion_find(name)>=0)
{
raydium_log("ODE: Cannot add explosion \"%s\": name already exists",name);
return -1;
}
for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
if(!raydium_ode_explosion[i].state)
{
strcpy(raydium_ode_explosion[i].name,name);
raydium_ode_explosion[i].state=1;
raydium_ode_explosion[i].config_radius=final_radius;
raydium_ode_explosion[i].config_propag=propag;
raydium_ode_explosion[i].radius=0;
memcpy(raydium_ode_explosion[i].position,pos,sizeof(dReal)*3);
f=raydium_ode_ExplosionCallback;
if(f)
f(RAYDIUM_ODE_NETWORK_EXPLOSION_EXPL,final_radius,propag,pos);
return i;
}
raydium_log("ODE: No more explosion slots ! aborting \"%s\" creation",name);
return -1;
}
// load object from disk
// raydium_ode_object_load(char *filename, char *suffix)
////////
void raydium_ode_element_camera_inboard(int e, dReal px, dReal py, dReal pz, dReal lookx, dReal looky, dReal lookz)
{
dBodyID body;
dVector3 face,up,cam;
if(!raydium_ode_element_isvalid(e))
{
raydium_log("ODE: Error: cannot set camera on element: invalid name or index");
return;
}
if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
{
raydium_log("ODE: Error: cannot put camera on a static element");
return;
}
//glLoadIdentity();
raydium_camera_internal_prepare();
body=raydium_ode_element[e].body;
dBodyGetRelPointPos(body,px,py,pz,cam);
dBodyGetRelPointPos(body,lookx,looky,lookz,face);
dBodyVectorToWorld (body,0,0,1,up);
gluLookAt(cam[0],cam[1],cam[2],face[0],face[1],face[2],up[0],up[1],up[2]);
raydium_camera_internal(cam[0], cam[1], cam[2]);
}
void raydium_ode_element_camera_inboard_name(char *name, dReal px, dReal py, dReal pz, dReal lookx, dReal looky, dReal lookz)
{
raydium_ode_element_camera_inboard(raydium_ode_element_find(name),px,py,pz,lookx,looky,lookz);
}
void raydium_ode_draw_all(signed char names)
{
int i,j;
signed char (*bef)(int);
void (*aft)(int);
bef=raydium_ode_BeforeElementDrawCallback;
aft=raydium_ode_AfterElementDrawCallback;
if(names==RAYDIUM_ODE_DRAW_DEBUG)
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
if(raydium_ode_motor[i].state==RAYDIUM_ODE_MOTOR_ROCKET)
{
int j;
j=raydium_ode_motor[i].rocket_element;
raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[j].geom), (dReal *)dGeomGetRotation(raydium_ode_element[j].geom));
glDisable(GL_LIGHTING);
raydium_texture_current_set_name("rgb(1,0,0)");
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_main);
glLineWidth(1.f);
glBegin(GL_LINES);
glVertex3f(raydium_ode_motor[i].rocket_position[0],raydium_ode_motor[i].rocket_position[1],raydium_ode_motor[i].rocket_position[2]);
glVertex3f(raydium_ode_motor[i].rocket_position[0]+raydium_ode_motor[i].rocket_direction[0],
raydium_ode_motor[i].rocket_position[1]+raydium_ode_motor[i].rocket_direction[1],
raydium_ode_motor[i].rocket_position[2]+raydium_ode_motor[i].rocket_direction[2]);
glEnd();
if(raydium_light_enabled_tag)
glEnable(GL_LIGHTING);
}
if(names==RAYDIUM_ODE_DRAW_DEBUG)
for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
if(raydium_ode_explosion[i].state)
{
int j;
j=raydium_ode_explosion[i].element;
raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[j].geom), (dReal *)dGeomGetRotation(raydium_ode_element[j].geom));
glutWireSphere(raydium_ode_explosion[i].radius,10,10);
}
if(names==RAYDIUM_ODE_DRAW_DEBUG)
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(raydium_ode_joint[i].state)
{
void (*f1)(dJointID,dVector3);
void (*f2)(dJointID,dVector3);
dVector3 res1;
dVector3 res2;
dMatrix3 r;
int type;
char col;
dRSetIdentity(r);
type=dJointGetType(raydium_ode_joint[i].joint);
switch(type)
{
case dJointTypeHinge2:
f1=dJointGetHinge2Anchor;
f2=dJointGetHinge2Anchor2;
col='3';
break;
case dJointTypeUniversal:
f1=dJointGetUniversalAnchor;
f2=dJointGetUniversalAnchor2;
col='5';
break;
case dJointTypeHinge:
f1=dJointGetHingeAnchor;
f2=dJointGetHingeAnchor2;
col='2';
break;
case dJointTypeFixed:
f1=NULL;
f2=NULL;
col='0';
break;
default: raydium_log("ODE: ERROR: draw_all: invalid joint type !");
}
if(f1 && f2)
{
f1(raydium_ode_joint[i].joint,res1);
f2(raydium_ode_joint[i].joint,res2);
raydium_texture_current_set_name("rgb(1,0,0)");
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_main);
raydium_camera_replace_go(res1,r);
glutWireSphere(0.05,5,5);
raydium_camera_replace_go(res2,r);
glutWireSphere(0.05,5,5);
raydium_osd_color_ega(col);
raydium_osd_printf_3D(res1[0],res1[1],res1[2],12,0.6,"font2.tga","<%s>",raydium_ode_joint[i].name);
}
}
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state)
{
if(names==RAYDIUM_ODE_DRAW_NORMAL ||
names==RAYDIUM_ODE_DRAW_SHADOWERS ||
names==RAYDIUM_ODE_DRAW_NORMAL_NO_POST)
{
if(names==RAYDIUM_ODE_DRAW_SHADOWERS && raydium_ode_element[i].mesh==raydium_shadow_ground_mesh)
continue;
if(names!=RAYDIUM_ODE_DRAW_SHADOWERS && bef && !bef(i))
continue;
raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[i].geom), (dReal *)dGeomGetRotation(raydium_ode_element[i].geom));
if(raydium_ode_element[i].mesh>=0)
{
if(raydium_shadow_rendering)
raydium_shadow_object_draw(raydium_ode_element[i].mesh);
else
raydium_object_draw(raydium_ode_element[i].mesh);
}
if(names!=RAYDIUM_ODE_DRAW_SHADOWERS && aft)
aft(i);
if(raydium_ode_element[i].particle>=0 && names!=RAYDIUM_ODE_DRAW_SHADOWERS)
{
dVector3 res;
// if element is static, fake a temporary body
if(raydium_ode_element[i].state==RAYDIUM_ODE_STATIC)
{
dBodyID body;
dReal *pos;
dQuaternion rot;
body=dBodyCreate(raydium_ode_world);
pos=raydium_ode_element_pos_get(i);
raydium_ode_element_rotq_get(i,rot);
dBodySetPosition(body,pos[0],pos[1],pos[2]);
dBodySetQuaternion(body,rot);
dBodyGetRelPointPos(body,
raydium_ode_element[i].particle_offset[0],
raydium_ode_element[i].particle_offset[1],
raydium_ode_element[i].particle_offset[2],
res);
dBodyDestroy(body);
}
else
if(raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD)
{
dBodyGetRelPointPos(raydium_ode_element[i].body,
raydium_ode_element[i].particle_offset[0],
raydium_ode_element[i].particle_offset[1],
raydium_ode_element[i].particle_offset[2],
res);
}
raydium_particle_generator_move(
raydium_ode_element[i].particle,res);
}
for(j=0;j<RAYDIUM_ODE_ELEMENT_MAX_FIXING;j++)
if(raydium_ode_element[i].fixed_elements[j])
{
glPushMatrix();
glTranslatef(raydium_ode_element[i].fixed_elements[j]->rel_pos[0],
raydium_ode_element[i].fixed_elements[j]->rel_pos[1],
raydium_ode_element[i].fixed_elements[j]->rel_pos[2]);
{
dMatrix3 R;
GLfloat matrix[16];
dQtoR(raydium_ode_element[i].fixed_elements[j]->rel_rot,R);
matrix[0]=R[0];
matrix[1]=R[4];
matrix[2]=R[8];
matrix[3]=0;
matrix[4]=R[1];
matrix[5]=R[5];
matrix[6]=R[9];
matrix[7]=0;
matrix[8]=R[2];
matrix[9]=R[6];
matrix[10]=R[10];
matrix[11]=0;
matrix[12]=0;
matrix[13]=0;
matrix[14]=0;
matrix[15]=1;
glMultMatrixf (matrix);
}
raydium_object_draw(raydium_ode_element[i].fixed_elements[j]->mesh);
glPopMatrix();
}
}
else
{
const dReal *p;
if(names==RAYDIUM_ODE_DRAW_DEBUG) // draw shape
{
raydium_rendering_internal_prepare_texture_render(0); // !!!
raydium_texture_current_set_name("rgb(1,0,0)");
raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[i].geom), (dReal *)dGeomGetRotation(raydium_ode_element[i].geom));
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_main);
if(dGeomGetClass(raydium_ode_element[i].geom)==dBoxClass)
{
dVector3 sides;
float lx;
float ly;
float lz;
dGeomBoxGetLengths(raydium_ode_element[i].geom,sides);
lx = sides[0]*0.5f;
ly = sides[1]*0.5f;
lz = sides[2]*0.5f;
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// sides
glBegin (GL_TRIANGLE_STRIP);
glNormal3f (-1,0,0);
glVertex3f (-lx,-ly,-lz);
glVertex3f (-lx,-ly,lz);
glVertex3f (-lx,ly,-lz);
glVertex3f (-lx,ly,lz);
glNormal3f (0,1,0);
glVertex3f (lx,ly,-lz);
glVertex3f (lx,ly,lz);
glNormal3f (1,0,0);
glVertex3f (lx,-ly,-lz);
glVertex3f (lx,-ly,lz);
glNormal3f (0,-1,0);
glVertex3f (-lx,-ly,-lz);
glVertex3f (-lx,-ly,lz);
glEnd();
// top face
glBegin (GL_TRIANGLE_FAN);
glNormal3f (0,0,1);
glVertex3f (-lx,-ly,lz);
glVertex3f (lx,-ly,lz);
glVertex3f (lx,ly,lz);
glVertex3f (-lx,ly,lz);
glEnd();
// bottom face
glBegin (GL_TRIANGLE_FAN);
glNormal3f (0,0,-1);
glVertex3f (-lx,-ly,-lz);
glVertex3f (-lx,ly,-lz);
glVertex3f (lx,ly,-lz);
glVertex3f (lx,-ly,-lz);
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
else
//if(dGeomGetClass(raydium_ode_element[i].geom)==dSphereClass)
{
glutWireSphere(dGeomSphereGetRadius(raydium_ode_element[i].geom),10,10);
}
p=dGeomGetPosition(raydium_ode_element[i].geom);
if(raydium_ode_element[i]._touched)
raydium_osd_color_ega('c');
else
raydium_osd_color_ega('f');
if(raydium_ode_element[i]._avoidedcol)
raydium_osd_color_ega('d');
if(!dGeomIsEnabled(raydium_ode_element[i].geom))
raydium_osd_color_ega('a');
if( raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD &&
!dBodyIsEnabled(raydium_ode_element[i].body) )
raydium_osd_color_ega('0');
raydium_osd_printf_3D(p[0],p[1],p[2],12,0.6,"font2.tga","%i %s (%s) @ %i",i,raydium_ode_element[i].name,raydium_ode_object[raydium_ode_element[i].object].name,raydium_ode_element[i].distant_owner);
}
if(names==RAYDIUM_ODE_DRAW_AABB) // draw AABB
{
dReal aabb[6];
raydium_camera_replace();
raydium_rendering_internal_prepare_texture_render(0); // !!
raydium_texture_current_set_name("rgb(0,0,1)");
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_main);
dGeomGetAABB(raydium_ode_element[i].geom,aabb);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// sides
glBegin (GL_TRIANGLE_STRIP);
glNormal3f (-1,0,0);
glVertex3f (aabb[0],aabb[2],aabb[4]);
glVertex3f (aabb[0],aabb[2],aabb[5]);
glVertex3f (aabb[0],aabb[3],aabb[4]);
glVertex3f (aabb[0],aabb[3],aabb[5]);
glNormal3f (0,1,0);
glVertex3f (aabb[1],aabb[3],aabb[4]);
glVertex3f (aabb[1],aabb[3],aabb[5]);
glNormal3f (1,0,0);
glVertex3f (aabb[1],aabb[2],aabb[4]);
glVertex3f (aabb[1],aabb[2],aabb[5]);
glNormal3f (0,-1,0);
glVertex3f (aabb[0],aabb[2],aabb[4]);
glVertex3f (aabb[0],aabb[2],aabb[5]);
glEnd();
// top face
glBegin (GL_TRIANGLE_FAN);
glNormal3f (0,0,1);
glVertex3f (aabb[0],aabb[2],aabb[5]);
glVertex3f (aabb[1],aabb[2],aabb[5]);
glVertex3f (aabb[1],aabb[3],aabb[5]);
glVertex3f (aabb[0],aabb[3],aabb[5]);
glEnd();
// bottom face
glBegin (GL_TRIANGLE_FAN);
glNormal3f (0,0,-1);
glVertex3f (aabb[0],aabb[2],aabb[4]);
glVertex3f (aabb[0],aabb[3],aabb[4]);
glVertex3f (aabb[1],aabb[3],aabb[4]);
glVertex3f (aabb[1],aabb[2],aabb[4]);
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if(names==RAYDIUM_ODE_DRAW_RAY)
{
if(raydium_ode_element[i].ray.state)
{
dVector3 start,dir;
dReal len;
raydium_rendering_internal_prepare_texture_render(0); // !!!
raydium_texture_current_set_name("rgb(1,0,0)");
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_main);
dGeomRayGet(raydium_ode_element[i].ray.geom,start,dir);
len=dGeomRayGetLength(raydium_ode_element[i].ray.geom);
raydium_camera_replace();
glBegin(GL_LINES);
//printf("%f %f %f | %f %f %f\n",start[0],start[1],start[2],dir[0],dir[1],dir[2]);
glVertex3f(start[0],start[1],start[2]);
glVertex3f(start[0]+(dir[0]*len),start[1]+(dir[1]*len),start[2]+(dir[2]*len));
glEnd();
}
}
}
}
if(names==RAYDIUM_ODE_DRAW_NORMAL) // but not RAYDIUM_ODE_DRAW_NORMAL_NO_POST
{
raydium_hdr_map(); // create HDR map
raydium_shadow_map_render();
}
}
void raydium_ode_near_callback(void *data, dGeomID o1, dGeomID o2)
{
int i,n;
// dirty, but...
#define N 400
static dContact contact[N];
dJointID c;
raydium_ode_Element *e1, *e2;
int ground_elem_id,distan_obj_id;
dReal erp=0;
dReal cfm=0;
dReal slip=0;
int count=0;
signed char (*f)(int,int, dContact *);
signed char (*r)(int,int, dContact *);
f=raydium_ode_CollideCallback;
r=raydium_ode_RayCallback;
if(dGeomIsSpace (o1) || dGeomIsSpace (o2))
{
raydium_ode_Object *oo1, *oo2;
signed char (*g)(int,int);
oo1=dGeomGetData(o1);
oo2=dGeomGetData(o2);
g=raydium_ode_ObjectNearCollide;
if(g && !g(oo1->id,oo2->id)) return;
dSpaceCollide2 (o1,o2,data,&raydium_ode_near_callback);
return;
}
ground_elem_id=raydium_ode_element_find("ground");
distan_obj_id=raydium_ode_object_find("DISTANT");
e1=dGeomGetData(o1);
e2=dGeomGetData(o2);
/*
// avoid "ground - distant elements" contacts (may do it for all static-static contacts ?)
if(e1->id == ground_elem_id && e2->object == distan_obj_id)
return;
if(e2->id == ground_elem_id && e1->object == distan_obj_id)
return;
// .
*/
// As said above, we will avoid all static-statics contacts.
// I think we must provide a "pre-filter" callback, since the user
// may need this contact infos
if(e1->state==RAYDIUM_ODE_STATIC && e2->state==RAYDIUM_ODE_STATIC)
return;
n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
if(n>=N-1)
raydium_log("ODE: WARNING ! Not enought contact points available ! (%i max)",N);
if (n > 0)
{
for (i=0; i<n; i++)
{
e1=dGeomGetData(contact[i].geom.g1);
e2=dGeomGetData(contact[i].geom.g2);
if(e1==NULL || e2==NULL)
continue; // Deleted, or not one of our elements
if(e1==e2)
continue; // May happend with ray
if(e1 && e1->marked_as_deleted)
return;
if(e2 && e2->marked_as_deleted)
return;
if( e1 && e2 && e1->_movesfrom>=0 &&
e1->_movesfrom==e2->object)
{
e1->_avoidedcol=1;
continue; // avoid collision ! (where are moving from this object)
}
if( e1 && e2 && e2->_movesfrom>=0 &&
e2->_movesfrom==e1->object)
{
e2->_avoidedcol=1;
continue; // avoid collision ! (where are moving from this object)
}
erp=cfm=slip=0;
if(e1)
{
erp=e1->erp;
cfm=e1->cfm;
slip=e1->slip;
count=1;
}
if(e2)
{
erp+=e2->erp;
cfm+=e2->cfm;
slip+=e2->slip;
count++;
}
if(count)
{
erp/=count;
cfm/=count;
slip/=count;
}
contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
dContactSoftERP | dContactSoftCFM | dContactApprox1;
contact[i].surface.mu = dInfinity;
contact[i].surface.slip1 = slip;
contact[i].surface.slip2 = slip;
contact[i].surface.soft_erp = erp;
contact[i].surface.soft_cfm = cfm;
if(dGeomGetClass(contact[i].geom.g1)==dRayClass)
{
// raydium_ode_RayCallback (1)
if(r)
{
int id1,id2;
id1=id2=-1;
if(e1) id1=e1->id;
if(e2) id2=e2->id;
if(!r(id1,id2,&contact[i])) continue;
}
if(e1 && e2 &&
(e1->ray.min_dist > contact[i].geom.depth || e1->ray.min_dist==0) )
{
e1->ray.min_dist=contact[i].geom.depth;
e1->ray.min_elem=e2->id;
memcpy(e1->ray.min_pos,contact[i].geom.pos,sizeof(dReal)*3);
}
if(e1 && e2 && e1->ray.max_dist < contact[i].geom.depth)
{
e1->ray.max_dist=contact[i].geom.depth;
e1->ray.max_elem=e2->id;
memcpy(e1->ray.max_pos,contact[i].geom.pos,sizeof(dReal)*3);
}
continue;
}
if(dGeomGetClass(contact[i].geom.g2)==dRayClass)
{
// raydium_ode_RayCallback (2)
if(r)
{
int id1,id2;
id1=id2=-1;
if(e1) id1=e1->id;
if(e2) id2=e2->id;
if(!r(id1,id2,&contact[i])) continue;
}
if(e1 && e2 &&
(e2->ray.min_dist > contact[i].geom.depth || e2->ray.min_dist==0) )
{
e2->ray.min_dist=contact[i].geom.depth;
e2->ray.min_elem=e1->id;
memcpy(e2->ray.min_pos,contact[i].geom.pos,sizeof(dReal)*3);
}
if(e1 && e2 && e2->ray.max_dist < contact[i].geom.depth)
{
e2->ray.max_dist=contact[i].geom.depth;
e2->ray.max_elem=e1->id;
memcpy(e2->ray.max_pos,contact[i].geom.pos,sizeof(dReal)*3);
}
continue;
}
// raydium_ode_CollideCallback
if(f)
{
int id1,id2;
id1=id2=-1;
if(e1) id1=e1->id;
if(e2) id2=e2->id;
if(!f(id1,id2,&contact[i])) continue;
}
if(e1) e1->_touched=1; // may use it as a counter ?
if(e2) e2->_touched=1; // ...
//printf("%s <-> %s\n",e1->name,e2->name); // let's flood :)
c = dJointCreateContact (raydium_ode_world,raydium_ode_contactgroup,&contact[i]);
dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2));
}
}
}
void raydium_ode_callback(void)
{
int i;
void (*f)(void);
f=raydium_ode_StepCallback;
raydium_ode_network_read();
if(f) f();
/*
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(raydium_ode_joint[i].state)
{
if(raydium_ode_joint[i].hinge2correct)
{
//dJointCorrectHinge2(raydium_ode_joint[i].joint);
}
}
*/
for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
if(raydium_ode_motor[i].state)
raydium_ode_motor_update_joints_data_internal(i);
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state)
{
// init per_step variables
raydium_ode_element[i]._touched=0;
raydium_ode_element[i]._avoidedcol=0;
raydium_ode_element[i].ground_texture=0;
// test for damping effect:
if( raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD &&
raydium_ode_element[i].rotfriction!=0.f)
{
dReal *torque;
dReal torqueinv[3];
// may use element size, too ...
torque=(dReal *)dBodyGetAngularVel(raydium_ode_element[i].body);
torqueinv[0]=torque[0]*-raydium_ode_element[i].rotfriction;
torqueinv[1]=torque[1]*-raydium_ode_element[i].rotfriction;
torqueinv[2]=torque[2]*-raydium_ode_element[i].rotfriction;
dBodyAddTorque(raydium_ode_element[i].body,torqueinv[0],torqueinv[1],torqueinv[2]);
}
if(raydium_ode_element[i].ray.state)
{
// update ray position and direction
dReal *pos;
dReal dir[3];
raydium_ode_Ray *r;
r=&raydium_ode_element[i].ray;
dBodyVectorToWorld(raydium_ode_element[i].body,
r->rel_dir[0],
r->rel_dir[1],
r->rel_dir[2],
dir);
//printf("set : %f %f %f\n",dir[0],dir[1],dir[2]);
pos=(dReal *)dBodyGetPosition(raydium_ode_element[i].body);
dGeomRaySet(r->geom,pos[0],pos[1],pos[2],dir[0],dir[1],dir[2]);
r->max_dist=0;
r->min_dist=0;
r->max_elem=r->min_elem=-1;
}
}
for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
if(raydium_ode_explosion[i].state)
{
// 1 - check if radius > config_radius (and then delete explosion)
if(raydium_ode_explosion[i].radius>raydium_ode_explosion[i].config_radius)
raydium_ode_explosion_delete(i);
else
{
// 2 - increment radius
raydium_ode_explosion[i].radius+=raydium_ode_explosion[i].config_propag;
// 3 - delete previous element if exists
if(raydium_ode_explosion[i].element>=0)
raydium_ode_element_delete(raydium_ode_explosion[i].element,0);
// 4 - create new element
// (not really a distant element, but we don't want progap' ...)
raydium_ode_network_distant_create=1;
raydium_ode_explosion[i].element=
raydium_ode_object_sphere_add(raydium_ode_explosion[i].name,
raydium_ode_object_find("GLOBAL"),
0,
raydium_ode_explosion[i].radius,
RAYDIUM_ODE_STATIC,
0, /* see below */
"");
raydium_ode_element[raydium_ode_explosion[i].element].user_tag=RAYDIUM_ODE_TAG_EXPLOSION;
raydium_ode_element_material(raydium_ode_explosion[i].element,RAYDIUM_ODE_MATERIAL_SOFT2);
raydium_ode_element_move(raydium_ode_explosion[i].element,raydium_ode_explosion[i].position);
}
}
raydium_ode_element_delete_LOCK=1;
//raydium_profile_start();
dSpaceCollide (raydium_ode_space,0,&raydium_ode_near_callback);
for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
if(raydium_ode_object[i].state && raydium_ode_object[i].colliding)
dSpaceCollide ((dSpaceID)raydium_ode_object[i].group,0,&raydium_ode_near_callback);
//raydium_profile_end("collision detection");
raydium_ode_element_delete_LOCK=0;
//raydium_profile_start();
#ifdef ODE_QUICKSTEP
dWorldQuickStep(raydium_ode_world,RAYDIUM_ODE_TIMESTEP);
#else
dWorldStep(raydium_ode_world,RAYDIUM_ODE_TIMESTEP);
#endif
//raydium_profile_end("world stepping");
dJointGroupEmpty (raydium_ode_contactgroup);
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state &&
raydium_ode_element[i].marked_as_deleted)
raydium_ode_element_delete(i,1);
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state &&
raydium_ode_element[i]._movesfrom>=0 &&
!raydium_ode_element[i]._avoidedcol )
raydium_ode_element[i]._movesfrom=-1;
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state &&
raydium_ode_element[i].isplayer )
{
dMatrix3 R;
dRFromEulerAngles(R,0,0,raydium_ode_element[i].playerangle);
dBodySetRotation(raydium_ode_element[i].body,R);
dBodySetAngularVel(raydium_ode_element[i].body,0,0,0);
}
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state &&
raydium_ode_element[i].ttl!=-1 )
{
if(raydium_ode_element[i].ttl==0)
raydium_ode_element_delete(i,1);
else
raydium_ode_element[i].ttl--;
}
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state &&
raydium_ode_element[i].nid>=0 &&
raydium_ode_element[i].distant)
raydium_ode_network_element_trajectory_correct(i);
for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
if(raydium_ode_joint[i].state)
raydium_ode_joint_break(i);
}
void raydium_ode_time_change(GLfloat perc)
{
raydium_timecall_freq_change(raydium_ode_timecall,(RAYDIUM_ODE_PHYSICS_FREQ*perc)/100.f);
raydium_particle_time_factor=perc/100.f;
raydium_object_anim_time_factor=perc/100.f;
}
void raydium_ode_internal_particle_genetator_deleted_callback(int gen)
{
int i;
for(i=1;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state &&
raydium_ode_element[i].particle==gen)
raydium_ode_element[i].particle=-1;
}
void raydium_ode_element_particle(int elem, char *filename)
{
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot attach particle generator: invalid index or name");
return;
}
raydium_ode_element[elem].particle=raydium_particle_generator_load(filename,raydium_ode_element[elem].name);
memset(raydium_ode_element[elem].particle_offset,0,sizeof(dReal)*3);
}
void raydium_ode_element_particle_name(char *elem, char *filename)
{
raydium_ode_element_particle(raydium_ode_element_find(elem),filename);
}
void raydium_ode_element_particle_offset(int elem, char *filename, dReal *offset)
{
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot attach particle generator (offset): invalid index or name");
return;
}
raydium_ode_element[elem].particle=raydium_particle_generator_load(filename,raydium_ode_element[elem].name);
memcpy(raydium_ode_element[elem].particle_offset,offset,sizeof(dReal)*3);
}
void raydium_ode_element_particle_offset_name(char *elem, char *filename, dReal *offset)
{
raydium_ode_element_particle_offset(raydium_ode_element_find(elem),filename,offset);
}
void raydium_ode_element_particle_offset_name_3f(char *elem, char *filename, dReal ox, dReal oy, dReal oz)
{
dReal offset[3];
offset[0]=ox;
offset[1]=oy;
offset[2]=oz;
raydium_ode_element_particle_offset(raydium_ode_element_find(elem),filename,offset);
}
// no offset provided yet for particle_point ... (easy to write, indeed)
void raydium_ode_element_particle_point(int elem, char *filename)
{
char n[RAYDIUM_MAX_NAME_LEN];
int p;
dReal *pos;
if(!raydium_ode_element_isvalid(elem))
{
raydium_log("ODE: Error: Cannot attach particle genrator: invalid index or name");
return;
}
raydium_particle_name_auto(raydium_ode_element[elem].name,n);
p=raydium_particle_generator_load(filename,n);
if(p<0) return;
pos=raydium_ode_element_pos_get(elem);
raydium_particle_generator_move(p,pos);
}
void raydium_ode_element_particle_point_name(char *elem, char *filename)
{
raydium_ode_element_particle_point(raydium_ode_element_find(elem),filename);
}
// smooth camera related functions
void raydium_camera_smooth_path_to_element(char *path, int element, GLfloat path_step, GLfloat smooth_step)
{
GLfloat x,y,z,zoom,roll;
GLfloat *pos;
pos=raydium_ode_element_pos_get(element);
if(raydium_camera_smooth_path(path,path_step,&x,&y,&z,&zoom,&roll)==-1)
raydium_log("camera path error with '%s'",path);
raydium_camera_smooth(x,y,z,pos[1],-pos[2],pos[0],zoom,roll,smooth_step);
}
void raydium_camera_smooth_path_to_element_name(char *path,char *element, GLfloat path_step, GLfloat smooth_step)
{
raydium_camera_smooth_path_to_element(path,raydium_ode_element_find(element),path_step,smooth_step);
}
void raydium_camera_smooth_element_to_path_offset(int element, GLfloat offset_x, GLfloat offset_y, GLfloat offset_z, char *path, GLfloat path_step, GLfloat smooth_step)
{
GLfloat x,y,z,zoom,roll;
GLfloat *pos;
GLfloat offset[3];
pos=raydium_ode_element_pos_get(element);
if(raydium_camera_smooth_path(path,path_step,&x,&y,&z,&zoom,&roll)==-1)
raydium_log("camera path error with '%s'",path);
// static elems are not supported
dBodyVectorToWorld(raydium_ode_element[element].body,offset_x,offset_y,offset_z,offset);
raydium_camera_smooth(pos[0]+offset[0],pos[1]+offset[1],pos[2]+offset[2],y,-z,x,zoom,roll,smooth_step);
}
void raydium_camera_smooth_element_to_path_offset_name(char *element, GLfloat offset_x, GLfloat offset_y, GLfloat offset_z, char *path, GLfloat path_step, GLfloat smooth_step)
{
raydium_camera_smooth_element_to_path_offset(raydium_ode_element_find(element),offset_x,offset_y,offset_z,path,path_step,smooth_step);
}
void raydium_camera_smooth_element_to_path_name(char *element, char *path, GLfloat path_step, GLfloat smooth_step)
{
raydium_camera_smooth_element_to_path_offset(raydium_ode_element_find(element),0,0,0,path,path_step,smooth_step);
}
// This function is provided "for fun" only. Not all effects are dumped:
// Missing : shadows, forced colors, before/after callbacks,
// fixed elements, ...
// Some code is pasted from file.c (and this is BAD ! :)
int raydium_ode_capture_3d(char *filename)
{
int i,j,k;
FILE *fp;
dVector3 res,norm;
char text[256];
char sprt[256];
fp=raydium_file_fopen(filename,"wt");
if(!fp)
{
raydium_log("ERROR : failed to create 3D capture file '%s'",filename);
return 0;
}
fprintf(fp,"1\n");
for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
if(raydium_ode_element[i].state && raydium_ode_element[i].mesh>=0)
{
int end;
dBodyID body;
dReal *pos;
dQuaternion rot;
body=dBodyCreate(raydium_ode_world);
pos=raydium_ode_element_pos_get(i);
raydium_ode_element_rotq_get(i,rot);
dBodySetPosition(body,pos[0],pos[1],pos[2]);
dBodySetQuaternion(body,rot);
k=raydium_ode_element[i].mesh;
// should prepare "ode" instance here, too ...
if(raydium_object_anims[k]>0)
end=raydium_object_start[k]+raydium_object_anim_len[k];
else
end=raydium_object_end[k];
for(j=raydium_object_start[k];j<end;j++)
{
if(raydium_vertex_texture_multi[j])
{
sprintf(text,"%s;%f|%f|%s",raydium_texture_name[raydium_vertex_texture[j]],
raydium_vertex_texture_multi_u[j],
raydium_vertex_texture_multi_v[j],
raydium_texture_name[raydium_vertex_texture_multi[j]]);
}
else
strcpy(text,raydium_texture_name[raydium_vertex_texture[j]]);
dBodyGetRelPointPos(body,
raydium_vertex_x[j],
raydium_vertex_y[j],
raydium_vertex_z[j],
res);
dBodyVectorToWorld(body,
raydium_vertex_normal_visu_x[j],
raydium_vertex_normal_visu_y[j],
raydium_vertex_normal_visu_z[j],
norm);
fprintf(fp,"%f %f %f %f %f %f %f %f %s\n",
res[0],
res[1],
res[2],
norm[0],
norm[1],
norm[2],
raydium_vertex_texture_u[j],
raydium_vertex_texture_v[j],
text);
}
dBodyDestroy(body);
// raydium_ode_element[i].mesh
}
fclose(fp);
raydium_log("3D capture saved to '%s'",filename);
sprintf(sprt,"%s.sprt",filename);
raydium_particle_state_dump(sprt);
return 1;
}
int raydium_ode_orphans_check(void)
{
int i,j,k,n;
dGeomID g;
int cpt=0;
for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
if(raydium_ode_object[i].state)
{
n=dSpaceGetNumGeoms(raydium_ode_object[i].group);
if(!n) continue;
for(j=0;j<n;j++)
{
g=dSpaceGetGeom(raydium_ode_object[i].group,j);
for(k=0;k<RAYDIUM_ODE_MAX_ELEMENTS;k++)
if(raydium_ode_element[k].state)
if(raydium_ode_element[k].geom==g)
break;
if(k==RAYDIUM_ODE_MAX_ELEMENTS)
{
cpt++;
raydium_log("new orphan in '%s'",raydium_ode_object[i].name);
}
}
}
return cpt;
}
#include "ode_net.c"