How to use Functions callbacks with classes in C++?

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

How to use Functions callbacks with classes in C++?

Postby Julio Jerez » Fri Feb 18, 2005 11:10 am

How can I use Newton in Cpp with virtual function as callbacks?
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
Julio Jerez
Moderator
Moderator
 
Posts: 11039
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Return to General Discussion

Who is online

Users browsing this forum: No registered users and 3 guests