diff options
author | sanine <sanine.not@pm.me> | 2022-10-01 20:59:36 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-10-01 20:59:36 -0500 |
commit | c5fc66ee58f2c60f2d226868bb1cf5b91badaf53 (patch) | |
tree | 277dd280daf10bf77013236b8edfa5f88708c7e0 /libs/ode-0.16.1/ode/src/ode.cpp | |
parent | 1cf9cc3408af7008451f9133fb95af66a9697d15 (diff) |
add ode
Diffstat (limited to 'libs/ode-0.16.1/ode/src/ode.cpp')
-rw-r--r-- | libs/ode-0.16.1/ode/src/ode.cpp | 2325 |
1 files changed, 2325 insertions, 0 deletions
diff --git a/libs/ode-0.16.1/ode/src/ode.cpp b/libs/ode-0.16.1/ode/src/ode.cpp new file mode 100644 index 0000000..40bfd6a --- /dev/null +++ b/libs/ode-0.16.1/ode/src/ode.cpp @@ -0,0 +1,2325 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" +#endif + +// this source file is mostly concerned with the data structures, not the +// numerics. + +#include <ode/ode.h> +#include <ode/memory.h> +#include <ode/error.h> +#include "config.h" +#include "matrix.h" +#include "odemath.h" +#include "objects.h" +#include "joints/joints.h" +#include "step.h" +#include "quickstep.h" +#include "util.h" +#include "odetls.h" + +// misc defines +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// utility + + +// add an object `obj' to the list who's head pointer is pointed to by `first'. + +void addObjectToList (dObject *obj, dObject **first) +{ + obj->next = *first; + obj->tome = first; + if (*first) (*first)->tome = &obj->next; + (*first) = obj; +} + + +// remove the object from the linked list + +static inline void removeObjectFromList (dObject *obj) +{ + if (obj->next) obj->next->tome = obj->tome; + *(obj->tome) = obj->next; + // safeguard + obj->next = NULL; + obj->tome = NULL; +} + + +// remove the joint from neighbour lists of all connected bodies + +static void removeJointReferencesFromAttachedBodies (dxJoint *j) +{ + for (int i=0; i<2; i++) { + dxBody *body = j->node[i].body; + if (body) { + dxJointNode *n = body->firstjoint; + dxJointNode *last = NULL; + while (n) { + if (n->joint == j) { + if (last) last->next = n->next; + else body->firstjoint = n->next; + break; + } + last = n; + n = n->next; + } + } + } + j->node[0].body = NULL; + j->node[0].next = NULL; + j->node[1].body = NULL; + j->node[1].next = NULL; +} + +//**************************************************************************** +// debugging + +// see if an object list loops on itself (if so, it's bad). + +static int listHasLoops (dObject *first) +{ + if (first==0 || first->next==0) return 0; + dObject *a=first,*b=first->next; + int skip=0; + while (b) { + if (a==b) return 1; + b = b->next; + if (skip) a = a->next; + skip ^= 1; + } + return 0; +} + + +// check the validity of the world data structures + +static int g_world_check_tag_generator = 0; + +static inline int generateWorldCheckTag() +{ + // Atomicity is not necessary here + return ++g_world_check_tag_generator; +} + +static void checkWorld (dxWorld *w) +{ + dxBody *b; + dxJoint *j; + + // check there are no loops + if (listHasLoops (w->firstbody)) dDebug (0,"body list has loops"); + if (listHasLoops (w->firstjoint)) dDebug (0,"joint list has loops"); + + // check lists are well formed (check `tome' pointers) + for (b=w->firstbody; b; b=(dxBody*)b->next) { + if (b->next && b->next->tome != &b->next) + dDebug (0,"bad tome pointer in body list"); + } + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->next && j->next->tome != &j->next) + dDebug (0,"bad tome pointer in joint list"); + } + + // check counts + int n = 0; + for (b=w->firstbody; b; b=(dxBody*)b->next) n++; + if (w->nb != n) dDebug (0,"body count incorrect"); + n = 0; + for (j=w->firstjoint; j; j=(dxJoint*)j->next) n++; + if (w->nj != n) dDebug (0,"joint count incorrect"); + + // set all tag values to a known value + int count = generateWorldCheckTag(); + for (b=w->firstbody; b; b=(dxBody*)b->next) b->tag = count; + for (j=w->firstjoint; j; j=(dxJoint*)j->next) j->tag = count; + + // check all body/joint world pointers are ok + for (b=w->firstbody; b; b=(dxBody*)b->next) if (b->world != w) + dDebug (0,"bad world pointer in body list"); + for (j=w->firstjoint; j; j=(dxJoint*)j->next) if (j->world != w) + dDebug (0,"bad world pointer in joint list"); + + /* + // check for half-connected joints - actually now these are valid + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->node[0].body || j->node[1].body) { + if (!(j->node[0].body && j->node[1].body)) + dDebug (0,"half connected joint found"); + } + } + */ + + // check that every joint node appears in the joint lists of both bodies it + // attaches + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + for (int i=0; i<2; i++) { + if (j->node[i].body) { + int ok = 0; + for (dxJointNode *n=j->node[i].body->firstjoint; n; n=n->next) { + if (n->joint == j) ok = 1; + } + if (ok==0) dDebug (0,"joint not in joint list of attached body"); + } + } + } + + // check all body joint lists (correct body ptrs) + for (b=w->firstbody; b; b=(dxBody*)b->next) { + for (dxJointNode *n=b->firstjoint; n; n=n->next) { + if (&n->joint->node[0] == n) { + if (n->joint->node[1].body != b) + dDebug (0,"bad body pointer in joint node of body list (1)"); + } + else { + if (n->joint->node[0].body != b) + dDebug (0,"bad body pointer in joint node of body list (2)"); + } + if (n->joint->tag != count) dDebug (0,"bad joint node pointer in body"); + } + } + + // check all body pointers in joints, check they are distinct + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->node[0].body && (j->node[0].body == j->node[1].body)) + dDebug (0,"non-distinct body pointers in joint"); + if ((j->node[0].body && j->node[0].body->tag != count) || + (j->node[1].body && j->node[1].body->tag != count)) + dDebug (0,"bad body pointer in joint"); + } +} + + +void dWorldCheck (dxWorld *w) +{ + checkWorld (w); +} + +//**************************************************************************** +// body + +dxBody::dxBody(dxWorld *w) : +dObject(w) +{ + +} + + +dxWorld* dBodyGetWorld (dxBody * b) +{ + dAASSERT (b); + return b->world; +} + +dxBody *dBodyCreate (dxWorld *w) +{ + dAASSERT (w); + dxBody *b = new dxBody(w); + b->firstjoint = NULL; + b->flags = 0; + b->geom = NULL; + b->average_lvel_buffer = NULL; + b->average_avel_buffer = NULL; + dMassSetParameters (&b->mass,1,0,0,0,1,1,1,0,0,0); + dSetZero (b->invI,4*3); + b->invI[0] = 1; + b->invI[5] = 1; + b->invI[10] = 1; + b->invMass = 1; + dSetZero (b->posr.pos,4); + dSetZero (b->q,4); + b->q[0] = 1; + dRSetIdentity (b->posr.R); + dSetZero (b->lvel,4); + dSetZero (b->avel,4); + dSetZero (b->facc,4); + dSetZero (b->tacc,4); + dSetZero (b->finite_rot_axis,4); + addObjectToList (b,(dObject **) &w->firstbody); + w->nb++; + + // set auto-disable parameters + b->average_avel_buffer = b->average_lvel_buffer = NULL; // no buffer at beginning + dBodySetAutoDisableDefaults (b); // must do this after adding to world + b->adis_stepsleft = b->adis.idle_steps; + b->adis_timeleft = b->adis.idle_time; + b->average_counter = 0; + b->average_ready = 0; // average buffer not filled on the beginning + dBodySetAutoDisableAverageSamplesCount(b, b->adis.average_samples); + + b->moved_callback = NULL; + + dBodySetDampingDefaults(b); // must do this after adding to world + + b->flags |= w->body_flags & dxBodyMaxAngularSpeed; + b->max_angular_speed = w->max_angular_speed; + + b->flags |= dxBodyGyroscopic; + + return b; +} + + +void dBodyDestroy (dxBody *b) +{ + dAASSERT (b); + + // all geoms that link to this body must be notified that the body is about + // to disappear. note that the call to dGeomSetBody(geom,0) will result in + // dGeomGetBodyNext() returning 0 for the body, so we must get the next body + // before setting the body to 0. + dxGeom *next_geom = NULL; + for (dxGeom *geom = b->geom; geom; geom = next_geom) { + next_geom = dGeomGetBodyNext (geom); + dGeomSetBody (geom,0); + } + + // detach all neighbouring joints, then delete this body. + dxJointNode *n = b->firstjoint; + while (n) { + // sneaky trick to speed up removal of joint references (black magic) + n->joint->node[(n == n->joint->node)].body = NULL; + + dxJointNode *next = n->next; + n->next = NULL; + removeJointReferencesFromAttachedBodies (n->joint); + n = next; + } + removeObjectFromList (b); + b->world->nb--; + + // delete the average buffers + if(b->average_lvel_buffer) + { + delete[] (b->average_lvel_buffer); + b->average_lvel_buffer = NULL; + } + if(b->average_avel_buffer) + { + delete[] (b->average_avel_buffer); + b->average_avel_buffer = NULL; + } + + delete b; +} + + +void dBodySetData (dBodyID b, void *data) +{ + dAASSERT (b); + b->userdata = data; +} + + +void *dBodyGetData (dBodyID b) +{ + dAASSERT (b); + return b->userdata; +} + + +void dBodySetPosition (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->posr.pos[0] = x; + b->posr.pos[1] = y; + b->posr.pos[2] = z; + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + + +void dBodySetRotation (dBodyID b, const dMatrix3 R) +{ + dAASSERT (b && R); + + memcpy(b->posr.R, R, sizeof(dMatrix3)); + + bool bOrthogonalizeResult = dxOrthogonalizeR(b->posr.R); + dAVERIFY(bOrthogonalizeResult); + + dRtoQ (R, b->q); + dNormalize4 (b->q); + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) { + dGeomMoved (geom); + } +} + + +void dBodySetQuaternion (dBodyID b, const dQuaternion q) +{ + dAASSERT (b && q); + b->q[0] = q[0]; + b->q[1] = q[1]; + b->q[2] = q[2]; + b->q[3] = q[3]; + dNormalize4 (b->q); + dQtoR (b->q,b->posr.R); + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + + +void dBodySetLinearVel (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->lvel[0] = x; + b->lvel[1] = y; + b->lvel[2] = z; +} + + +void dBodySetAngularVel (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->avel[0] = x; + b->avel[1] = y; + b->avel[2] = z; +} + + +const dReal * dBodyGetPosition (dBodyID b) +{ + dAASSERT (b); + return b->posr.pos; +} + + +void dBodyCopyPosition (dBodyID b, dVector3 pos) +{ + dAASSERT (b); + dReal* src = b->posr.pos; + pos[0] = src[0]; + pos[1] = src[1]; + pos[2] = src[2]; +} + + +const dReal * dBodyGetRotation (dBodyID b) +{ + dAASSERT (b); + return b->posr.R; +} + + +void dBodyCopyRotation (dBodyID b, dMatrix3 R) +{ + dAASSERT (b); + const dReal* src = b->posr.R; + R[0] = src[0]; + R[1] = src[1]; + R[2] = src[2]; + R[3] = src[3]; + R[4] = src[4]; + R[5] = src[5]; + R[6] = src[6]; + R[7] = src[7]; + R[8] = src[8]; + R[9] = src[9]; + R[10] = src[10]; + R[11] = src[11]; +} + + +const dReal * dBodyGetQuaternion (dBodyID b) +{ + dAASSERT (b); + return b->q; +} + + +void dBodyCopyQuaternion (dBodyID b, dQuaternion quat) +{ + dAASSERT (b); + dReal* src = b->q; + quat[0] = src[0]; + quat[1] = src[1]; + quat[2] = src[2]; + quat[3] = src[3]; +} + + +const dReal * dBodyGetLinearVel (dBodyID b) +{ + dAASSERT (b); + return b->lvel; +} + + +const dReal * dBodyGetAngularVel (dBodyID b) +{ + dAASSERT (b); + return b->avel; +} + + +void dBodySetMass (dBodyID b, const dMass *mass) +{ + dAASSERT (b && mass ); + dIASSERT(dMassCheck(mass)); + + // The centre of mass must be at the origin. + // Use dMassTranslate( mass, -mass->c[0], -mass->c[1], -mass->c[2] ) to correct it. + dUASSERT( fabs( mass->c[0] ) <= dEpsilon && + fabs( mass->c[1] ) <= dEpsilon && + fabs( mass->c[2] ) <= dEpsilon, "The centre of mass must be at the origin." ); + + b->mass = *mass; + if (dInvertPDMatrix (b->mass.I,b->invI,3,NULL)==0) { + dDEBUGMSG ("inertia must be positive definite!"); + dRSetIdentity (b->invI); + } + b->invMass = dRecip(b->mass.mass); +} + + +void dBodyGetMass (dBodyID b, dMass *mass) +{ + dAASSERT (b && mass); + *mass = b->mass; +} + + +void dBodyAddForce (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + b->facc[0] += fx; + b->facc[1] += fy; + b->facc[2] += fz; +} + + +void dBodyAddTorque (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + b->tacc[0] += fx; + b->tacc[1] += fy; + b->tacc[2] += fz; +} + + +void dBodyAddRelForce (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + dVector3 t1,t2; + t1[0] = fx; + t1[1] = fy; + t1[2] = fz; + t1[3] = 0; + dMultiply0_331 (t2,b->posr.R,t1); + b->facc[0] += t2[0]; + b->facc[1] += t2[1]; + b->facc[2] += t2[2]; +} + + +void dBodyAddRelTorque (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + dVector3 t1,t2; + t1[0] = fx; + t1[1] = fy; + t1[2] = fz; + t1[3] = 0; + dMultiply0_331 (t2,b->posr.R,t1); + b->tacc[0] += t2[0]; + b->tacc[1] += t2[1]; + b->tacc[2] += t2[2]; +} + + +void dBodyAddForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + b->facc[0] += fx; + b->facc[1] += fy; + b->facc[2] += fz; + dVector3 f,q; + f[0] = fx; + f[1] = fy; + f[2] = fz; + q[0] = px - b->posr.pos[0]; + q[1] = py - b->posr.pos[1]; + q[2] = pz - b->posr.pos[2]; + dAddVectorCross3(b->tacc,q,f); +} + + +void dBodyAddForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + dVector3 prel,f,p; + f[0] = fx; + f[1] = fy; + f[2] = fz; + f[3] = 0; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMultiply0_331 (p,b->posr.R,prel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dAddVectorCross3(b->tacc,p,f); +} + + +void dBodyAddRelForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + dVector3 frel,f; + frel[0] = fx; + frel[1] = fy; + frel[2] = fz; + frel[3] = 0; + dMultiply0_331 (f,b->posr.R,frel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dVector3 q; + q[0] = px - b->posr.pos[0]; + q[1] = py - b->posr.pos[1]; + q[2] = pz - b->posr.pos[2]; + dAddVectorCross3(b->tacc,q,f); +} + + +void dBodyAddRelForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + dVector3 frel,prel,f,p; + frel[0] = fx; + frel[1] = fy; + frel[2] = fz; + frel[3] = 0; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMultiply0_331 (f,b->posr.R,frel); + dMultiply0_331 (p,b->posr.R,prel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dAddVectorCross3(b->tacc,p,f); +} + + +const dReal * dBodyGetForce (dBodyID b) +{ + dAASSERT (b); + return b->facc; +} + + +const dReal * dBodyGetTorque (dBodyID b) +{ + dAASSERT (b); + return b->tacc; +} + + +void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->facc[0] = x; + b->facc[1] = y; + b->facc[2] = z; +} + + +void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->tacc[0] = x; + b->tacc[1] = y; + b->tacc[2] = z; +} + + +void dBodyGetRelPointPos (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMultiply0_331 (p,b->posr.R,prel); + result[0] = p[0] + b->posr.pos[0]; + result[1] = p[1] + b->posr.pos[1]; + result[2] = p[2] + b->posr.pos[2]; +} + + +void dBodyGetRelPointVel (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMultiply0_331 (p,b->posr.R,prel); + result[0] = b->lvel[0]; + result[1] = b->lvel[1]; + result[2] = b->lvel[2]; + dAddVectorCross3(result,b->avel,p); +} + + +void dBodyGetPointVel (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px - b->posr.pos[0]; + p[1] = py - b->posr.pos[1]; + p[2] = pz - b->posr.pos[2]; + p[3] = 0; + result[0] = b->lvel[0]; + result[1] = b->lvel[1]; + result[2] = b->lvel[2]; + dAddVectorCross3(result,b->avel,p); +} + + +void dBodyGetPosRelPoint (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel; + prel[0] = px - b->posr.pos[0]; + prel[1] = py - b->posr.pos[1]; + prel[2] = pz - b->posr.pos[2]; + prel[3] = 0; + dMultiply1_331 (result,b->posr.R,prel); +} + + +void dBodyVectorToWorld (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px; + p[1] = py; + p[2] = pz; + p[3] = 0; + dMultiply0_331 (result,b->posr.R,p); +} + + +void dBodyVectorFromWorld (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px; + p[1] = py; + p[2] = pz; + p[3] = 0; + dMultiply1_331 (result,b->posr.R,p); +} + + +void dBodySetFiniteRotationMode (dBodyID b, int mode) +{ + dAASSERT (b); + b->flags &= ~(dxBodyFlagFiniteRotation | dxBodyFlagFiniteRotationAxis); + if (mode) { + b->flags |= dxBodyFlagFiniteRotation; + if (b->finite_rot_axis[0] != 0 || b->finite_rot_axis[1] != 0 || + b->finite_rot_axis[2] != 0) { + b->flags |= dxBodyFlagFiniteRotationAxis; + } + } +} + + +void dBodySetFiniteRotationAxis (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->finite_rot_axis[0] = x; + b->finite_rot_axis[1] = y; + b->finite_rot_axis[2] = z; + if (x != 0 || y != 0 || z != 0) { + dNormalize3 (b->finite_rot_axis); + b->flags |= dxBodyFlagFiniteRotationAxis; + } + else { + b->flags &= ~dxBodyFlagFiniteRotationAxis; + } +} + + +int dBodyGetFiniteRotationMode (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyFlagFiniteRotation) != 0); +} + + +void dBodyGetFiniteRotationAxis (dBodyID b, dVector3 result) +{ + dAASSERT (b); + result[0] = b->finite_rot_axis[0]; + result[1] = b->finite_rot_axis[1]; + result[2] = b->finite_rot_axis[2]; +} + + +int dBodyGetNumJoints (dBodyID b) +{ + dAASSERT (b); + int count=0; + for (dxJointNode *n=b->firstjoint; n; n=n->next, count++); + return count; +} + + +dJointID dBodyGetJoint (dBodyID b, int index) +{ + dAASSERT (b); + int i=0; + for (dxJointNode *n=b->firstjoint; n; n=n->next, i++) { + if (i == index) return n->joint; + } + return 0; +} + +void dBodySetDynamic (dBodyID b) +{ + dAASSERT (b); + + dBodySetMass(b,&b->mass); +} + +void dBodySetKinematic (dBodyID b) +{ + dAASSERT (b); + dSetZero (b->invI,4*3); + b->invMass = 0; +} + +int dBodyIsKinematic (dBodyID b) +{ + dAASSERT (b); + return b->invMass == 0; +} + +void dBodyEnable (dBodyID b) +{ + dAASSERT (b); + b->flags &= ~dxBodyDisabled; + b->adis_stepsleft = b->adis.idle_steps; + b->adis_timeleft = b->adis.idle_time; + // no code for average-processing needed here +} + + +void dBodyDisable (dBodyID b) +{ + dAASSERT (b); + b->flags |= dxBodyDisabled; +} + + +int dBodyIsEnabled (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyDisabled) == 0); +} + + +void dBodySetGravityMode (dBodyID b, int mode) +{ + dAASSERT (b); + if (mode) b->flags &= ~dxBodyNoGravity; + else b->flags |= dxBodyNoGravity; +} + + +int dBodyGetGravityMode (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyNoGravity) == 0); +} + + +// body auto-disable functions + +dReal dBodyGetAutoDisableLinearThreshold (dBodyID b) +{ + dAASSERT(b); + return dSqrt (b->adis.linear_average_threshold); +} + + +void dBodySetAutoDisableLinearThreshold (dBodyID b, dReal linear_average_threshold) +{ + dAASSERT(b); + b->adis.linear_average_threshold = linear_average_threshold * linear_average_threshold; +} + + +dReal dBodyGetAutoDisableAngularThreshold (dBodyID b) +{ + dAASSERT(b); + return dSqrt (b->adis.angular_average_threshold); +} + + +void dBodySetAutoDisableAngularThreshold (dBodyID b, dReal angular_average_threshold) +{ + dAASSERT(b); + b->adis.angular_average_threshold = angular_average_threshold * angular_average_threshold; +} + + +int dBodyGetAutoDisableAverageSamplesCount (dBodyID b) +{ + dAASSERT(b); + return b->adis.average_samples; +} + + +void dBodySetAutoDisableAverageSamplesCount (dBodyID b, unsigned int average_samples_count) +{ + dAASSERT(b); + b->adis.average_samples = average_samples_count; + // update the average buffers + if(b->average_lvel_buffer) + { + delete[] b->average_lvel_buffer; + b->average_lvel_buffer = NULL; + } + if(b->average_avel_buffer) + { + delete[] b->average_avel_buffer; + b->average_avel_buffer = NULL; + } + if(b->adis.average_samples > 0) + { + b->average_lvel_buffer = new dVector3[b->adis.average_samples]; + b->average_avel_buffer = new dVector3[b->adis.average_samples]; + } + else + { + b->average_lvel_buffer = NULL; + b->average_avel_buffer = NULL; + } + // new buffer is empty + b->average_counter = 0; + b->average_ready = 0; +} + + +int dBodyGetAutoDisableSteps (dBodyID b) +{ + dAASSERT(b); + return b->adis.idle_steps; +} + + +void dBodySetAutoDisableSteps (dBodyID b, int steps) +{ + dAASSERT(b); + b->adis.idle_steps = steps; +} + + +dReal dBodyGetAutoDisableTime (dBodyID b) +{ + dAASSERT(b); + return b->adis.idle_time; +} + + +void dBodySetAutoDisableTime (dBodyID b, dReal time) +{ + dAASSERT(b); + b->adis.idle_time = time; +} + + +int dBodyGetAutoDisableFlag (dBodyID b) +{ + dAASSERT(b); + return ((b->flags & dxBodyAutoDisable) != 0); +} + + +void dBodySetAutoDisableFlag (dBodyID b, int do_auto_disable) +{ + dAASSERT(b); + if (!do_auto_disable) + { + b->flags &= ~dxBodyAutoDisable; + // (mg) we should also reset the IsDisabled state to correspond to the DoDisabling flag + b->flags &= ~dxBodyDisabled; + b->adis.idle_steps = dWorldGetAutoDisableSteps(b->world); + b->adis.idle_time = dWorldGetAutoDisableTime(b->world); + // resetting the average calculations too + dBodySetAutoDisableAverageSamplesCount(b, dWorldGetAutoDisableAverageSamplesCount(b->world) ); + } + else + { + b->flags |= dxBodyAutoDisable; + } +} + + +void dBodySetAutoDisableDefaults (dBodyID b) +{ + dAASSERT(b); + dWorldID w = b->world; + dAASSERT(w); + b->adis = w->adis; + dBodySetAutoDisableFlag (b, w->body_flags & dxBodyAutoDisable); +} + + +// body damping functions + +dReal dBodyGetLinearDamping(dBodyID b) +{ + dAASSERT(b); + return b->dampingp.linear_scale; +} + +void dBodySetLinearDamping(dBodyID b, dReal scale) +{ + dAASSERT(b); + if (scale) + b->flags |= dxBodyLinearDamping; + else + b->flags &= ~dxBodyLinearDamping; + b->dampingp.linear_scale = scale; +} + +dReal dBodyGetAngularDamping(dBodyID b) +{ + dAASSERT(b); + return b->dampingp.angular_scale; +} + +void dBodySetAngularDamping(dBodyID b, dReal scale) +{ + dAASSERT(b); + if (scale) + b->flags |= dxBodyAngularDamping; + else + b->flags &= ~dxBodyAngularDamping; + b->dampingp.angular_scale = scale; +} + +void dBodySetDamping(dBodyID b, dReal linear_scale, dReal angular_scale) +{ + dAASSERT(b); + dBodySetLinearDamping(b, linear_scale); + dBodySetAngularDamping(b, angular_scale); +} + +dReal dBodyGetLinearDampingThreshold(dBodyID b) +{ + dAASSERT(b); + return dSqrt(b->dampingp.linear_threshold); +} + +void dBodySetLinearDampingThreshold(dBodyID b, dReal threshold) +{ + dAASSERT(b); + b->dampingp.linear_threshold = threshold*threshold; +} + + +dReal dBodyGetAngularDampingThreshold(dBodyID b) +{ + dAASSERT(b); + return dSqrt(b->dampingp.angular_threshold); +} + +void dBodySetAngularDampingThreshold(dBodyID b, dReal threshold) +{ + dAASSERT(b); + b->dampingp.angular_threshold = threshold*threshold; +} + +void dBodySetDampingDefaults(dBodyID b) +{ + dAASSERT(b); + dWorldID w = b->world; + dAASSERT(w); + b->dampingp = w->dampingp; + const unsigned mask = dxBodyLinearDamping | dxBodyAngularDamping; + b->flags &= ~mask; // zero them + b->flags |= w->body_flags & mask; +} + +dReal dBodyGetMaxAngularSpeed(dBodyID b) +{ + dAASSERT(b); + return b->max_angular_speed; +} + +void dBodySetMaxAngularSpeed(dBodyID b, dReal max_speed) +{ + dAASSERT(b); + if (max_speed < dInfinity) + b->flags |= dxBodyMaxAngularSpeed; + else + b->flags &= ~dxBodyMaxAngularSpeed; + b->max_angular_speed = max_speed; +} + +void dBodySetMovedCallback(dBodyID b, void (*callback)(dBodyID)) +{ + dAASSERT(b); + b->moved_callback = callback; +} + + +dGeomID dBodyGetFirstGeom(dBodyID b) +{ + dAASSERT(b); + return b->geom; +} + + +dGeomID dBodyGetNextGeom(dGeomID geom) +{ + dAASSERT(geom); + return dGeomGetBodyNext(geom); +} + + +int dBodyGetGyroscopicMode(dBodyID b) +{ + dAASSERT(b); + return b->flags & dxBodyGyroscopic; +} + +void dBodySetGyroscopicMode(dBodyID b, int enabled) +{ + dAASSERT(b); + if (enabled) + b->flags |= dxBodyGyroscopic; + else + b->flags &= ~dxBodyGyroscopic; +} + + + +//**************************************************************************** +// joints + + + +template<class T> +dxJoint* createJoint(dWorldID w, dJointGroupID group) +{ + dxJoint *j; + if (group) { + j = group->alloc<T>(w); + } else { + j = new T(w); + } + return j; +} + + +dxJoint * dJointCreateBall (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointBall>(w,group); +} + + +dxJoint * dJointCreateHinge (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointHinge>(w,group); +} + + +dxJoint * dJointCreateSlider (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointSlider>(w,group); +} + + +dxJoint * dJointCreateContact (dWorldID w, dJointGroupID group, + const dContact *c) +{ + dAASSERT (w && c); + dxJointContact *j = (dxJointContact *) + createJoint<dxJointContact> (w,group); + j->contact = *c; + return j; +} + + +dxJoint * dJointCreateHinge2 (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointHinge2> (w,group); +} + + +dxJoint * dJointCreateUniversal (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointUniversal> (w,group); +} + +dxJoint * dJointCreatePR (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointPR> (w,group); +} + +dxJoint * dJointCreatePU (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointPU> (w,group); +} + +dxJoint * dJointCreatePiston (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointPiston> (w,group); +} + +dxJoint * dJointCreateFixed (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointFixed> (w,group); +} + + +dxJoint * dJointCreateNull (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointNull> (w,group); +} + + +dxJoint * dJointCreateAMotor (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointAMotor> (w,group); +} + +dxJoint * dJointCreateLMotor (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointLMotor> (w,group); +} + +dxJoint * dJointCreatePlane2D (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointPlane2D> (w,group); +} + +dxJoint * dJointCreateDBall (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointDBall> (w,group); +} + +dxJoint * dJointCreateDHinge (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointDHinge> (w,group); +} + + +dxJoint * dJointCreateTransmission (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint<dxJointTransmission> (w,group); +} + +static void FinalizeAndDestroyJointInstance(dxJoint *j, bool delete_it) +{ + // if any group joints have their world pointer set to 0, their world was + // previously destroyed. no special handling is required for these joints. + if (j->world != NULL) { + removeJointReferencesFromAttachedBodies (j); + removeObjectFromList (j); + j->world->nj--; + } + if (delete_it) { + delete j; + } else { + j->~dxJoint(); + } +} + +void dJointDestroy (dxJoint *j) +{ + dAASSERT (j); + if (!(j->flags & dJOINT_INGROUP)) { + FinalizeAndDestroyJointInstance(j, true); + } +} + + +dJointGroupID dJointGroupCreate (int /*max_size*/) +{ + // not any more ... dUASSERT (max_size > 0,"max size must be > 0"); + dxJointGroup *group = new dxJointGroup(); + return group; +} + + +void dJointGroupDestroy (dJointGroupID group) +{ + dAASSERT (group); + dJointGroupEmpty (group); + delete group; +} + +void dJointGroupEmpty (dJointGroupID group) +{ + dAASSERT (group); + + const sizeint num_joints = group->getJointCount(); + if (num_joints != 0) { + // Local array is used since ALLOCA leads to mysterious NULL values in first array element and crashes under VS2005 :) + const sizeint max_stack_jlist_size = 1024; + dxJoint *stack_jlist[max_stack_jlist_size]; + + const sizeint jlist_size = num_joints * sizeof(dxJoint*); + dxJoint **jlist = num_joints <= max_stack_jlist_size ? stack_jlist : (dxJoint **)dAlloc(jlist_size); + + if (jlist != NULL) { + // the joints in this group are detached starting from the most recently + // added (at the top of the stack). this helps ensure that the various + // linked lists are not traversed too much, as the joints will hopefully + // be at the start of those lists. + sizeint num_exported = group->exportJoints(jlist); + dIVERIFY(num_exported == num_joints); + + for (sizeint i = num_joints; i != 0; ) { + --i; + dxJoint *j = jlist[i]; + FinalizeAndDestroyJointInstance(j, false); + } + } else { + // ...else if there is no memory, go on detaching the way it is possible + sizeint joint_bytes; + for (dxJoint *j = (dxJoint *)group->beginEnum(); j != NULL; j = (dxJoint *)group->continueEnum(joint_bytes)) { + joint_bytes = j->size(); // Get size before object is destroyed! + FinalizeAndDestroyJointInstance(j, false); + } + } + + group->freeAll(); + + if (jlist != stack_jlist && jlist != NULL) { + dFree(jlist, jlist_size); + } + } +} + + +int dJointGetNumBodies(dxJoint *joint) +{ + // check arguments + dUASSERT (joint,"bad joint argument"); + + if ( !joint->node[0].body ) + return 0; + else if ( !joint->node[1].body ) + return 1; + else + return 2; +} + + +void dJointAttach (dxJoint *joint, dxBody *body1, dxBody *body2) +{ + // check arguments + dUASSERT (joint,"bad joint argument"); + dUASSERT (body1 == NULL || body1 != body2, "can't have body1==body2"); + dxWorld *world = joint->world; + dUASSERT ( (body1 == NULL || body1->world == world) && + (body2 == NULL || body2->world == world), + "joint and bodies must be in same world"); + + // check if the joint can not be attached to just one body + dUASSERT (!((joint->flags & dJOINT_TWOBODIES) && + ((body1 != NULL) != (body2 != NULL))), + "joint can not be attached to just one body"); + + // remove any existing body attachments + if (joint->node[0].body != NULL || joint->node[1].body != NULL) { + removeJointReferencesFromAttachedBodies (joint); + } + + // if a body is zero, make sure that it is body2, so 0 --> node[1].body + if (body1 == NULL) { + body1 = body2; + body2 = NULL; + joint->flags |= dJOINT_REVERSE; + } + else { + joint->flags &= (~dJOINT_REVERSE); + } + + // attach to new bodies + joint->node[0].body = body1; + joint->node[1].body = body2; + + if (body1 != NULL) { + joint->node[1].next = body1->firstjoint; + body1->firstjoint = &joint->node[1]; + } + else { + joint->node[1].next = NULL; + } + + if (body2 != NULL) { + joint->node[0].next = body2->firstjoint; + body2->firstjoint = &joint->node[0]; + } + else { + joint->node[0].next = NULL; + } + + // Since the bodies are now set. + // Calculate the values depending on the bodies. + // Only need to calculate relative value if a body exist + if (body1 != NULL || body2 != NULL) { + joint->setRelativeValues(); + } +} + +void dJointEnable (dxJoint *joint) +{ + dAASSERT (joint); + joint->flags &= ~dJOINT_DISABLED; +} + +void dJointDisable (dxJoint *joint) +{ + dAASSERT (joint); + joint->flags |= dJOINT_DISABLED; +} + +int dJointIsEnabled (dxJoint *joint) +{ + dAASSERT (joint); + return (joint->flags & dJOINT_DISABLED) == 0; +} + +void dJointSetData (dxJoint *joint, void *data) +{ + dAASSERT (joint); + joint->userdata = data; +} + + +void *dJointGetData (dxJoint *joint) +{ + dAASSERT (joint); + return joint->userdata; +} + + +dJointType dJointGetType (dxJoint *joint) +{ + dAASSERT (joint); + return joint->type(); +} + + +dBodyID dJointGetBody (dxJoint *joint, int index) +{ + dAASSERT (joint); + if (index == 0 || index == 1) { + if (joint->flags & dJOINT_REVERSE) return joint->node[1-index].body; + else return joint->node[index].body; + } + else return 0; +} + + +void dJointSetFeedback (dxJoint *joint, dJointFeedback *f) +{ + dAASSERT (joint); + joint->feedback = f; +} + + +dJointFeedback *dJointGetFeedback (dxJoint *joint) +{ + dAASSERT (joint); + return joint->feedback; +} + + + +dJointID dConnectingJoint (dBodyID in_b1, dBodyID in_b2) +{ + dAASSERT (in_b1 || in_b2); + + dBodyID b1, b2; + + if (in_b1 == 0) { + b1 = in_b2; + b2 = in_b1; + } + else { + b1 = in_b1; + b2 = in_b2; + } + + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) return n->joint; + } + + return 0; +} + + + +int dConnectingJointList (dBodyID in_b1, dBodyID in_b2, dJointID* out_list) +{ + dAASSERT (in_b1 || in_b2); + + + dBodyID b1, b2; + + if (in_b1 == 0) { + b1 = in_b2; + b2 = in_b1; + } + else { + b1 = in_b1; + b2 = in_b2; + } + + // look through b1's neighbour list for b2 + int numConnectingJoints = 0; + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) + out_list[numConnectingJoints++] = n->joint; + } + + return numConnectingJoints; +} + + +int dAreConnected (dBodyID b1, dBodyID b2) +{ + dAASSERT (b1/* && b2*/); // b2 can be NULL to test for connection to environment + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) return 1; + } + return 0; +} + + +int dAreConnectedExcluding (dBodyID b1, dBodyID b2, int joint_type) +{ + dAASSERT (b1/* && b2*/); // b2 can be NULL to test for connection to environment + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (dJointGetType (n->joint) != joint_type && n->body == b2) return 1; + } + return 0; +} + +//**************************************************************************** +// world + +dxWorld * dWorldCreate() +{ + dxWorld *w = new dxWorld(); + + return w; +} + + +void dWorldDestroy (dxWorld *w) +{ + // delete all bodies and joints + dAASSERT (w); + dxBody *nextb, *b = w->firstbody; + while (b) { + nextb = (dxBody*) b->next; + dBodyDestroy(b); // calling here dBodyDestroy for correct destroying! (i.e. the average buffers) + b = nextb; + } + + dxJoint *nextj, *j = w->firstjoint; + while (j) { + nextj = (dxJoint*)j->next; + if (j->flags & dJOINT_INGROUP) { + // the joint is part of a group, so "deactivate" it instead + j->world = NULL; + j->node[0].body = NULL; + j->node[0].next = NULL; + j->node[1].body = NULL; + j->node[1].next = NULL; + dMessage (0,"warning: destroying world containing grouped joints"); + } + else { + // TODO: shouldn't we call dJointDestroy()? + sizeint sz = j->size(); + j->~dxJoint(); + dFree (j,sz); + } + j = nextj; + } + + delete w; +} + + +void dWorldSetData (dWorldID w, void *data) +{ + dAASSERT (w); + w->userdata = data; +} + + +void* dWorldGetData (dWorldID w) +{ + dAASSERT (w); + return w->userdata; +} + + +void dWorldSetGravity (dWorldID w, dReal x, dReal y, dReal z) +{ + dAASSERT (w); + w->gravity[0] = x; + w->gravity[1] = y; + w->gravity[2] = z; +} + + +void dWorldGetGravity (dWorldID w, dVector3 g) +{ + dAASSERT (w); + g[0] = w->gravity[0]; + g[1] = w->gravity[1]; + g[2] = w->gravity[2]; +} + + +void dWorldSetERP (dWorldID w, dReal erp) +{ + dAASSERT (w); + w->global_erp = erp; +} + + +dReal dWorldGetERP (dWorldID w) +{ + dAASSERT (w); + return w->global_erp; +} + + +void dWorldSetCFM (dWorldID w, dReal cfm) +{ + dAASSERT (w); + w->global_cfm = cfm; +} + + +dReal dWorldGetCFM (dWorldID w) +{ + dAASSERT (w); + return w->global_cfm; +} + + +void dWorldSetStepIslandsProcessingMaxThreadCount(dWorldID w, unsigned count) +{ + dAASSERT (w); + w->islands_max_threads = count; +} + +unsigned dWorldGetStepIslandsProcessingMaxThreadCount(dWorldID w) +{ + dAASSERT (w); + return w->islands_max_threads; +} + +int dWorldUseSharedWorkingMemory(dWorldID w, dWorldID from_world) +{ + dUASSERT (w,"bad world argument"); + + bool result = false; + + if (from_world) + { + dUASSERT (!w->wmem, "world does already have working memory allocated"); // Prevent replacement of one memory object with another to avoid cases when smaller buffer replaces a larger one or memory manager changes. + + dxStepWorkingMemory *wmem = AllocateOnDemand(from_world->wmem); + + if (wmem) + { + // Even though there is an assertion check on entry still release existing + // memory object for extra safety. + if (w->wmem) + { + w->wmem->Release(); + w->wmem = NULL; + } + + wmem->Addref(); + w->wmem = wmem; + + result = true; + } + } + else + { + dxStepWorkingMemory *wmem = w->wmem; + + if (wmem) + { + wmem->Release(); + w->wmem = NULL; + } + + result = true; + } + + return result; +} + +void dWorldCleanupWorkingMemory(dWorldID w) +{ + dUASSERT (w,"bad world argument"); + + dxStepWorkingMemory *wmem = w->wmem; + + if (wmem) + { + wmem->CleanupMemory(); + } +} + +int dWorldSetStepMemoryReservationPolicy(dWorldID w, const dWorldStepReserveInfo *policyinfo) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (!policyinfo || (policyinfo->struct_size >= sizeof(*policyinfo) && policyinfo->reserve_factor >= 1.0f), "Bad policy info"); + + bool result = false; + + dxStepWorkingMemory *wmem = policyinfo ? AllocateOnDemand(w->wmem) : w->wmem; + + if (wmem) + { + if (policyinfo) + { + wmem->SetMemoryReserveInfo(policyinfo->reserve_factor, policyinfo->reserve_minimum); + result = wmem->GetMemoryReserveInfo() != NULL; + } + else + { + wmem->ResetMemoryReserveInfoToDefault(); + result = true; + } + } + else if (!policyinfo) + { + result = true; + } + + return result; +} + +int dWorldSetStepMemoryManager(dWorldID w, const dWorldStepMemoryFunctionsInfo *memfuncs) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (!memfuncs || memfuncs->struct_size >= sizeof(*memfuncs), "Bad memory functions info"); + + bool result = false; + + dxStepWorkingMemory *wmem = memfuncs ? AllocateOnDemand(w->wmem) : w->wmem; + + if (wmem) + { + if (memfuncs) + { + wmem->SetMemoryManager(memfuncs->alloc_block, memfuncs->shrink_block, memfuncs->free_block); + result = wmem->GetMemoryManager() != NULL; + } + else + { + wmem->ResetMemoryManagerToDefault(); + result = true; + } + } + else if (!memfuncs) + { + result = true; + } + + return result; +} + +void dWorldSetStepThreadingImplementation(dWorldID w, + const dxThreadingFunctionsInfo *functions_info, dThreadingImplementationID threading_impl) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (!functions_info || functions_info->struct_size >= sizeof(*functions_info), "Bad threading functions info"); + +#if dTHREADING_INTF_DISABLED + dUASSERT(functions_info == NULL && threading_impl == NULL, "Threading interface is not available"); +#else + w->assignThreadingImpl(functions_info, threading_impl); +#endif +} + + +int dWorldStep (dWorldID w, dReal stepsize) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (stepsize > 0,"stepsize must be > 0"); + + bool result = false; + + dxWorldProcessIslandsInfo islandsinfo; + if (dxReallocateWorldProcessContext (w, islandsinfo, stepsize, &dxEstimateStepMemoryRequirements)) + { + if (dxProcessIslands (w, islandsinfo, stepsize, &dxStepIsland, &dxEstimateStepMaxCallCount)) + { + result = true; + } + } + + return result; +} + +int dWorldQuickStep (dWorldID w, dReal stepsize) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (stepsize > 0,"stepsize must be > 0"); + + bool result = false; + + dxWorldProcessIslandsInfo islandsinfo; + if (dxReallocateWorldProcessContext (w, islandsinfo, stepsize, &dxEstimateQuickStepMemoryRequirements)) + { + if (dxProcessIslands (w, islandsinfo, stepsize, &dxQuickStepIsland, &dxEstimateQuickStepMaxCallCount)) + { + result = true; + } + } + + return result; +} + + +void dWorldImpulseToForce (dWorldID w, dReal stepsize, + dReal ix, dReal iy, dReal iz, + dVector3 force) +{ + dAASSERT (w); + stepsize = dRecip(stepsize); + force[0] = stepsize * ix; + force[1] = stepsize * iy; + force[2] = stepsize * iz; + // @@@ force[3] = 0; +} + + +// world auto-disable functions + +dReal dWorldGetAutoDisableLinearThreshold (dWorldID w) +{ + dAASSERT(w); + return dSqrt (w->adis.linear_average_threshold); +} + + +void dWorldSetAutoDisableLinearThreshold (dWorldID w, dReal linear_average_threshold) +{ + dAASSERT(w); + w->adis.linear_average_threshold = linear_average_threshold * linear_average_threshold; +} + + +dReal dWorldGetAutoDisableAngularThreshold (dWorldID w) +{ + dAASSERT(w); + return dSqrt (w->adis.angular_average_threshold); +} + + +void dWorldSetAutoDisableAngularThreshold (dWorldID w, dReal angular_average_threshold) +{ + dAASSERT(w); + w->adis.angular_average_threshold = angular_average_threshold * angular_average_threshold; +} + + +int dWorldGetAutoDisableAverageSamplesCount (dWorldID w) +{ + dAASSERT(w); + return w->adis.average_samples; +} + + +void dWorldSetAutoDisableAverageSamplesCount (dWorldID w, unsigned int average_samples_count) +{ + dAASSERT(w); + w->adis.average_samples = average_samples_count; +} + + +int dWorldGetAutoDisableSteps (dWorldID w) +{ + dAASSERT(w); + return w->adis.idle_steps; +} + + +void dWorldSetAutoDisableSteps (dWorldID w, int steps) +{ + dAASSERT(w); + w->adis.idle_steps = steps; +} + + +dReal dWorldGetAutoDisableTime (dWorldID w) +{ + dAASSERT(w); + return w->adis.idle_time; +} + + +void dWorldSetAutoDisableTime (dWorldID w, dReal time) +{ + dAASSERT(w); + w->adis.idle_time = time; +} + + +int dWorldGetAutoDisableFlag (dWorldID w) +{ + dAASSERT(w); + return w->body_flags & dxBodyAutoDisable; +} + + +void dWorldSetAutoDisableFlag (dWorldID w, int do_auto_disable) +{ + dAASSERT(w); + if (do_auto_disable) + w->body_flags |= dxBodyAutoDisable; + else + w->body_flags &= ~dxBodyAutoDisable; +} + + +// world damping functions + +dReal dWorldGetLinearDampingThreshold(dWorldID w) +{ + dAASSERT(w); + return dSqrt(w->dampingp.linear_threshold); +} + +void dWorldSetLinearDampingThreshold(dWorldID w, dReal threshold) +{ + dAASSERT(w); + w->dampingp.linear_threshold = threshold*threshold; +} + +dReal dWorldGetAngularDampingThreshold(dWorldID w) +{ + dAASSERT(w); + return dSqrt(w->dampingp.angular_threshold); +} + +void dWorldSetAngularDampingThreshold(dWorldID w, dReal threshold) +{ + dAASSERT(w); + w->dampingp.angular_threshold = threshold*threshold; +} + +dReal dWorldGetLinearDamping(dWorldID w) +{ + dAASSERT(w); + return w->dampingp.linear_scale; +} + +void dWorldSetLinearDamping(dWorldID w, dReal scale) +{ + dAASSERT(w); + if (scale) + w->body_flags |= dxBodyLinearDamping; + else + w->body_flags &= ~dxBodyLinearDamping; + w->dampingp.linear_scale = scale; +} + +dReal dWorldGetAngularDamping(dWorldID w) +{ + dAASSERT(w); + return w->dampingp.angular_scale; +} + +void dWorldSetAngularDamping(dWorldID w, dReal scale) +{ + dAASSERT(w); + if (scale) + w->body_flags |= dxBodyAngularDamping; + else + w->body_flags &= ~dxBodyAngularDamping; + w->dampingp.angular_scale = scale; +} + +void dWorldSetDamping(dWorldID w, dReal linear_scale, dReal angular_scale) +{ + dAASSERT(w); + dWorldSetLinearDamping(w, linear_scale); + dWorldSetAngularDamping(w, angular_scale); +} + +dReal dWorldGetMaxAngularSpeed(dWorldID w) +{ + dAASSERT(w); + return w->max_angular_speed; +} + +void dWorldSetMaxAngularSpeed(dWorldID w, dReal max_speed) +{ + dAASSERT(w); + if (max_speed < dInfinity) + w->body_flags |= dxBodyMaxAngularSpeed; + else + w->body_flags &= ~dxBodyMaxAngularSpeed; + w->max_angular_speed = max_speed; +} + + +void dWorldSetQuickStepNumIterations (dWorldID w, int num) +{ + dAASSERT(w); + w->qs.num_iterations = num; +} + + +int dWorldGetQuickStepNumIterations (dWorldID w) +{ + dAASSERT(w); + return w->qs.num_iterations; +} + + +void dWorldSetQuickStepW (dWorldID w, dReal param) +{ + dAASSERT(w); + w->qs.w = param; +} + + +dReal dWorldGetQuickStepW (dWorldID w) +{ + dAASSERT(w); + return w->qs.w; +} + + +void dWorldSetContactMaxCorrectingVel (dWorldID w, dReal vel) +{ + dAASSERT(w); + w->contactp.max_vel = vel; +} + + +dReal dWorldGetContactMaxCorrectingVel (dWorldID w) +{ + dAASSERT(w); + return w->contactp.max_vel; +} + + +void dWorldSetContactSurfaceLayer (dWorldID w, dReal depth) +{ + dAASSERT(w); + w->contactp.min_depth = depth; +} + + +dReal dWorldGetContactSurfaceLayer (dWorldID w) +{ + dAASSERT(w); + return w->contactp.min_depth; +} + +//**************************************************************************** +// testing + +#define NUM 100 + +#define DO(x) + + +extern "C" void dTestDataStructures() +{ + int i; + DO(printf ("testDynamicsStuff()\n")); + + dBodyID body [NUM]; + int nb = 0; + dJointID joint [NUM]; + int nj = 0; + + for (i=0; i<NUM; i++) body[i] = NULL; + for (i=0; i<NUM; i++) joint[i] = NULL; + + DO(printf ("creating world\n")); + dWorldID w = dWorldCreate(); + checkWorld (w); + + for (;;) { + if (nb < NUM && dRandReal() > 0.5) { + DO(printf ("creating body\n")); + body[nb] = dBodyCreate (w); + DO(printf ("\t--> %p\n",body[nb])); + nb++; + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + if (nj < NUM && nb > 2 && dRandReal() > 0.5) { + dBodyID b1 = body [dRand() % nb]; + dBodyID b2 = body [dRand() % nb]; + if (b1 != b2) { + DO(printf ("creating joint, attaching to %p,%p\n",b1,b2)); + joint[nj] = dJointCreateBall (w,0); + DO(printf ("\t-->%p\n",joint[nj])); + checkWorld (w); + dJointAttach (joint[nj],b1,b2); + nj++; + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + if (nj > 0 && nb > 2 && dRandReal() > 0.5) { + dBodyID b1 = body [dRand() % nb]; + dBodyID b2 = body [dRand() % nb]; + if (b1 != b2) { + int k = dRand() % nj; + DO(printf ("reattaching joint %p\n",joint[k])); + dJointAttach (joint[k],b1,b2); + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + if (nb > 0 && dRandReal() > 0.5) { + int k = dRand() % nb; + DO(printf ("destroying body %p\n",body[k])); + dBodyDestroy (body[k]); + checkWorld (w); + for (; k < (NUM-1); k++) body[k] = body[k+1]; + nb--; + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + if (nj > 0 && dRandReal() > 0.5) { + int k = dRand() % nj; + DO(printf ("destroying joint %p\n",joint[k])); + dJointDestroy (joint[k]); + checkWorld (w); + for (; k < (NUM-1); k++) joint[k] = joint[k+1]; + nj--; + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + + /* + printf ("creating world\n"); + dWorldID w = dWorldCreate(); + checkWorld (w); + printf ("creating body\n"); + dBodyID b1 = dBodyCreate (w); + checkWorld (w); + printf ("creating body\n"); + dBodyID b2 = dBodyCreate (w); + checkWorld (w); + printf ("creating joint\n"); + dJointID j = dJointCreateBall (w); + checkWorld (w); + printf ("attaching joint\n"); + dJointAttach (j,b1,b2); + checkWorld (w); + printf ("destroying joint\n"); + dJointDestroy (j); + checkWorld (w); + printf ("destroying body\n"); + dBodyDestroy (b1); + checkWorld (w); + printf ("destroying body\n"); + dBodyDestroy (b2); + checkWorld (w); + printf ("destroying world\n"); + dWorldDestroy (w); + */ +} + +//**************************************************************************** +// configuration +#if 1 +#define REGISTER_EXTENSION( __a ) #__a " " +#else +#define REGISTER_EXTENSION( __a ) "__a " +#endif +static const char ode_configuration[] = "ODE " + +// EXTENSION LIST BEGIN +//********************************** + +#ifdef dNODEBUG +REGISTER_EXTENSION( ODE_EXT_no_debug ) +#endif // dNODEBUG + +#if dTRIMESH_ENABLED +REGISTER_EXTENSION( ODE_EXT_trimesh ) + +// tri-mesh extensions +#if dTRIMESH_OPCODE +REGISTER_EXTENSION( ODE_EXT_opcode ) + +// opcode extensions +#if dTRIMESH_16BIT_INDICES +REGISTER_EXTENSION( ODE_OPC_16bit_indices ) +#endif + +#if !dTRIMESH_OPCODE_USE_OLD_TRIMESH_TRIMESH_COLLIDER +REGISTER_EXTENSION( ODE_OPC_new_collider ) +#endif + +#endif // dTRIMESH_OPCODE + +#if dTRIMESH_GIMPACT +REGISTER_EXTENSION( ODE_EXT_gimpact ) + +// gimpact extensions +#endif + +#endif // dTRIMESH_ENABLED + +#if dTLS_ENABLED +REGISTER_EXTENSION( ODE_EXT_mt_collisions ) +#endif // dTLS_ENABLED + +#if !dTHREADING_INTF_DISABLED +REGISTER_EXTENSION( ODE_EXT_threading ) + +#if dBUILTIN_THREADING_IMPL_ENABLED +REGISTER_EXTENSION( ODE_THR_builtin_impl ) +#endif // #if dBUILTIN_THREADING_IMPL_ENABLED +#endif // #if !dTHREADING_INTF_DISABLED + +//********************************** +// EXTENSION LIST END + +// These tokens are mutually exclusive, and always present +#ifdef dSINGLE +"ODE_single_precision" +#else +"ODE_double_precision" +#endif // dDOUBLE + +; // END + +const char* dGetConfiguration (void) +{ + return ode_configuration; +} + + +// Helper to check for a feature of ODE +int dCheckConfiguration( const char* extension ) +{ + const char *start; + char *where, *terminator; + + /* Feature names should not have spaces. */ + where = (char*)strchr(extension, ' '); + if ( where || *extension == '\0') + return 1; + + const char* config = dGetConfiguration(); + + const sizeint ext_length = strlen(extension); + + /* It takes a bit of care to be fool-proof. Don't be fooled by sub-strings, etc. */ + start = config; + for ( ; ; ) + { + where = (char*)strstr((const char *) start, extension); + if (!where) + break; + + terminator = where + ext_length; + + if ( (where == start || *(where - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0') ) + { + return 1; + } + + start = terminator; + } + + return 0; +} + + +// Local Variables: +// c-basic-offset:4 +// End: |