Irrlicth-Newton Demonstration with Irrlicht 1.4, Newton 1.53

A forum to store posts deemed exceptionally wise and useful
gbutcher
Posts: 8
Joined: Sun Jan 06, 2008 4:27 pm

Irrlicth-Newton Demonstration with Irrlicht 1.4, Newton 1.53

Post by gbutcher »

I munged Mercior's demo to work:

Code: Select all

/* Updated Mercior's Irrlicht-Newton Demonstration
by Glenn Butcher, Jan 2008

Uses Irrlicht 1.4 and Newton 1.53, compiles with Mingw/DevC++
Major changes:
    - Change matrix4 to use theCMatrix4 template class
    - Padded the Newton world because the bsp size didn't include the initial crates
        (Shoot some crates over the wall, see what happens)
    - Added setMaterialFlag(EMF_LIGHTING, false) to MakeCube to light up the cube texture
    - Put it all in main.cpp so I could concentrate on finding the above...
        (Mercoir, I'm >50, don't think global variables, in moderation, are so bad  :D)
    
*/

#pragma comment(lib, "Irrlicht.lib")
#pragma comment(lib, "Newton.lib")

#define NEWTON_GRAVITY -800.0f

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// Irrlicht:
#include <irrlicht.h>
#include <wchar.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// Newton:
#include <Newton.h>

	// Old man's cube class... 
	struct NewtonCube {
		IAnimatedMesh *mesh;
		ISceneNode *node;
		NewtonBody *body;
		NewtonCollision *collision;
	};
	NewtonCube *cubes[512];
	int currentCube;

	// Frame drawing variables:
	int lastFPS;
	u32 lasttick;

	// Irrlicht vars:
	IVideoDriver* driver;
	ISceneManager* smgr;
	IGUIEnvironment* guienv;
	IrrlichtDevice *device;

	// Newton vars:
	NewtonWorld *nWorld;

	// Our level:
	scene::IAnimatedMesh* g_map;
	scene::ISceneNode* g_mapnode;
	scene::ITriangleSelector *g_selector;
	NewtonCollision* g_newtonmap;
	NewtonBody* g_newtonmapbody;

	// Scene vars:
	ICameraSceneNode *cam;


void SetMeshTransformEvent(const NewtonBody* body, const float* matrix)
{
	// Instantiate Irricht CMatrix4 template as float, copy the matrix into it:
	// ggb: Old tutorial used matrix4
	CMatrix4<float> mat;
	mat.setM(matrix);

	// Retreive the user data attached to the Newton body:
	ISceneNode *tmp = (ISceneNode *)NewtonBodyGetUserData(body);
	if (tmp)
	{
		// Position the node:
		tmp->setPosition(mat.getTranslation());		// set position
		tmp->setRotation(mat.getRotationDegrees());	// and rotation
	}
}

void ApplyForceAndTorqueEvent (const NewtonBody* body)
{
	float mass;
	float Ixx;
	float Iyy;
	float Izz;
	float force[3];
	float torque[3];

	NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);

	force[0] = 0.0f;
	force[1] = NEWTON_GRAVITY * mass;
	force[2] = 0.0f;

	torque[0] = 0.0f;
	torque[1] = 0.0f;
	torque[2] = 0.0f;

	NewtonBodyAddForce (body, force);
	NewtonBodyAddTorque (body, torque);
}

NewtonCube* MakeCube(vector3df loc)
{
	NewtonCube *tmp = new NewtonCube;

	tmp->mesh = smgr->getMesh("data/smallcube.3ds");
	tmp->node = smgr->addAnimatedMeshSceneNode(tmp->mesh);
	tmp->node->setMaterialFlag(EMF_LIGHTING, false);
	tmp->node->setMaterialTexture(0, driver->getTexture("data/crate.jpg"));

	// Create a box primitive. 38 is just an estimated value of the size of the model:
	tmp->collision = NewtonCreateBox(nWorld, 38, 38, 38, NULL);
	tmp->body = NewtonCreateBody(nWorld, tmp->collision);

	// Set user data pointer to the scene node:
	NewtonBodySetUserData(tmp->body, tmp->node);

	// Set body mass & inertia matrix
	NewtonBodySetMassMatrix (tmp->body, 10.0f, 150.0f, 150.0f, 150.0f);

	// Set the freeze threshhold to 1 unit (default is 0.01 but irrlight uses a 
	// large unit scale):
	NewtonBodySetFreezeTreshold(tmp->body, 1.0, 1.0, 1);

	// Set callback functions for the body:
	NewtonBodySetTransformCallback(tmp->body, SetMeshTransformEvent);
	NewtonBodySetForceAndTorqueCallback(tmp->body, ApplyForceAndTorqueEvent);
	
	// Animate the body by setting the angular velocity - makes 'em spin!
	float omega[3]; omega[1] = 1.0f; omega[2] = 0.0f; omega[3] = 0.0f;
	NewtonBodySetOmega (tmp->body, &omega[0]);

	// Set the position of the body:
	CMatrix4<float> mat;
	//matrix4 mat;
	mat.setTranslation(loc);
	NewtonBodySetMatrix(tmp->body, mat.pointer());


	if (currentCube == 512)
	{
		printf("* Too many cubes!");
	}
	cubes[currentCube] = tmp;
	currentCube ++;

	return tmp;
}

class MyEventReceiver : public IEventReceiver
{
public:
	virtual bool OnEvent(const SEvent& event)
    {
	   if (event.EventType == irr::EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == 
            EMIE_LMOUSE_PRESSED_DOWN)
	   {
		  // make a cube where the camera is and set its velocity to follow the target:
		  NewtonCube *tmp = MakeCube(cam->getPosition());
		  if (!tmp) return false;
		  vector3df camvec = (cam->getTarget() - cam->getPosition()).normalize() * 500;
		  float newpos[3] = { camvec.X, camvec.Y, camvec.Z };
		  NewtonBodySetVelocity(tmp->body, (float*)newpos);
	   }
	   return false;
    }
};


int main(int argc, char* argv[])
{

	// Init the Irrlicht engine:
	MyEventReceiver receiver;
	device = createDevice(EDT_OPENGL, dimension2d<s32>(800, 600), 16, false, true, false, &receiver);

	driver = device->getVideoDriver();
	smgr = device->getSceneManager();
	guienv = device->getGUIEnvironment();

	// Init Newton:
	nWorld = NewtonCreate(NULL, NULL);

	// Set up default material properties for Newton:
	int i = NewtonMaterialGetDefaultGroupID(nWorld);
	NewtonMaterialSetDefaultFriction   (nWorld, i, i, 0.8f, 0.4f);
	NewtonMaterialSetDefaultElasticity (nWorld, i, i, 0.3f);
	NewtonMaterialSetDefaultSoftness   (nWorld, i, i, 0.05f);
	NewtonMaterialSetCollisionCallback (nWorld, i, i, NULL, NULL, NULL, NULL);

	// Add the camera:
	cam = smgr->addCameraSceneNodeFPS();
	cam->setPosition(vector3df(0, 350, 0));

	// Initialize variables:
	lasttick = 0;
	currentCube = 0;

	// Add skybox:
	smgr->addSkyBoxSceneNode(driver->getTexture("data/irrlicht2_up.bmp"),
                            driver->getTexture("data/irrlicht2_dn.bmp"),
                            driver->getTexture("data/irrlicht2_lf.bmp"),
                            driver->getTexture("data/irrlicht2_rt.bmp"),
                            driver->getTexture("data/irrlicht2_ft.bmp"),
                            driver->getTexture("data/irrlicht2_bk.bmp"));

	// Load map:
	g_map = smgr->getMesh("data/physicstest.bsp");
	g_mapnode = smgr->addOctTreeSceneNode(g_map->getMesh(0));

	//////////////////////////////////////////////////////////////////////////
	//
	// Create the newton collision tree from the map mesh
	//
	// Remember to use (video::S3DVertex) if you are loading a mesh without 
	// lightmaps for your level. (Like a .x or .3ds level)
	//
	//////////////////////////////////////////////////////////////////////////
	g_newtonmap = NewtonCreateTreeCollision(nWorld, NULL);
	NewtonTreeCollisionBeginBuild(g_newtonmap);
	int cMeshBuffer, j;
	int v1i, v2i, v3i;
	IMeshBuffer *mb;

	float vArray[9]; // vertex array (3*3 floats)

	int tmpCount = 0;

	for (cMeshBuffer=0; cMeshBuffer<g_map->getMesh(0)->getMeshBufferCount(); cMeshBuffer++)
	{
		mb = g_map->getMesh(0)->getMeshBuffer(cMeshBuffer);

		video::S3DVertex2TCoords* mb_vertices = (irr::video::S3DVertex2TCoords*)mb->getVertices();

		u16* mb_indices  = mb->getIndices();

		// add each triangle from the mesh:
		for (j=0; j<mb->getIndexCount(); j+=3)
		{
			v1i = mb_indices[j];
			v2i = mb_indices[j+1];
			v3i = mb_indices[j+2];

			vArray[0] = mb_vertices[v1i].Pos.X;
			vArray[1] = mb_vertices[v1i].Pos.Y;
			vArray[2] = mb_vertices[v1i].Pos.Z;
			vArray[3] = mb_vertices[v2i].Pos.X;
			vArray[4] = mb_vertices[v2i].Pos.Y;
			vArray[5] = mb_vertices[v2i].Pos.Z;
			vArray[6] = mb_vertices[v3i].Pos.X;
			vArray[7] = mb_vertices[v3i].Pos.Y;
			vArray[8] = mb_vertices[v3i].Pos.Z;

			NewtonTreeCollisionAddFace(g_newtonmap, 3, (float*)vArray, 12, 1);
		}

	}
	NewtonTreeCollisionEndBuild(g_newtonmap, 0);
	g_newtonmapbody = NewtonCreateBody(nWorld, g_newtonmap);


	// Set the newton world size based on the bsp size:
	float boxP0[3];
	float boxP1[3];
	float matrix[4][4];
	NewtonBodyGetMatrix (g_newtonmapbody, &matrix[0][0]);
	NewtonCollisionCalculateAABB (g_newtonmap, &matrix[0][0],  &boxP0[0], &boxP1[0]);
	printf("min: %f,%f,%f  max: %f,%f,%f\n",boxP0[0],boxP0[1],boxP0[2],boxP1[0],
        boxP1[1],boxP1[2]);  //exposed the 'small world' problem...
	// You can pad the box here if you wish 
	// ggb: I spent a lot of time figuring out the initial boxes were outside the 
	//      Newton world bounded by the bsp size.  Just padded y by 1000 in both 
	//      directions to snag them.
	boxP0[1] -= 1000.0f;  //boxP0.y
	boxP1[1] += 1000.0f;  //boxP1.y
	NewtonSetWorldSize (nWorld, (float*)boxP0, (float*)boxP1);

	// Hide cursor:
	device->getCursorControl()->setVisible(false);

	// Make some cubes:
	int xo = 500, yo = 500;
	int x, y;
	for (x=0; x<10; x++)
	{
		for (y=0; y<10; y++)
		{
			MakeCube(vector3df((float)(x*100)-xo, 500.0f, (float)(y*100)-yo));
		}
	}

 
	// Main Loop:
	while(device->run())
	{
	   	driver->beginScene(true, true, video::SColor(0,220,220,255));

	   // Render the scene:
	   smgr->drawAll();

	   driver->endScene();

	   // Draw fps counter:
	   int fps = driver->getFPS();
	   if (lastFPS != fps)
	   {
		  wchar_t tmp[1024];
		  swprintf(tmp, 1024, L"Newton Example [fps:%d] [triangles:%d]",
		      fps, driver->getPrimitiveCountDrawn());
		  device->setWindowCaption(tmp);
		  lastFPS = fps;
	   }

	   // Update newton 100 times / second:
	   if (device->getTimer()->getTime() > lasttick + 10) {
		  lasttick = device->getTimer()->getTime();
		  NewtonUpdate(nWorld, 0.01f);
	   }
	}

	// Clean up memory:
        
	// Release the collision tree:
	NewtonReleaseCollision(nWorld, g_newtonmap);

	// Release the box primitives:
	for (int i=0; i<currentCube; i++)
		NewtonReleaseCollision(nWorld, cubes[i]->collision);

	// Finish Newton & Irrlicht:
	NewtonDestroy(nWorld);
	device->drop();

	return 0;
}
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Quake world collision question

Post by Seven »

I have been using these types of tuts for a hosrt while now and have a nice little test bed created. Question though, how do you detect a collision between a node and the quake world. for example, in the following code, I load up a quake world and then have objects that I create bounce all over it. I can even detect when objects collide against each other, because I have newton materials assigned to them. What I would like to do is tell when the object hits the quake mesh, so that I can make it explode and whatnot.

Code: Select all

	virtual bool Create(CSLevel* level, int id, char* zipfile, char* levelname) {	
											CSObject::Create(level, id);

											video::IVideoDriver* driver = level->m_App->m_Engine->m_Driver;
											scene::ISceneManager* smgr = level->m_Smgr;
											scene::ICameraSceneNode* camera = level->m_Camera;

											/////////////////////////////////////////////////////////////
											//load a map as an oct tree scene node add a zip file
											level->m_App->m_Engine->m_Device->getFileSystem()->addZipFileArchive(zipfile);

											//get model mesh
											scene::IAnimatedMesh* world_mesh_anim = smgr->getMesh(levelname);

											//create the scene node
											m_Node = smgr->addOctTreeSceneNode(world_mesh_anim);
											
											// set whether light affects the node
											m_Node->setMaterialFlag(video::EMF_LIGHTING, false);

											//position the scene node
											m_Node->setPosition(core::vector3df(45,0,0));

											//let's create the body for our map
											//if we don't do this, the ellipsoid trought the map
											//the creation methos is the same
											irr::newton::SBodyFromNode mapData;
											mapData.Node = m_Node;
		
											//because the node is a oct tree scene node and not a simple scene node we need to pass the mesh also
											mapData.Mesh = world_mesh_anim->getMesh(0);
											mapData.Type = newton::EBT_TREE;

											//create the body
											irr::newton::IBody* world_p_node = level->m_NewtonWorld->createBody(mapData);

											//world_p_node->setUserData((void*)this);
											//world_p_node->setMaterial(level->Newton_Material_Quake);
											
											/////////////////////////////////////////////////////////////
											return true;			
										}


the code above kind of works, but the commented out materials code uses the mesh as a rectangle that encloses the entire quake world, not each individual wall.
any help is appreciated.

Seven
gbutcher
Posts: 8
Joined: Sun Jan 06, 2008 4:27 pm

NewtonMaterialSetCollisionCallback

Post by gbutcher »

NewtonMaterialSetCollisionCallback(...)

I think this will do what you're looking for; register a function to be called upon a contact. I'm guessing however; the demo code I posted above is my first Newton effort...

g
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

Thanks for the reply. I do have the callbacks setup and working, but the quake node seems to get treated as a single rectangle for collision reaction. This causes the 'bullet' to hit the quake node total bounding box instead of a 'wall'. I can also have it hit just a wall, but when i do that, the frame rate slows to something awful. The end result is that i am doing something wrong I am sure, but I cant seem to find what it is.
fabregot
Posts: 2
Joined: Mon Sep 18, 2006 4:32 pm

Post by fabregot »

Code: Select all

float omega[3]; omega[1] = 1.0f; omega[2] = 0.0f; omega[3] = 0.0f; 
In this part on VS .NET 2003 crashes!

Change this for:

Code: Select all

float omega[3]; omega[1] = 1.0f; omega[2] = 0.0f; omega[0] = 0.0f; 
Because the '3' is out of index.

It's ok?
Dorth
Posts: 931
Joined: Sat May 26, 2007 11:03 pm

Post by Dorth »

Or maybe O[0] = 1.0f; etc. since it's the first of the array?
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

you must create the terrain like a tree for newton look for tree bouding boxes.
Take a look at irrnewt wrapper for looking how it does that.
etcaptor
Posts: 871
Joined: Fri Apr 09, 2004 10:32 pm
Location: Valhalla
Contact:

Post by etcaptor »

Full/advanced/ Newton integration with Irrlicht is "bpia" /big pain in ass"/ :D It is the last obstacle for my last project release. But it's almost complete. You must consider your collision type - box, sphere, cylinder, cone, mesh. For mesh type must check whether it octree or terrain. Also you must find vertex types of your mesh. Some problems are very strange/maybe Irrlicht bugs/ but for octree you must use IAnimatedMesh, and for terrain IMesh.
Also Newton design is not OOP :(.
When I see my wrappers I just foll in depression with all callbacks :)
I forgot that Irrlicht and Newton haves different scales. I forgot that when any Irrlicht mesh is resized you must recalculate newton rigid body. And many many related details. Yet I congratulate your for this topic. Let it's grown with all kind of these problems and solutions.
ImageImage
Site development -Rock and metal online
--- etcaptor.com ------freenetlife.com
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

Those problems that you name are all resolve in irrNewt (newton wrrapper).
If you don't want you use it and want do it one for yourself, it will be a extremly helpful aproach to take a look at, because it is OOP and has all problem tbat you name solved in high level, for example createing a convexhull, tree, compound etc. Realy practice at least to learn and take some ideas.
In fact you can take and better it, of course it need some upgrade.

I hope it help you.
etcaptor
Posts: 871
Joined: Fri Apr 09, 2004 10:32 pm
Location: Valhalla
Contact:

Post by etcaptor »

Yeah, thanks. But I already finished with my own implementation last night. Will take a look there.
ImageImage
Site development -Rock and metal online
--- etcaptor.com ------freenetlife.com
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

Coud you pass me the function that you used to make convex hulls?
I mean the part that give the vertext to newton.
Because although this work in irrnewt quit well, I don't like the shape that it forms. Maybe IT IS in fact the form that it should form but maybe not and there is some vertex missing or something like that.
etcaptor
Posts: 871
Joined: Fri Apr 09, 2004 10:32 pm
Location: Valhalla
Contact:

Post by etcaptor »

Yes, will post it tonight when going home. Done:
Here is this part of code and debug screen with sydney.md2 animated mesh. You can use convexhull modifier for response to any bounding box changes.

Image

Code: Select all

//---------------------------------------------------------------------------
        case ID_CONVEXHULL:
        {
            IMeshBuffer *mb = NULL;
            int BufferCount = m_Mesh->getMeshBufferCount();
            array<vector3df> varray;

            for (int bi = 0 ; bi < BufferCount ; bi++)
            {
                mb = m_Mesh->getMeshBuffer(bi);
                int VerticleCount = mb->getVertexCount();
                varray.reallocate(varray.size()+ VerticleCount);

                switch(mb->getVertexType())
                {
                    case EVT_STANDARD:
                    {
                        S3DVertex* Vertices = (S3DVertex*)mb->getVertices();
                        for (int ii = 0 ; ii < VerticleCount ; ii++)
                        {
                            Vertices = (S3DVertex*)mb->getVertices();
                            for(int j=0;j< VerticleCount; j++)
                                varray.push_back( Vertices[j].Pos * IrrToNewton * m_ISceneNode->getScale());
                        }

                    }break;

                    case EVT_2TCOORDS:
                    {
                        S3DVertex2TCoords* Vertices = (S3DVertex2TCoords*)mb->getVertices();
                        for (int ii = 0 ; ii < VerticleCount ; ii++)
                        {
                            Vertices = (S3DVertex2TCoords*)mb->getVertices();
                            for(int j=0;j< VerticleCount; j++)
                            varray.push_back( Vertices[j].Pos * IrrToNewton * m_ISceneNode->getScale());
                        }
                    }break;
                };
            }

            Collision = NewtonCreateConvexHull(m_IrrNewtonWorld->GetNewtonWorld(), mb->getVertexCount(),&varray.pointer()->X ,sizeof(vector3df), NULL);
            m_ConvexHullModifier = NewtonCreateConvexHullModifier(m_IrrNewtonWorld->GetNewtonWorld(),Collision);
        } //END OF ID_CONVEXHULL
ImageImage
Site development -Rock and metal online
--- etcaptor.com ------freenetlife.com
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

sry for the noobish question, but how can i move my model? O.o
i was searching all the time, but couldn't do it...

i saw it in the tutorial, but it was really hard... isn't there any easy way to do?

Code: Select all

void _cdecl CGame::ApplyForceAndTorqueEvent (const NewtonBody* body) 
{ 
   float mass; 
   float Ixx; 
   float Iyy; 
   float Izz; 
   float force[3]; 
   float torque[3]; 

   NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz); 

   force[0] = 0.0f; 
   force[1] = NEWTON_GRAVITY * mass; 
   force[2] = 0.0f; 

   torque[0] = 0.0f; 
   torque[1] = 0.0f; 
   torque[2] = 0.0f; 

   NewtonBodyAddForce (body, force); 
   NewtonBodyAddTorque (body, torque); 
}
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

etcaptor wrote:Yes, will post it tonight when going home. Done:
Here is this part of code and debug screen with sydney.md2 animated mesh. You can use convexhull modifier for response to any bounding box changes.

Image

Code: Select all

//---------------------------------------------------------------------------
        case ID_CONVEXHULL:
Tip: Don't forget to test for and reject degenerate triangles.
etcaptor
Posts: 871
Joined: Fri Apr 09, 2004 10:32 pm
Location: Valhalla
Contact:

Post by etcaptor »

Yes, thanks.
ImageImage
Site development -Rock and metal online
--- etcaptor.com ------freenetlife.com
Post Reply