Starting out with the basic code from the first tutorial we now expand on the
base code. To show the joints in action we will need
to increase the number of objects by one, and then create a new joint group and
a joint ID. So our global variables for ODE, which are the same for all three
types of joints, now look like this:
MATRIX GeomMatrix; dWorldID World; dSpaceID Space; MyObject Object[2]; // two geom objects dJointGroupID contactgroup; dJointGroupID jointgroup; // contact group for the new joint dJointID Joint; // the joint ID
We now move on to the initialization routine for ODE which I called InitODE. I will list the whole function again, but I'll just comment on the new code required to make the joints.
void InitODE()
{
World = dWorldCreate();
Space = dHashSpaceCreate(0);
contactgroup = dJointGroupCreate(0);
// As well as the contact group for collisions we need to create a new joint group and
// assign its ID to jointgroup
jointgroup = dJointGroupCreate(0);
dCreatePlane(Space, 0, 1, 0, 0);
dWorldSetGravity(World, 0, -1.0, 0);
dWorldSetCFM(World, 1e-5);
dWorldSetERP(World, 0.2);
dWorldSetContactMaxCorrectingVel(World, 0.9);
dWorldSetContactSurfaceLayer(World, 0);
dWorldSetAutoDisableFlag(World, 1);
dReal sides[3];
dMass m;
dMatrix3 R;
VECTOR tempVect(0.0, 0.0, 0.0);
sides[0] = 2.0;
sides[1] = 2.0;
sides[2] = 2.0;
// Here we instantiate the two bodies we will be using
Object[0].Body = dBodyCreate(World);
Object[1].Body = dBodyCreate(World);
// Set up for body 1. Nothing much has changed here, we are now dealing with an array
// instead of a single object and I have changed its initial position and rotated the
// object 45 degrees around the Y axis using dRFromEulerAngles.
dBodySetPosition(Object[0].Body, -1.4142, 1.0, -5.0);
dBodySetLinearVel(Object[0].Body, tempVect.x, tempVect.y, tempVect.z);
dBodySetData(Object[0].Body, (void*)i);
dRFromEulerAngles(R, 0.0, pi / 4, 0.0);
dBodySetRotation(Object[0].Body, R);
dMassSetBox(&m, DENSITY, sides[0], sides[1], sides[2]);
Object[0].Geom[0] = dCreateBox(Space, sides[0], sides[1], sides[2]);
dGeomSetBody(Object[0].Geom[0], Object[0].Body);
dBodySetMass(Object[0].Body, &m);
// Set up for body 2. As above, except for its initial position.
dBodySetPosition(Object[1].Body, 1.4142, 3.0, -5.0);
dBodySetLinearVel(Object[1].Body, tempVect.x, tempVect.y, tempVect.z);
dBodySetData(Object[1].Body, (void*)i);
dRFromEulerAngles(R, 0.0, pi / 4, 0.0);
dBodySetRotation(Object[1].Body, R);
dMassSetBox(&m, DENSITY, sides[0], sides[1], sides[2]);
Object[1].Geom[0] = dCreateBox(Space, sides[0], sides[1], sides[2]);
dGeomSetBody(Object[1].Geom[0], Object[1].Body);
dBodySetMass(Object[1].Body, &m);
// To join the two objects together we first need to create a new joint with a call to
// dJointCreateBall and retain the ID returned in our Joint variable.
Joint = dJointCreateBall(World, jointgroup);
// We now instruct ODE that this new joint will be attached to our two object bodies.
dJointAttach(Joint, Object[0].Body, Object[1].Body);
// And lastly we tell ODE where exactly the two objects are joined in world coordinates.
dJointSetBallAnchor(Joint, 0.0, 2.0, -5.0);
}

Now there is only one more change needed to get this ball and socket example
working, and that is to change the call to DrawGeom in our original SimLoop
routine to the following.
DrawGeom(Object[0].Geom[0], 0, 0, 0); DrawGeom(Object[1].Geom[0], 0, 0, 0);
Joint = dJointCreateHinge(World, jointgroup); dJointAttach(Joint, Object[0].Body, Object[1].Body); dJointSetHingeAnchor(Joint, 0.0, 2.0, -5.0); dJointSetHingeAxis(Joint, 0, 0, 1);

Joint = dJointCreateSlider(World, jointgroup); dJointAttach(Joint, Object[0].Body, Object[1].Body); dJointSetSliderAxis(Joint, 0, 1, 0); dBodyAddForce(Object[1].Body, 0, 200, 0); // Added a force to show the slider joint in action

dJointGroupDestroy(jointgroup);