The following is example code that would be used to determine collision in a complicated envirnment. In this case there is a large array of pendulums disrupted by a falling wood block.
This is a simulation for only one set of objects, you can imagine how complex this would get if you had an entire environment to provide reactons for.

/*
Copyright MathEngine PLC 2000
www.mathengine.com
$Name: AUTO_TEMP_MeTKMakeRelease_1_299 $
$Id: ManyPendulums.c,v 1.16 2000/08/31 13:52:45 lyndonh Exp $
*/
/*
This example shows the collision detection, Dynamics Event Manager
and Kea Dynamics working on a complicated environment.
*/
#pragma warning( disable : 4305 )
#include "MePrecision.h"
#include "McdFrame.h"
#include "McdPrimitives.h"
#include "McdDtBridge.h"
#include "Mdt.h"
#include "MeMath.h"
#include "MeViewer.h"
extern struct MeMemoryAPI MeMemoryAPIMalloc;
struct MeMemoryOptions opts;
/* Global declarations */
/* Number of pendulums down one side of grid */
#define NSIDE 20
#define NPENDULUMS (NSIDE * NSIDE)
#define penRadius (MeReal)0.5
#define penHeight (MeReal)2.0
#define penJoint (MeReal)5.0
#define penDensity (MeReal)8.0
#define penSpacing (MeReal)3.0
/* MeReal penRadius = (MeReal)0.5; */
/* MeReal penHeight = (MeReal)2.0; */
/* MeReal penJoint = (MeReal)5.0; */
/* MeReal penDensity = (MeReal)8.0; */
/* MeReal penSpacing = (MeReal)3.0; */
MeReal thingDensity = 1.0;
MeVector3 thingDim = {3.8, 3.8, 3.8};
MeVector3 thingStart = {0.8, 20.0, 0.01};
/* color of pendulums in the corners */
MeVector3 topLeftColor = {1, 0, 0};
MeVector3 topRightColor = {1, 1, 0};
MeVector3 bottomLeftColor = {0, 1, 0};
MeVector3 bottomRightColor = {0, 0, 1};
/* Force applied to the box to drag it around */
MeReal thingForce = 1000;
/* World for the Dynamics Toolkit simulation */
MdtWorldID world;
/* Collision */
McdDtBridge *cdHandler;
McdSpaceID space;
/* Kea solver workspace */
void *KeaMemoryArea;
/* Physics representations */
MdtBodyID thing;
MdtBodyID pen[NPENDULUMS];
MdtBSJointID joint[NPENDULUMS];
/* Graphical representations */
RGraphic *groundG;
RGraphic *thingG;
RGraphic *penG[NPENDULUMS];
RGraphic *lineG[NPENDULUMS];
/* Collision reps */
McdModelID groundCM;
McdModelID thingCM;
McdModelID penCM[NPENDULUMS];
McdGeometryID plane_prim, box_prim, pen_prim[NPENDULUMS];
MeReal gravity[3] = { 0, -10, 0 };
/* Render context */
RRender *rc;
/* Timestep size */
MeReal step = (MeReal)(0.04);
MeReal groundTransform[4][4] =
{
{1, 0, 0, 0},
{0, 0, -1, 0},
{0, 1, 0, 0},
{0, -1, 0, 1}
};
MeReal groundRenderTransform[16] =
{
1, 0, 0, 0,
0, 0, -1, 0,
0, 1, 0, 0,
0, -1.5, 0, 1
};
/* Functions to add forces to block to drag it around. */
void increaseXForce(void)
{
MdtBodyEnable(thing);
MdtBodyAddForce(thing, thingForce, 0, 0);
}
void decreaseXForce(void)
{
MdtBodyEnable(thing);
MdtBodyAddForce(thing, -thingForce, 0, 0);
}
void increaseZForce(void)
{
MdtBodyEnable(thing);
MdtBodyAddForce(thing, 0, 0, thingForce);
}
void decreaseZForce(void)
{
MdtBodyEnable(thing);
MdtBodyAddForce(thing, 0, 0, -thingForce);
}
void ThingCameraTrack()
{
MeVector3 pos;
MdtBodyGetPosition(thing, pos);
rc->m_cameraLookAt[0] = pos[0];
rc->m_cameraLookAt[1] = pos[1];
rc->m_cameraLookAt[2] = pos[2];
RUpdateCamera();
}
/*
Tick() is a callback function called from the renderer's main loop
to evolve the world by 'step' seconds
*/
void tick(RRender * rc)
{
/*
These timer calls are for the OpenGL performance bar.
*/
RStopTimer(kRRender);
/* Update collision */
RStartTimer(kRCollision);
McdDtBridgeUpdateAllFreezeFlags(space);
McdPairHandlerUpdate();
RStopTimer(kRCollision);
/* Update dynamics */
RStartTimer(kRDynamics);
MdtWorldStep(world, step);
RStopTimer(kRDynamics);
RStartTimer(kRRender);
ThingCameraTrack();
}
/*
Reset boxes and pendulums to initial positions
*/
void reset(void)
{
int i,j;
/* Offset to start making pendulums from */
MeReal start = (NSIDE-1) * -penSpacing * (MeReal)0.5;
MdtBodySetPosition(thing, thingStart[0], thingStart[1], thingStart[2]);
MdtBodySetQuaternion(thing, 1, 0, 0, 0);
MdtBodySetLinearVelocity(thing, 0, 0, 0);
MdtBodySetAngularVelocity(thing, 0, 0, 0);
MdtBodyEnable(thing);
for (i = 0; i < NSIDE; i++)
{
for(j=0; j < NSIDE; j++)
{
MdtBodySetPosition(pen[(i*NSIDE)+j], start + i * penSpacing, penHeight, start + j * penSpacing);
MdtBodySetQuaternion(pen[(i*NSIDE)+j], 1, 0, 0, 0);
MdtBodySetLinearVelocity(pen[(i*NSIDE)+j], 0, 0, 0);
MdtBodySetAngularVelocity(pen[(i*NSIDE)+j], 0, 0, 0);
MdtBodyEnable(pen[(i*NSIDE)+j]);
}
}
}
void cleanup(void)
{
int i;
McdGeometryDestroy(plane_prim);
McdModelDestroy(groundCM);
McdGeometryDestroy(box_prim);
McdModelDestroy(thingCM);
for (i = 0; i < NPENDULUMS; i++)
{
McdGeometryDestroy(pen_prim[i]);
McdModelDestroy(penCM[i]);
}
McdSpaceDestroy(space);
McdDtBridgeDestroy(cdHandler);
McdDtBridgeTerm();
McdTerm();
MdtWorldDestroy(world);
free(KeaMemoryArea);
RDeleteRenderContext(rc);
}
/*
Main Routine
*/
int main(int argc, const char **argv)
{
const RRenderType render = RParseRenderType(&argc, &argv);
#ifndef PS2
static char *help[] =
{
"Left Mouse Drag - move camera",
" Enter - reset",
" w,a,s,d - drag block around"
};
#else
static char *help[] =
{
" Start - reset",
" Directional pad - drag block around"
};
#endif
const int helpNum = sizeof (help) / sizeof (help[0]);
int i, j, k, id;
float color[3];
short material1;
MeReal mass, start;
MeMatrix3 I;
AcmeReal lineStart[3] = { 0.0, penRadius, 0.0};
AcmeReal lineEnd[3] = { 0.0, penJoint - penHeight, 0.0};
MeVector3 tempColorTop, tempColorBottom;
MeReal propI, propJ;
MdtContactParamsID props;
if (render == kRD3D) {
MeInfo(0,"Direct3D not supported for this example.\n");
exit(1);
}
MeMemorySetDefaults(&opts);
(*MeMemoryAPI.setOptions)(&opts);
/*
Initialise dynamics
*/
KeaMemoryArea = malloc(2000000);
world = MdtWorldCreate(NPENDULUMS + 1, NPENDULUMS + 100, KeaMemoryArea, 2000000);
MdtWorldSetGravity(world, gravity[0], gravity[1], gravity[2]);
/*
In this demo, a lot of objects are stationary a lot of the time.
To speed things up we tell Mdt to AutoDisable objects when they
come to rest. Disabled MdtBodies are automatically re-Enabled
when an Enabled body contacts them.
*/
MdtWorldSetDEMMode(world, MdtDEMModePartitionAutoDisable);
/*
THING:
*/
thing = MdtBodyCreate(world);
mass = thingDensity * thingDim[0] * thingDim[1] * thingDim[2];
MdtMakeInertiaTensorBox(mass, thingDim[0], thingDim[1], thingDim[2], I);
MdtBodySetMass(thing, mass);
MdtBodySetInertiaTensor(thing, I);
/*
Add a little (angular)velocity damping
*/
MdtBodySetAngularVelocityDamping(thing, 0.03);
MdtBodySetLinearVelocityDamping(thing, 0.02);
/*
PENDULUMS:
*/
mass = PI * penRadius * penRadius * penDensity;
MdtMakeInertiaTensorSphere(mass, penRadius, I);
for (i = 0; i < NPENDULUMS; i++)
{
pen[i] = MdtBodyCreate(world);
MdtBodySetMass(pen[i], mass);
MdtBodySetInertiaTensor(pen[i], I);
MdtBodySetLinearVelocityDamping(pen[i], (MeReal)(0.2));
MdtBodySetAngularVelocityDamping(pen[i], (MeReal)(0.1));
}
/* reset pendulums to correct positions.. */
reset();
/* offset to start making pendulums from */
start = (NSIDE-1) * -penSpacing * (MeReal)0.5;
/* now make all the joints */
for (i = 0; i < NSIDE; i++)
{
for(j=0; j < NSIDE; j++)
{
joint[(i*NSIDE)+j] = MdtBSJointCreate(world, pen[(i*NSIDE)+j], 0);
MdtBSJointSetPosition(joint[(i*NSIDE)+j], start + i * penSpacing, penJoint, start + j * penSpacing);
MdtBSJointEnable(joint[(i*NSIDE)+j]);
}
}
/*
Collision detection
*/
McdInit(McdPrimitivesGetTypeCount());
McdPrimitivesRegisterTypes();
McdPrimitivesRegisterInteractions();
McdDtBridgeInit(0);
/* max objects and pairs */
space = McdSpaceAxisSortCreate(McdAllAxes, NPENDULUMS + 2, 150);
McdPairHandlerRegisterSpace(space);
cdHandler = McdDtBridgeCreate();
/* max pairs at a time */
McdDtBridgeSetPairListMaxCount(cdHandler, 150);
/*
Set parameters for contacts.
*/
material1 = McdDtBridgeGetDefaultMaterialID();
props = McdDtBridgeGetContactParams(material1, material1);
MdtContactParamsSetType(props, MdtContactTypeFriction2D);
MdtContactParamsSetFriction(props, 2.0);
MdtContactParamsSetRestitution(props, 0.3);
/*
Only use 3 contacts per pair.
*/
id = McdIntersectGetDefaultRequestID();
McdIntersectRequestSetContactMaxCount(id, id, 3);
plane_prim = McdPlaneCreate();
groundCM = McdModelCreate(plane_prim);
McdSpaceInsertModel(space, groundCM);
McdDtBridgeSetBody(cdHandler, groundCM, 0);
McdModelSetTransformPtr(groundCM, groundTransform);
McdModelFreezeInSpace(groundCM);
box_prim = McdBoxCreate(thingDim[0],
thingDim[1], thingDim[2]);
thingCM = McdModelCreate(box_prim);
McdDtBridgeSetBody(cdHandler, thingCM, thing);
McdSpaceInsertModel(space, thingCM);
for (i = 0; i < NPENDULUMS; i++)
{
pen_prim[i] = McdBoxCreate(2 * penRadius,
2 * penRadius, 2 * penRadius);
penCM[i] = McdModelCreate(pen_prim[i]);
McdDtBridgeSetBody(cdHandler, penCM[i], pen[i]);
McdSpaceInsertModel(space, penCM[i]);
}
McdSpaceBuild(space);
/*
Initialise rendering attributes
*/
rc = RNewRenderContext(render, kRQualitySmooth);
rc->m_cameraOffset = 30;
RUpdateCamera();
/*
GROUND:
*/
color[0] = 0.0f;
color[1] = 0.75f;
color[2] = 0.1f;
groundG =
RCreateCube(rc, 84.0f, 84.0f, 0.5f, color,
groundRenderTransform);
#ifndef PS2
RSetTexture(groundG, "checkerboard");
#endif
color[0] = 0.1;
color[1] = 0.1;
color[2] = 0.8;
thingG =
RCreateCube(rc, thingDim[0], thingDim[1], thingDim[2],
color, MdtBodyGetTransformPtr(thing));
#ifndef PS2
RSetTexture(thingG, "wood1");
#endif
/* make graphics (pretty colours) */
for (i = 0; i < NSIDE; i++)
{
for(j=0; j < NSIDE; j++)
{
propI = (MeReal)i/((MeReal)NSIDE-1);
propJ = (MeReal)j/((MeReal)NSIDE-1);
for(k=0; k<3; k++)
{
tempColorTop[k] =
(propI * (topRightColor[k] - topLeftColor[k])) + topLeftColor[k];
tempColorBottom[k] =
(propI * (bottomRightColor[k] - bottomLeftColor[k])) + bottomLeftColor[k];
color[k] =
(propJ * (tempColorTop[k] - tempColorBottom[k])) + tempColorBottom[k];
}
penG[(i*NSIDE)+j] =
RCreateCube(rc, 2*penRadius, 2*penRadius, 2*penRadius,
color, MdtBodyGetTransformPtr(pen[(i*NSIDE)+j]));
lineG[(i*NSIDE)+j] =
RCreateLine(rc, lineStart, lineEnd,
color, MdtBodyGetTransformPtr(pen[(i*NSIDE)+j]));
}
}
/*
KEYS:
*/
#ifndef PS2
RUseKey('w', increaseZForce);
RUseKey('s', decreaseZForce);
RUseKey('a', decreaseXForce);
RUseKey('d', increaseXForce);
RUseKey('\r', reset);
#else
RUsePadKey(PADLup, increaseZForce);
RUsePadKey(PADLdown, decreaseZForce);
RUsePadKey(PADLright, decreaseXForce);
RUsePadKey(PADLleft, increaseXForce);
RUsePadKey(PADstart, reset);
#endif
/* selects a fixed-width font */
RSetOGLFont(3);
RCreateUserHelp(help, helpNum);
rc->m_title = "ManyPendulums example";
/*
Cleanup after simulation.
*/
#ifndef PS2
atexit(cleanup);
#endif
/*
Run the Simulation.
*/
/*
RRun() executes the main loop.
Pseudocode: while no exit-request { Handle user input call Tick() to
evolve the simulation and update graphic transforms Draw graphics }
*/
RRun(rc, tick);
return 0;
}