Tutorial - Newton Callbacks tutorial with Irrlicht

From Newton Wiki
Jump to: navigation, search

An adaptation of Newton 1.5.3 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);
}