This is a problem that many novice C++ programmers face when confronted with a library with C interface. Some time this lead them to dismiss the library altogether thinking there is no way it can be used in C++ with an object oriented design, when it is just the opposite, a library with a C interface is by far more flexible to integrate with a C++ application than a one with a C++ interface. The reason is that the application does not have to inherit all the baggage or designed patterns of the original design. The application can make its own design. This is one possible solution to the problem:
-Create your own base class representing your rigid body.
-Add a private static function for each function callback of the rigid body.
-Add a pure virtual function for each function callback of the rigid body
-Make the constructor private
-Add a pointer to the rigid body as private member.
-Wrap all the functionality of the rigid body with equivalents public member function.
Here is an example:
- Code: Select all
// Header file for a Object oriented encapsulation of a Newton Rigid body
class MyMatrix; // an object that encapsulates the application matrix
class MyWorld; // an object encapsulation of the Newton world.
// Ridig nody base class
class MyRididBody
{
protected:
// dummy constructor
MyRididBody ();
// this effective construtor
void Int (MyWorld* world, NewtonCollision* collision);
virtual ~ MyRididBody();
// public interface
public:
void SetMatrix (const MyMatrix& matrix);
const MyMatrix& GetMatrix SetMatrix () const;
void SetCollision (const MyCollision* collision);
MyCollision* GetCollision ();
protected:
// Rigid body events
virtual void ApplyForceAndTorque () = 0;
virtual void AutoActivation (unsigned state) = 0;
virtual void SetTransform(const MyMatrix& matrix) = 0;
private:
static void AutoDestruction (const NewtonBody* body);
static void ApplyForceAndTorque (const NewtonBody* body);
static void SetTransform (const NewtonBody* body, const float* matrix);
static void AutoAutoactivation (const NewtonBody* body, unsigned state);
NewtonBody* m_body;
// other class members if desired here
...
};
// Code implementation of a Newton Ridif Body encapsulation
#include "MyRidifBody.h"
MyRididBody::MyRididBody ()
:m_body (NULL)
{
}
// this is the effective constructor,
// it must be called by each derived class from the constructor
void MyRididBody::Init (MyWorld* world, NewtonCollision* collision)
{
// create the ridid body
m_body = NewtonCreateBody (world->GetWorld(), NewtonCollision);
// store the pointer to the class with the Newton Objects
NewtonBodySetUserData (m_body, this);
// hook the events call backs
NewtonBodySetTransformCallback (m_body, SetTransform);
NewtonBodySetDestructorCallback (m_body, AutoDestruction);
NewtonBodySetAutoactiveCallback (m_body, AutoAutovation);
NewtonBodySetForceAndTorqueCallback (m_body, ApplyForceAndTorque);
}
MyRididBody::~MyRididBody ()
{
//if the class has thet user data, it means the application is detroying this object
if (NewtonBodyGetUserData (m_body)) {
// set the user data callback to NULL to prevent infinite recursion
NewtonBodySetDestructorCallback (m_body, NULL);
// call newton to destroy this rigid body
NewtonDestroyBody (NewtonBodyGetWorld (m_body));
}
}
// This function can be called aoutomatically from the Newton World to destroy a body
void MyRididBody::AutoDestruction ()
{
MyRididBody* body;
// get the pointer to the body class
body = (MyRididBody *) NewtonBodySetUserData (this);
// set the body callback and user data to NULL to prevent infinite recursion
NewtonBodySetDestructorCallback (me, NULL);
NewtonBodySetUserData (m_body, NULL);
// delete this class
delete body;
}
void MyRididBody::SetTransform (const NewtonBody* me, const float* matrix)
{
MyRididBody* body;
// get the pointer to the body class
body = (MyRididBody *) NewtonBodyGetUserData (me);
_ASSERTE (body);
const MyMatrix& matrix = *((const MyMatrix*) (matrix));
body-> SetTransform(matrix);
}
void MyRididBody::ApplyForceAndTorque (const NewtonBody* me)
{
MyRididBody* body;
// get the pointer to the body class
body = (MyRididBody *) NewtonBodyGetUserData (me);
_ASSERTE (body);
body-> ApplyForceAndTorque()
}
// the rest of the implemetation is very simular.
...
...
// here is and example of a gravity Box
Class MyBox: public MyBody
{
public:
MyBox (MyWorld* world, const MyMatrix& location, const MyVector& size, float mass)
:MyBody ()
{
NewtonCollision* collision;
// create the collision and initilize the object
collision = NewtonCreateBox (nWorld, size.m_x, size.m_y, size.m_z, NULL);
Init (world, collision);
NewtonReleaseCollision (nWorld, collision);
// initilize the rest of the object by calling member of the base class,
//or call newton funtion directly
float Ixx;
float Iyy;
float Izz;
Ixx = mass * (size.m_y * size.m_y + size.m_z * size.m_z) / 12.0f;
Iyy = mass * (size.m_x * size.m_x + size.m_z * size.m_z) / 12.0f;
Izz = mass * (size.m_x * size.m_x + size.m_y * size.m_y) / 12.0f;
NewtonBodySetMassMatrix (blockBoxBody, mass, Ixx, Iyy, Izz);
NewtonBodySetMatrix (m_body, &location[0][0]);
PhysicsSetTransform (m_body, &location[0][0]);
// more initializtion
...
}
~MyBox ()
{
// nothing for this object
}
void ApplyForceAndTorque ()
{
// add the gravity force to this body
float mass;
float Ixx;
float Iyy;
float Izz;
NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);
dVector force (0.0f, mass * GRAVITY, 0.0f);
NewtonBodySetForce (body, &force.m_x);
}
// implement the rest of the funtionality here
};
With this approach the application will have all the benefit of the cpp interface, and can even customize what is desired to include with your object oriented design.
For more references check the implementation of the custom joint library included with the SDK