Tutorial - Newton Callbacks tutorial with Irrlicht
From Newton Wiki
An adaptation of Tutorial 2 - Using Callbacks. It uses Irrlicht 1.3.1 for the graphics engine.
#include <stdafx.h>
#include "newton.h"
#include "tutorial.h"
#include "HiResTimer.h"
#include "RenderPrimitive.h"
#include "Irrlicht.h"
#pragma comment(lib,"Irrlicht.lib")
#pragma comment(lib, "Newton.lib")
using namespace irr;
CHiResTimer timer; //not actually used in the tutorial
#define GRAVITY -9.8f
#define NEWTONTOIRR 32.0f; //conversion factor between the two
#define IRRTONEWTON 1.0f/NEWTONTOIRR;
core::vector3df cameraDir (320.0, -160.0, -160.0);
core::vector3df cameraEyepoint (-640.0f, 160.0, 160.0);
static NewtonWorld* nWorld;
irr::IrrlichtDevice* device;
static void CleanUp ();
static void* PhysicsAlloc (int sizeInBytes);
static void PhysicsFree (void *ptr, int sizeInBytes);
static void PhysicsBodyDestructor (const NewtonBody* body);
static void PhysicsApplyForceAndTorque (const NewtonBody* body);
static void PhysicsSetTransform (const NewtonBody* body, const dFloat* matrix);
//********************************************************************
//
// Newton Tutorial 2 Using Callbacks
//
//********************************************************************
int main(int argc, char **argv)
{
// initialize irrLicht
//This, of course, is set up for Directx 9, substitute
//EDT_SOFTWARE for the software renderer. However, I don't recommend it as it will be deadly slow
device = irr::createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(800,600), 16, false, false, false, 0);
//Set the working directory for the location of the graphics files.
device->getFileSystem()->changeWorkingDirectoryTo("c:/sdk/irrlicht-1.3.1/media");
scene::ISceneManager* smgr = device->getSceneManager();
video::IVideoDriver* driver = device->getVideoDriver();
// create the physics scene
InitScene();
// Execute irrLicht main loop for ever
int lastFPS = -1;
while (device->run())
{
//Simple default to make the physics update 60 times a second.
//Seems to work pretty well
NewtonUpdate (nWorld,1.0f/60.0f);
driver->beginScene(true, true, video::SColor(255,255,255,255));
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - Newton tutorial 2. FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
return 0;
}
// memory allocation for Newton
void* PhysicsAlloc (int sizeInBytes)
{
return malloc (sizeInBytes);
}
// memory de-allocation for Newton
void PhysicsFree (void *ptr, int sizeInBytes)
{
free (ptr);
}
// add force and torque to rigid body
void PhysicsApplyForceAndTorque (const NewtonBody* body)
{
dFloat Ixx;
dFloat Iyy;
dFloat Izz;
dFloat mass;
NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);
dVector force (0.0f, mass * GRAVITY, 0.0f);
NewtonBodySetForce (body, &force.m_x);
}
// set the transformation of a rigid body
//You have to do this so that the Newton body and irrLicht scene node are in sync,
//and you actually see the changes created by the physics simulation
void PhysicsSetTransform (const NewtonBody* body, const dFloat* matrix)
{
scene::ISceneNode* primitive;
// get the graphic object form the rigid body
//Newton can store a pointer to the scene node in the body object.
primitive = (scene::ISceneNode*) NewtonBodyGetUserData (body);
// set the transformation matrix for this rigid body
dMatrix& mat = *((dMatrix*)matrix);
//Create a matrix to store the irrLicht transformation that will correspond
//to the Newton transformation
core::matrix4 irrMatrix;
//There's no easy way to get the information from one to the other, so a memory copy is required.
//The matrix is a 4x4 float
memcpy (irrMatrix.pointer(), &mat, 16*sizeof(float));
//In order to get the transform right, you have to apply the translation and the rotation
//from the Newton body to the irrLicht scene node.
core::vector3df position (irrMatrix.getTranslation());
position *=NEWTONTOIRR;
core::vector3df rotation;
NewtonGetEulerAngle(irrMatrix.pointer(), &rotation.X);
rotation = rotation * (180.0/3.1416);
primitive->setPosition (position);
primitive->setRotation(rotation);
}
// rigid body destructor
void PhysicsBodyDestructor (const NewtonBody* body)
{
scene::ISceneNode* primitive;
// get the graphic object form the rigid body
primitive = (scene::ISceneNode*) NewtonBodyGetUserData (body);
// destroy the graphic object
primitive->drop();
}
// destroy the world and every thing in it
void CleanUp ()
{
// destroy the Newton world
NewtonDestroy (nWorld);
}
// create physics scene
void InitScene()
{
scene::ISceneManager* smgr = device->getSceneManager();
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneNode* sphere;
scene::ISceneNode* floor;
NewtonBody* sphereBody;
NewtonBody* floorBody;
NewtonCollision* collision;
// create the newton world
nWorld = NewtonCreate (PhysicsAlloc, PhysicsFree);
// set the linear solver model for faster speed
// NewtonSetSolverModel (nWorld, 10);
// set the adaptive friction model for faster speed
// NewtonSetFrictionModel (nWorld, 1);
// Set the termination function
atexit(CleanUp);
// create the sky box
smgr->addSkyBoxSceneNode(
driver->getTexture("irrlicht2_up.jpg"),
driver->getTexture("irrlicht2_dn.jpg"),
driver->getTexture("irrlicht2_lf.jpg"),
driver->getTexture("irrlicht2_rt.jpg"),
driver->getTexture("irrlicht2_ft.jpg"),
driver->getTexture("irrlicht2_bk.jpg"));
// create the the floor graphic objects
dVector size (100.0f, 2.0f, 100.0f);
dMatrix location (GetIdentityMatrix());
location.m_posit.m_y = -5.0f;
// create a box for floor
//Uses the addCubeSceneNode function, but since it only takes one size parameter,
//you have to squish it using the scale vector
core::vector3df position (location.m_posit.m_x, location.m_posit.m_y, location.m_posit.m_z);
position *= NEWTONTOIRR;
float irrSize = size.m_x*NEWTONTOIRR;
floor = smgr->addCubeSceneNode(irrSize, 0,-1,
position,
core::vector3df(0.0,0.0,0.0),
core::vector3df(1.0,2.0/100.0,1.0));
if (floor)
{
floor->setMaterialFlag(video::EMF_LIGHTING, false);
floor->setMaterialTexture(0, driver->getTexture("terrain-texture.jpg"));
}
// create the the floor collision, and body with default values
collision = NewtonCreateBox (nWorld, size.m_x, size.m_y, size.m_z, NULL);
floorBody = NewtonCreateBody (nWorld, collision);
NewtonReleaseCollision (nWorld, collision);
// set the transformation for this rigid body
NewtonBodySetMatrix (floorBody, &location[0][0]);
// save the pointer to the graphic object with the body.
NewtonBodySetUserData (floorBody, floor);
// set a destructor for this rigid body
NewtonBodySetDestructorCallback (floorBody, PhysicsBodyDestructor);
// set the initial size for the spheres
size = dVector(0.5f, 0.5f, 0.5f);
irrSize = size.m_x*NEWTONTOIRR;
// create the collision
collision = NewtonCreateSphere (nWorld, size.m_x, size.m_y, size.m_z, NULL);
// create 100 stacks of 10 spheres each
location.m_posit.m_x = -16.0f;
for (int k = 0; k < 8; k ++) {
location.m_posit.m_z = 0.0f;
for (int j = 0; j < 4; j ++) {
location.m_posit.m_y = -3.75f - 0.01f;
for (int i = 0; i < 8; i ++) {
// create a graphic sphere.
// Boxes are fun, but spheres scatter so much better.
sphere = smgr->addSphereSceneNode(irrSize);
if (sphere)
{
sphere->setMaterialFlag(video::EMF_LIGHTING, false);
sphere->setMaterialTexture(0, driver->getTexture("earth.bmp"));
}
//create the rigid body
sphereBody = NewtonCreateBody (nWorld, collision);
// save the pointer to the graphic object with the body.
NewtonBodySetUserData (sphereBody, sphere);
// set a destructor for this rigid body
NewtonBodySetDestructorCallback (sphereBody, PhysicsBodyDestructor);
// set the transform call back function
NewtonBodySetTransformCallback (sphereBody, PhysicsSetTransform);
// set the force and torque call back function
NewtonBodySetForceAndTorqueCallback (sphereBody, PhysicsApplyForceAndTorque);
// set the mass matrix
NewtonBodySetMassMatrix (sphereBody, 1.0f, 1.0f, 1.0f, 1.0f);
// set the matrix for both the rigid body and the graphic body
NewtonBodySetMatrix (sphereBody, &location[0][0]);
PhysicsSetTransform (sphereBody, &location[0][0]);
location.m_posit.m_y += size.m_y * 2.0f;
}
//Randomize the locations a little bit, or else the spheres
//will stack perfectly on top of one another and won't fall down!
location.m_posit.m_z -= size.m_z * 4.0f*rand()/32767;
}
location.m_posit.m_x += size.m_x * 4.0f*rand()/32767;
}
// release the collision geometry when not needed
NewtonReleaseCollision (nWorld, collision);
//Add an irrLicht FPS camera, and turn off the cursor visibility
float cameraRotateSpeed = 100.0;
float cameraMoveSpeed = 500.0;
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0,
cameraRotateSpeed,
cameraMoveSpeed,
-1, 0, 0, false, 0.0);
if (camera)
{
camera->setPosition(cameraEyepoint);
camera->setTarget(cameraEyepoint+cameraDir);
}
device->getCursorControl()->setVisible(false);
}
