the .h file
Code: Select all
#ifndef __C_SCENE_NODE_ANIMATOR_NEWTON_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_NEWTON_H_INCLUDED__
#include "irrList.h"
#include "ISceneNode.h"
#include "ISceneNodeAnimator.h"
#include <newton.h>
namespace irr
{
namespace scene
{
//! Body types
enum E_NEWTON_BODY_TYPE
{
ENBT_CUBE,
ENBT_SPHERE
};
//! An animator that animates the scene node according to the Newton Game Dynamics
class CSceneNodeAnimatorNewton : public ISceneNodeAnimator
{
public:
//! Constructor
CSceneNodeAnimatorNewton(E_NEWTON_BODY_TYPE type = ENBT_CUBE,
const core::vector3df& size = core::vector3df(10,10,10), f32 mass = 10);
//! destructor
virtual ~CSceneNodeAnimatorNewton();
//! animates a scene node
virtual void animateNode(ISceneNode* node, u32 timeMs);
//! Gets the newton body
/** \return Returns the newton body */
NewtonBody* getNewtonBody()
{
return Body;
}
//! Gets the newton world
/** \return Returns the newton world. */
static NewtonWorld* getNewtonWorld()
{
return nWorld;
}
//! Sets the gravity
/** \param newGravity: the new gravity to be used */
static void setGravity(f32 newGravity)
{
Gravity = newGravity;
}
//! Sets the update interval
/** \param ms: the update inerval in milli seconds */
static void setUpdateInterval(f32 ms)
{
dt = ms;
}
private:
//the newton force and torque callback
static void forceAndTorqueCallback(const NewtonBody* body);
//the newton transform callback
static void transformCallback(const NewtonBody* body, const f32* matrix);
//the mass of the newton body
f32 Mass;
//the size of the newton collision
core::vector3df Size;
//the type of the newton collision (box or sphere)
E_NEWTON_BODY_TYPE Type;
//the newton world
static NewtonWorld* nWorld;
//the newton body
NewtonBody* Body;
//the gravity of the world
static f32 Gravity;
//bool used to check if an animateNode call is the first or not
bool FirstAnimate;
/* a list of created animators of this type, this is used to keep track
of who's updating the newton world, when an animator is deleted the job is
passed on to the next in the list */
static core::list<CSceneNodeAnimatorNewton*> CreatedAnimators;
//bool to check if this animator is updating the newton world
bool IAmUpdating;
//current time, gets updated on every animateNode call
static f32 CurrentTime;
//the time accumulator is making sure that the world is updated right
static f32 TimeAccumulator;
//the time step
static f32 dt;
};
}//end namespace scene
}//end namespace irr
#endif
Code: Select all
#include "CSceneNodeAnimatorNewton.h"
namespace irr
{
namespace scene
{
//declare static data members
NewtonWorld* CSceneNodeAnimatorNewton::nWorld = NewtonCreate(NULL, NULL);
core::list<CSceneNodeAnimatorNewton*> CSceneNodeAnimatorNewton::CreatedAnimators;
f32 CSceneNodeAnimatorNewton::CurrentTime = 0;
f32 CSceneNodeAnimatorNewton::TimeAccumulator = 0;
f32 CSceneNodeAnimatorNewton::dt = 10;
f32 CSceneNodeAnimatorNewton::Gravity = -98.f;
//! Constructor
CSceneNodeAnimatorNewton::CSceneNodeAnimatorNewton(E_NEWTON_BODY_TYPE type, const core::vector3df& size, f32 mass)
: Mass(mass), Size(size), Type(type), Body(0), FirstAnimate(true), IAmUpdating(false)
{
//search though the other created animators to see if anyone is updating the newton world
bool anotherIsUpdating = false;
core::list<CSceneNodeAnimatorNewton*>::Iterator it = CreatedAnimators.begin();
for (; it != CreatedAnimators.end(); ++it)
{
//if an object is found
if((*it))
{
//is it updating
if((*it)->IAmUpdating)
anotherIsUpdating = true;
}
}
//if no other animator is updating the newton world - make this one do it
if(!anotherIsUpdating)
{
IAmUpdating = true;
}
//put this animator in the static list
CreatedAnimators.push_back(this);
/* the newton world could have been deleted, if at some time in the code no animators where active.
Because of this the animator needs to check if the newton world is there, and create a new one if it isn't */
if(!nWorld)
nWorld = NewtonCreate(NULL, NULL);
}
//! destructor
CSceneNodeAnimatorNewton::~CSceneNodeAnimatorNewton()
{
//a bool to check if other animators is still there
bool foundOther = false;
//bool to check if another animator is set to update
bool anotherIsUpdating = false;
//iterate though the list to remove the pointer to this animator, and check if other animators are still active
core::list<CSceneNodeAnimatorNewton*>::Iterator it = CreatedAnimators.begin();
for (; it != CreatedAnimators.end(); ++it)
{
//remove the pointer to this, from the list
if((*it) == this)
(*it) = 0;
//if an animator is found
if((*it))
foundOther = true;
}
//if this animator was the one updating the newton world - make another one update
if(IAmUpdating)
{
it = CreatedAnimators.begin();
for(; it!= CreatedAnimators.end(); ++it)
{
//if an animator is found
if((*it))
{
//and it is the first one found
if(!anotherIsUpdating)
{
//make it update
(*it)->IAmUpdating = true;
anotherIsUpdating = true;
}
}
}
}
//delete the newton body
if(Body)
NewtonDestroyBody(nWorld, Body);
//if this is the last animator - delete the newton world
if(!foundOther)
{
if(nWorld)
{
NewtonDestroy(nWorld);
nWorld = 0;
}
}
}
//! animates a scene node
void CSceneNodeAnimatorNewton::animateNode(ISceneNode* node, u32 timeMs)
{
//if this is the first update - create the newton body
if(FirstAnimate)
{
NewtonCollision* collision = 0;
float I[3];
if(Type == ENBT_CUBE)
{
//calculate the inertia
I[0] = 0.0833f*Mass*(Size.Z*Size.Z + Size.Y*Size.Y);
I[1] = 0.0833f*Mass*(Size.Z*Size.Z + Size.X*Size.X);
I[2] = 0.0833f*Mass*(Size.X*Size.X + Size.Y*Size.Y);
//create the collision
collision = NewtonCreateBox(nWorld, Size.X, Size.Y, Size.Z, NULL);
}
if(Type == ENBT_SPHERE)
{
//calculate inertia
I[0] = 0.2f*Mass*(Size.Z*Size.Z + Size.Y*Size.Y);
I[1] = 0.2f*Mass*(Size.Z*Size.Z + Size.X*Size.X);
I[2] = 0.2f*Mass*(Size.X*Size.X + Size.Y*Size.Y);
//create the collision
collision = NewtonCreateSphere(nWorld, Size.X, Size.Y, Size.Z, NULL);
}
if(collision)
{
//create the body
Body = NewtonCreateBody(nWorld, collision);
//release the collision
NewtonReleaseCollision(nWorld, collision);
}
if(Body)
{
//set the mass and inertia of the body
NewtonBodySetMassMatrix(Body, Mass, I[0], I[1], I[2]);
//apply the node's matrix to the body
NewtonBodySetMatrix(Body, node->getRelativeTransformation().pointer());
//set the node as userdata of the body
NewtonBodySetUserData(Body, node);
//set the callbacks
NewtonBodySetForceAndTorqueCallback(Body, forceAndTorqueCallback);
NewtonBodySetTransformCallback(Body, transformCallback);
}
FirstAnimate = false;
}
//if this animator is taking care of updating the newton world
if(IAmUpdating)
{
//update the newton world
if(TimeAccumulator < dt)
{
//get the time from the device
f32 newTime = timeMs;
//calculate the time step
f32 deltaTime = newTime - CurrentTime;
//update CurrentTime
CurrentTime = newTime;
//add the time step to the time accumulator
TimeAccumulator += deltaTime;
}
//update if the TimeAccumulator is big enough
if(TimeAccumulator >= dt)
{
//update
NewtonUpdate(nWorld, dt/1000); //convert to seconds
TimeAccumulator -= dt;
}
}
}
void CSceneNodeAnimatorNewton::forceAndTorqueCallback(const NewtonBody* body)
{
//some floats to hold the information of the body
float Ixx;
float Iyy;
float Izz;
float mass;
//get the info and put it in the above floats
NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);
//create a force vector with gravity
float force[3] = {0.0f, mass*Gravity, 0.0f};
//apply the force
NewtonBodySetForce(body, force);
}
void CSceneNodeAnimatorNewton::transformCallback(const NewtonBody* body, const f32* matrix)
{
//get the scene node from the newton body
ISceneNode* node = (ISceneNode*)NewtonBodyGetUserData(body);
//make a matrix to hold the body matrix
core::matrix4 irrMat;
//copy the body matrix to the matrix4
memcpy(irrMat.pointer(), matrix, sizeof(float)*16);
//move and rotate the node according to the matrix
if(node)
{
node->setPosition(irrMat.getTranslation());
node->setRotation(irrMat.getRotationDegrees());
}
}
}//end namespace scene
}//end namespace irr
Code: Select all
#include <irrlicht.h>
#include <newton.h>
#include "CSceneNodeAnimatorNewton.h"
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
int main()
{
IrrlichtDevice* device = createDevice();
ISceneManager* smgr = device->getSceneManager();
IVideoDriver* driver = device->getVideoDriver();
ISceneNode* node = smgr->addCubeSceneNode();
ISceneNodeAnimator* anim = new CSceneNodeAnimatorNewton();
node->addAnimator(anim);
anim->drop();
ISceneNode* node2 = smgr->addSphereSceneNode();
node2->setPosition(vector3df(0,-30,5));
ISceneNodeAnimator* anim2 = new CSceneNodeAnimatorNewton(ENBT_SPHERE, vector3df(5,5,5), 0);
node2->addAnimator(anim2);
anim2->drop();
smgr->addCameraSceneNodeMaya();
while(device->run())
{
driver->beginScene(true, true, SColor(100,100,100,100));
smgr->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
Any comments would be appreciated!