Tutorial - Irrlicht Engine with Newton (triangle meshes tutorial)

From Newton Wiki
Jump to: navigation, search

Good day, dear Reader! Here is my first article about Irrlicht and Newton. Please, don't be too strict while reading and discussing it...

All needed comments are given within the code itself.

Please, enjoy ;)

Newton 2.35

This source was successfully built and runned with Vim, Irrlicht 1.7.2 and Newton 2.35, under Ubuntu 12.04.

The differences are minor and the results are the same while compiler does not throws any errors.

To compile this one i use these steps:

  1. Download irrlicht-1.7.2.zip
  2. Download newton-dynamics-2.35.rar
  3. Download irrnewttest1_models.zip
  4. Install Irrlicht:
    1. Copy the include/ dir to /usr/include/Irrlicht
    2. Copy the lib/Linux/libIrrlicht.a file to /usr/lib/
  5. Install Newton:
    1. Navigate to coreLibrary_200/projets/linux64
    2. Run make
    3. Copy the packages/dContainers/, packages/dCustomJoints/, packages/dMath/, packages/dScene/, packages/JointLibrary.h and packages/Newton.h to /usr/include/Newton
    4. Copy the coreLibrary_200/projets/linux64/libNewton.a to /usr/lib/
  6. Create, fulfill and save source file
  7. Navigate to the source file directory
  8. Run g++ irrnewttest1.cpp -o irrnewttest1.elf -I/usr/include/Newton/ -I/usr/include/Newton/dMath/ -I/usr/include/irrlicht/ -lIrrlicht -lNewton


In the Bash words:

unzip irrlicht-1.7.2.zip
unrar newton-dynamics-2.35.rar
unzip irrnewttest1_models.zip
cd irrlicht-1.7.2/
sudo mkdir /usr/include/Irrlicht
sudo cp -r irrlicht-1.7.2/include/* /usr/include/Irrlicht/
sudo cp lib/Linux/libIrrlicht.a /usr/lib/
cd ../newton-dynamics-2.35/
sudo mkdir /usr/include/Newton
sudo cp -r packages/dContainers/ packages/dCustomJoints/ packages/dMath/ packages/dScene/ packages/JointLibrary.h packages/Newton.h -t /usr/include/Newton
cd coreLibrary_200/projects/linux64/
make
sudo cp libNewton.a /usr/lib/
cd ~/
mkdir -p projects/gamedev/irrlicht
cp models/* projects/gamedev/irrlicht/
rm -r models/
cd projects/gamedev/irrlicht
vim irrnewttest1.cpp
# Go to the Insert mode (just hit i), fulfill the file, save it and quit Vim with :wq
g++ irrnewttest1.cpp -o irrnewttest1.elf -I/usr/include/Newton/ -I/usr/include/Newton/dMath/ -I/usr/include/irrlicht/  -lIrrlicht -lNewton
# Copy the media/ forlder here
./irrnewttest1.elf

So, here is the new source:

#include <Newton.h>

/*   To use these you should pass at least
 * "Newton/sdk/" and "Newton/sdk/Math/"
 * paths to your compiler command line
 */

#include <dVector.h>
#include <dMatrix.h>
#include <dMatrix.cpp>

/*
 *   Basic Irrlicht application heading:
 * irr header and namespace including 
 * to prevent irr::XXX::YYY constructions...
 * In a few words - "I'm too lazy for that..." =)
*/
#include <irrlicht.h>

using namespace irr;

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

/*
 *   Two more lazy-prevent instructions:
 * 1. passing library files to compiler
 * 2. disabling console window popup at start
 *
 *   These options will succeed if you are workin' 
 * under Windows only. Also you'll need to include
 * "Newton/sdk/AAA/BBB" path to your command line,
 * where AAA is "x32" or "x64" and BBB is "dll_@something@"
 * or "lib_@something@" (choose by your own will).
*/

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

    #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

/*
 *   These two functions are callbacks. They are called when
 * conditional action is performed. For example: you wake up
 * each morning when your alarm clock is shouting. Alarm
 * signal is a callback and the onset time you have set 
 * is a conditional action.
 *
 *   The first callback is executed when the physical body
 * changes its pose (position or rotation; I'm using this term since 
 * I was young and using PhysX =) ). Here we just set our
 * SceneNode position and rotation accordingly to physic body.
 * 
 *   Oh, and one more detail, I've forgot to tell about:
 * to speed-up our application, let's merge physic and 
 * graphic elements of model. We can assign some value
 * as a UserData for NewtonBody. If we set SceneNode
 * for each NewtonBody, we'll be able to easily update it 
 * simultaneosly.
*/

void SetTransformCallback(const NewtonBody* body, const dFloat* matrix, int threadIndex)
{
    ISceneNode* node = (ISceneNode*) NewtonBodyGetUserData(body);
    
    if (node)
    {
        matrix4 transform;
        transform.setM(matrix);

        node->setPosition(transform.getTranslation());
        node->setRotation(transform.getRotationDegrees());
    }
}

/*
 *   Here's another callback. It is executed when we are able
 * to apply some forces on our NewtonBody. Let's apply gravitation
 * to each registered in the NewtonWorld physic body.
 *
 *   Gravity is a body acceleration, calculated by formula:
 * a = m * g, where g = 9.8 m/sec in the direction of "down".
 *
 *   First of all we should get NewtonBody's inertion matrix - 
 * mass and some other values, which will probably be useless
 * for you for now. Then we calculate vector, equal to the
 * acceleration vector, described above.
*/

void ApplyForceAndTorqueCallback(const NewtonBody* body, dFloat timestep, int threadIndex) 
{ 
    dFloat Ixx, Iyy, Izz;
    dFloat mass;
 
    NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
 
    dVector gravityForce(0.0f, mass * -9.8f, 0.0f, 1.0f);
    NewtonBodySetForce(body, &gravityForce[0]);
}

/*
 *   This function will create NewtonBody with box collision
 * shape, based on certain SceneNode.
 *
 *   The body creation process is pretty simple: we create an
 * empty collision shape, calculate it's parameters, create
 * an instance of its, calculate its mass, inertia and other
 * params we are needed and then create actual body and 
 * "register" it within NewtonWorld.
 *
 *   Here is everything the same; just like I've described
 * above: we create an instance of NewtonBox shape, based
 * on node's AABB (Axes-Aligned Bounding Box) and then calculate
 * inertia matrix and register a new physic body.
*/

void CreateNewtonBox(NewtonWorld* world, ISceneNode *node, float mass, int shapeId = 0)
{
    NewtonCollision* collision;
 
    vector3df v1 = node->getBoundingBox().MinEdge;
    vector3df v2 = node->getBoundingBox().MaxEdge;

    dVector minBox(v1.X, v1.Y, v1.Z);
    dVector maxBox(v2.X, v2.Y, v2.Z);
 
    dVector size(maxBox - minBox);
    dVector origin((maxBox + minBox).Scale(0.5f));

    size.m_w = 1.0f;
    origin.m_w = 1.0f;
 
    dMatrix offset(GetIdentityMatrix());
    offset.m_posit = origin;
 
    collision = NewtonCreateBox(world, size.m_x, size.m_y, size.m_z, shapeId, &offset[0][0]);
 
    dVector inertia;
    NewtonBody* body;
 
    body = NewtonCreateBody(world, collision);
 
    NewtonBodySetUserData(body, node);
 
    dQuaternion q(node->getRotation().X, node->getRotation().Y, node->getRotation().Z, 1.f);
    dVector v(node->getPosition().X, node->getPosition().Y, node->getPosition().Z);

    dMatrix matrix(q, v);

    NewtonBodySetMatrix(body, &matrix[0][0]);
 
    NewtonConvexCollisionCalculateInertialMatrix(collision, &inertia[0], &origin[0]);   
 
    NewtonBodySetMassMatrix(body, mass, mass * inertia.m_x, mass * inertia.m_y, mass * inertia.m_z);
 
    NewtonBodySetCentreOfMass(body, &origin[0]);
 
    NewtonBodySetForceAndTorqueCallback(body, ApplyForceAndTorqueCallback);
 
    NewtonBodySetTransformCallback(body, SetTransformCallback);
}

/*
 *   Next three functions are used as supplemental for
 * one great (maybe not so GREAT, but useful enough =) ) function - 
 * creating trimesh (Triangle Mesh; Polygonal Mesh - physic model,
 * based on graphical mesh. It is usually used for creating levels
 * and static models, when physic model must correspond 1:1 to visible one).
 *
 *   Here we cycle through all mesh vertices and "pack" them into triangles.
 * When triangle is ready, we just add it to our collision shape.
 *
 *   There are three almost identical functions because of Irrlicht
 * mesh representation (not so Irrlicht as vendors and their formats =) ):
 * one can handle vertex only, vertex and its texture coordinates or 
 * vertex and its tangent. The difference is weak, so if you
 * want - you can merge these three functions into one,
 * simply switching between three differently typed arrays.
*/

void addMeshToTreeCollisionStandard(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df scale)
{
    vector3df vArray[3];

    S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();

    u16* mb_indices  = meshBuffer->getIndices();

    for (unsigned int j = 0; j < meshBuffer->getIndexCount(); j += 3)
    {
        int v1i = mb_indices[j + 0];
        int v2i = mb_indices[j + 1];
        int v3i = mb_indices[j + 2];

        vArray[0] = mb_vertices[v1i].Pos * scale.X;
        vArray[1] = mb_vertices[v2i].Pos * scale.Y;
        vArray[2] = mb_vertices[v3i].Pos * scale.Z;

        NewtonTreeCollisionAddFace(treeCollision, 3, &vArray[0].X, sizeof (vector3df), 1);
    }
}

void addMeshToTreeCollision2TCoords(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df scale)
{
    vector3df vArray[3];

    S3DVertex2TCoords* mb_vertices = (S3DVertex2TCoords*) meshBuffer->getVertices();

    u16* mb_indices  = meshBuffer->getIndices();

    for (unsigned int j = 0; j < meshBuffer->getIndexCount(); j += 3)
    {
        int v1i = mb_indices[j + 0];
        int v2i = mb_indices[j + 1];
        int v3i = mb_indices[j + 2];

        vArray[0] = mb_vertices[v1i].Pos * scale.X;
        vArray[1] = mb_vertices[v2i].Pos * scale.Y;
        vArray[2] = mb_vertices[v3i].Pos * scale.Z;

        NewtonTreeCollisionAddFace(treeCollision, 3, &vArray[0].X, sizeof (vector3df), 1);
    }
}

void addMeshToTreeCollisionTangents(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df scale)
{
    vector3df vArray[3];

    S3DVertexTangents* mb_vertices = (S3DVertexTangents*) meshBuffer->getVertices();

    u16* mb_indices  = meshBuffer->getIndices();

    for (unsigned int j = 0; j < meshBuffer->getIndexCount(); j += 3)
    {
        int v1i = mb_indices[j + 0];
        int v2i = mb_indices[j + 1];
        int v3i = mb_indices[j + 2];

        vArray[0] = mb_vertices[v1i].Pos * scale.X;
        vArray[1] = mb_vertices[v2i].Pos * scale.Y;
        vArray[2] = mb_vertices[v3i].Pos * scale.Z;

        NewtonTreeCollisionAddFace(treeCollision, 3, &vArray[0].X, sizeof (vector3df), 1);
    }
}

/*
 *   And here is this wonderful function..!
 *
 *   The difference between this function and the "CreateNewtonBox" function
 * is hidden in collision shape creation and weight-free body setting.
 * In a few words it will probably sounds like this: "If you are creating
 * trimesh, you should forget about it's dynamic". It is caused by very slow
 * polygonal collision tests. You see, when something is going to collide
 * with trimesh, engine should test huge amount of polygons to find out,
 * how this body will behave itself after collision. Besides, if your
 * model looks pretty good, it probably will contain thousands or even
 * millions of polygons. So, even creation process of such a "pretty" mesh will
 * store a "pretty" part of your system... 
 *
 *   Therefore I recommend you to use trimeshes only for static meshes, 
 * when engine doesn't need to calculate polygonal model position after 
 * its collision with something. So, you will not need the "mass"
 * parameter at all... 
 *
 *   And once more, in a few words this situation could be described as:
 * "Engine is too lazy for that..." =)
*/

void CreateNewtonMesh(NewtonWorld *world, IAnimatedMeshSceneNode *node)
{
    NewtonCollision *treeCollision;
    treeCollision = NewtonCreateTreeCollision(world, NULL);
    NewtonTreeCollisionBeginBuild(treeCollision);

    IMesh *mesh = node->getMesh();

    for (unsigned int i = 0; i < mesh->getMeshBufferCount(); i++)
    {
        IMeshBuffer *mb = mesh->getMeshBuffer(i);

        switch(mb->getVertexType())
        {
            case EVT_STANDARD:
                addMeshToTreeCollisionStandard(mb, treeCollision, node->getScale());
            break;

            case EVT_2TCOORDS:
                addMeshToTreeCollision2TCoords(mb, treeCollision, node->getScale());
            break;

            case EVT_TANGENTS:
                addMeshToTreeCollisionTangents(mb, treeCollision, node->getScale());
            break;

            default:
                printf("Newton error: Unknown vertex type in static mesh: %d\n", mb->getVertexType());
            break;
        }
    }
 
    NewtonTreeCollisionEndBuild(treeCollision, 1);

    NewtonBody* treeBody;
    treeBody = NewtonCreateBody(world, treeCollision);

    NewtonReleaseCollision(world, treeCollision);

    NewtonBodySetUserData(treeBody, node);
}

/*
 *   And here is the final stage of our demo coding - 
 * the "main" function. Here we need to initialize
 * Irrlicht application, Newton engine, create a
 * few bodies to show some simulations and advance
 * physics and graohics each frame.
 *
 *   The alghoritm is easy enough, so I'll not 
 * describe it... I'm too lazy =)
*/

int main()
{
    IrrlichtDevice *device =
        createDevice( EDT_OPENGL, dimension2d<u32>(640, 480), 16,
            false, false, false, 0);

    if (!device)
        return 1;

    NewtonWorld* World;
    World = NewtonCreate();
    NewtonSetPlatformArchitecture(World, 0);

    dVector minSize(-500.0f, -500.0f, -500.0f);
    dVector maxSize(500.0f, 500.0f, 500.0f);
    NewtonSetWorldSize(World, &minSize[0], &maxSize[0]);
    NewtonSetSolverModel(World, 1);

    device->setWindowCaption(L"My Demo");

    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();

    IAnimatedMesh* mesh = smgr->getMesh("wolftris.md2");

    if (!mesh)
    {
        device->drop();
        return 1;
    }

    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
    
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        node->setMD2Animation(EMAT_STAND);
        node->setMaterialTexture(0, driver->getTexture("wolfskin.jpg"));
        node->setPosition(vector3df(0, 150, 0));
    }

    IAnimatedMesh *levelMesh = smgr->getMesh("level.3ds");
    IAnimatedMeshSceneNode* level = smgr->addAnimatedMeshSceneNode(levelMesh);
    
    if (level)
        level->setMaterialFlag(EMF_LIGHTING, false);

    CreateNewtonBox(World, node, 1.f);
    CreateNewtonMesh(World, level);

    smgr->addCameraSceneNodeFPS();
    device->getCursorControl()->setVisible(false);

    while(device->run())
    {
        int fps = driver->getFPS();

        NewtonUpdate(World, 1.f / (float) fps);

        driver->beginScene(true, true, SColor(255,100,101,140));

        smgr->drawAll();
        guienv->drawAll();

        stringw title(L"My Demo [");
        title += fps;
        title += L" FPS]";

        device->setWindowCaption(title.c_str());

        driver->endScene();
    }

    device->drop();

    NewtonDestroyAllBodies(World);
    NewtonDestroy(World);

    return 0;
}

Newton 2.13

This code was successfully compiled, runned and tested with Microsoft Visual Studio 2009 Express, Irrlicht 1.7.1 and Newton 2.13.

#include <Newton.h>

/*   To use these you should pass at least
 * "Newton/sdk/" and "Newton/sdk/Math/"
 * paths to your compiler command line
 */

#include <dVector.h>
#include <dMatrix.h>
#include <dMatrix.cpp>

/*
 *   Basic Irrlicht application heading:
 * irr header and namespace including 
 * to prevent irr::XXX::YYY constructions...
 * In a few words - "I'm too lazy for that..." =)
*/
#include <irrlicht.h>

using namespace irr;

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

/*
 *   Two more lazy-prevent instructions:
 * 1. passing library files to compiler
 * 2. disabling console window popup at start
 *
 *   These options will succeed if you are workin' 
 * under Windows only. Also you'll need to include
 * "Newton/sdk/AAA/BBB" path to your command line,
 * where AAA is "x32" or "x64" and BBB is "dll_@something@"
 * or "lib_@something@" (choose by your own will).
*/

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

	#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

/*
 *   These two functions are callbacks. They are called when
 * conditional action is performed. For example: you wake up
 * each morning when your alarm clock is shouting. Alarm
 * signal is a callback and the onset time you have set 
 * is a conditional action.
 *
 *   The first callback is executed when the physical body
 * changes its pose (position or rotation; I'm using this term since 
 * I was young and using PhysX =) ). Here we just set our
 * SceneNode position and rotation accordingly to physic body.
 * 
 *   Oh, and one more detail, I've forgot to tell about:
 * to speed-up our application, let's merge physic and 
 * graphic elements of model. We can assign some value
 * as a UserData for NewtonBody. If we set SceneNode
 * for each NewtonBody, we'll be able to easily update it 
 * simultaneosly.
*/

void SetTransformCallback(const NewtonBody* body, const dFloat* matrix, int threadIndex)
{
	ISceneNode* node = (ISceneNode*) NewtonBodyGetUserData(body);
	
	if (node)
	{
		matrix4 transform;
		transform.setM(matrix);

		node->setPosition(transform.getTranslation());
		node->setRotation(transform.getRotationDegrees());
	}
}

/*
 *   Here's another callback. It is executed when we are able
 * to apply some forces on our NewtonBody. Let's apply gravitation
 * to each registered in the NewtonWorld physic body.
 *
 *   Gravity is a body acceleration, calculated by formula:
 * a = m * g, where g = 9.8 m/sec in the direction of "down".
 *
 *   First of all we should get NewtonBody's inertion matrix - 
 * mass and some other values, which will probably be useless
 * for you for now. Then we calculate vector, equal to the
 * acceleration vector, described above.
*/

void ApplyForceAndTorqueCallback(const NewtonBody* body, dFloat timestep, int threadIndex) 
{ 
   	dFloat Ixx, Iyy, Izz;
	dFloat mass;
 
	NewtonBodyGetMassMatrix(body, &mass, &Ixx, &Iyy, &Izz);
 
	dVector gravityForce(0.0f, mass * -9.8f, 0.0f, 1.0f);
	NewtonBodySetForce(body, &gravityForce[0]);
}

/*
 *   This function will create NewtonBody with box collision
 * shape, based on certain SceneNode.
 *
 *   The body creation process is pretty simple: we create an
 * empty collision shape, calculate it's parameters, create
 * an instance of its, calculate its mass, inertia and other
 * params we are needed and then create actual body and 
 * "register" it within NewtonWorld.
 *
 *   Here is everything the same; just like I've described
 * above: we create an instance of NewtonBox shape, based
 * on node's AABB (Axes-Aligned Bounding Box) and then calculate
 * inertia matrix and register a new physic body.
*/

void CreateNewtonBox(NewtonWorld* world, ISceneNode *node, float mass, int shapeId = 0)
{
	NewtonCollision* collision;
 
	vector3df v1 = node->getBoundingBox().MinEdge;
	vector3df v2 = node->getBoundingBox().MaxEdge;

	dVector minBox(v1.X, v1.Y, v1.Z);
	dVector maxBox(v2.X, v2.Y, v2.Z);
 
	dVector size(maxBox - minBox);
	dVector origin((maxBox + minBox).Scale(0.5f));

	size.m_w = 1.0f;
	origin.m_w = 1.0f;
 
	dMatrix offset(GetIdentityMatrix());
	offset.m_posit = origin;
 
	collision = NewtonCreateBox(world, size.m_x, size.m_y, size.m_z, shapeId, &offset[0][0]);
 
	dVector inertia;
	NewtonBody* body;
 
	body = NewtonCreateBody(world, collision);
 
	NewtonBodySetUserData(body, node);
 
	dQuaternion q(node->getRotation().X, node->getRotation().Y, node->getRotation().Z, 1.f);
	dVector v(node->getPosition().X, node->getPosition().Y, node->getPosition().Z);

	dMatrix matrix(q, v);

	NewtonBodySetMatrix(body, &matrix[0][0]);
 
	NewtonConvexCollisionCalculateInertialMatrix(collision, &inertia[0], &origin[0]);	
 
	NewtonBodySetMassMatrix(body, mass, mass * inertia.m_x, mass * inertia.m_y, mass * inertia.m_z);
 
	NewtonBodySetCentreOfMass(body, &origin[0]);
 
	NewtonBodySetForceAndTorqueCallback(body, ApplyForceAndTorqueCallback);
 
	NewtonBodySetTransformCallback(body, SetTransformCallback);
}

/*
 *   Next three functions are used as supplemental for
 * one great (maybe not so GREAT, but useful enough =) ) function - 
 * creating trimesh (Triangle Mesh; Polygonal Mesh - physic model,
 * based on graphical mesh. It is usually used for creating levels
 * and static models, when physic model must correspond 1:1 to visible one).
 *
 *   Here we cycle through all mesh vertices and "pack" them into triangles.
 * When triangle is ready, we just add it to our collision shape.
 *
 *   There are three almost identical functions because of Irrlicht
 * mesh representation (not so Irrlicht as vendors and their formats =) ):
 * one can handle vertex only, vertex and its texture coordinates or 
 * vertex and its tangent. The difference is weak, so if you
 * want - you can merge these three functions into one,
 * simply switching between three differently typed arrays.
*/

void addMeshToTreeCollisionStandard(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df scale)
{
	vector3df vArray[3];

	S3DVertex* mb_vertices = (S3DVertex*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	for (unsigned int j = 0; j < meshBuffer->getIndexCount(); j += 3)
	{
		int v1i = mb_indices[j + 0];
		int v2i = mb_indices[j + 1];
		int v3i = mb_indices[j + 2];

		vArray[0] = mb_vertices[v1i].Pos * scale.X;
		vArray[1] = mb_vertices[v2i].Pos * scale.Y;
		vArray[2] = mb_vertices[v3i].Pos * scale.Z;

		NewtonTreeCollisionAddFace(treeCollision, 3, &vArray[0].X, sizeof (vector3df), 1);
	}
}

void addMeshToTreeCollision2TCoords(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df scale)
{
	vector3df vArray[3];

	S3DVertex2TCoords* mb_vertices = (S3DVertex2TCoords*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	for (unsigned int j = 0; j < meshBuffer->getIndexCount(); j += 3)
	{
		int v1i = mb_indices[j + 0];
		int v2i = mb_indices[j + 1];
		int v3i = mb_indices[j + 2];

		vArray[0] = mb_vertices[v1i].Pos * scale.X;
		vArray[1] = mb_vertices[v2i].Pos * scale.Y;
		vArray[2] = mb_vertices[v3i].Pos * scale.Z;

		NewtonTreeCollisionAddFace(treeCollision, 3, &vArray[0].X, sizeof (vector3df), 1);
	}
}

void addMeshToTreeCollisionTangents(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df scale)
{
	vector3df vArray[3];

	S3DVertexTangents* mb_vertices = (S3DVertexTangents*) meshBuffer->getVertices();

	u16* mb_indices  = meshBuffer->getIndices();

	for (unsigned int j = 0; j < meshBuffer->getIndexCount(); j += 3)
	{
		int v1i = mb_indices[j + 0];
		int v2i = mb_indices[j + 1];
		int v3i = mb_indices[j + 2];

		vArray[0] = mb_vertices[v1i].Pos * scale.X;
		vArray[1] = mb_vertices[v2i].Pos * scale.Y;
		vArray[2] = mb_vertices[v3i].Pos * scale.Z;

		NewtonTreeCollisionAddFace(treeCollision, 3, &vArray[0].X, sizeof (vector3df), 1);
	}
}

/*
 *   And here is this wonderful function..!
 *
 *   The difference between this function and the "CreateNewtonBox" function
 * is hidden in collision shape creation and weight-free body setting.
 * In a few words it will probably sounds like this: "If you are creating
 * trimesh, you should forget about it's dynamic". It is caused by very slow
 * polygonal collision tests. You see, when something is going to collide
 * with trimesh, engine should test huge amount of polygons to find out,
 * how this body will behave itself after collision. Besides, if your
 * model looks pretty good, it probably will contain thousands or even
 * millions of polygons. So, even creation process of such a "pretty" mesh will
 * store a "pretty" part of your system... 
 *
 *   Therefore I recommend you to use trimeshes only for static meshes, 
 * when engine doesn't need to calculate polygonal model position after 
 * its collision with something. So, you will not need the "mass"
 * parameter at all... 
 *
 *   And once more, in a few words this situation could be described as:
 * "Engine is too lazy for that..." =)
*/

void CreateNewtonMesh(NewtonWorld *world, IAnimatedMeshSceneNode *node)
{
	NewtonCollision *treeCollision;
	treeCollision = NewtonCreateTreeCollision(world, NULL);
	NewtonTreeCollisionBeginBuild(treeCollision);

	IMesh *mesh = node->getMesh();

	for (unsigned int i = 0; i < mesh->getMeshBufferCount(); i++)
	{
		IMeshBuffer *mb = mesh->getMeshBuffer(i);

		switch(mb->getVertexType())
		{
			case EVT_STANDARD:
				addMeshToTreeCollisionStandard(mb, treeCollision, node->getScale());
			break;

			case EVT_2TCOORDS:
				addMeshToTreeCollision2TCoords(mb, treeCollision, node->getScale());
			break;

			case EVT_TANGENTS:
				addMeshToTreeCollisionTangents(mb, treeCollision, node->getScale());
			break;

			default:
				printf("Newton error: Unknown vertex type in static mesh: %d\n", mb->getVertexType());
			break;
		}
	}
 
	NewtonTreeCollisionEndBuild(treeCollision, 1);

	NewtonBody* treeBody;
	treeBody = NewtonCreateBody(world, treeCollision);

	NewtonReleaseCollision(world, treeCollision);

	NewtonBodySetUserData(treeBody, node);
}

/*
 *   And here is the final stage of our demo coding - 
 * the "main" function. Here we need to initialize
 * Irrlicht application, Newton engine, create a
 * few bodies to show some simulations and advance
 * physics and graohics each frame.
 *
 *   The alghoritm is easy enough, so I'll not 
 * describe it... I'm too lazy =)
*/

int main()
{
	IrrlichtDevice *device =
		createDevice( EDT_OPENGL, dimension2d<u32>(640, 480), 16,
			false, false, false, 0);

	if (!device)
		return 1;

	NewtonWorld* World;
	World = NewtonCreate();
	NewtonSetPlatformArchitecture(World, 0);

	dVector minSize(-500.0f, -500.0f, -500.0f);
	dVector maxSize(500.0f, 500.0f, 500.0f);
	NewtonSetWorldSize(World, &minSize[0], &maxSize[0]);
	NewtonSetSolverModel(World, 1);

	device->setWindowCaption(L"My Demo");

	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	IGUIEnvironment* guienv = device->getGUIEnvironment();

	IAnimatedMesh* mesh = smgr->getMesh("wolftris.md2");

	if (!mesh)
	{
		device->drop();
		return 1;
	}

	IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
	
	if (node)
	{
		node->setMaterialFlag(EMF_LIGHTING, false);
		node->setMD2Animation(EMAT_STAND);
		node->setMaterialTexture(0, driver->getTexture("wolfskin.jpg"));
		node->setPosition(vector3df(0, 150, 0));
	}

	IAnimatedMesh *levelMesh = smgr->getMesh("level.3ds");
	IAnimatedMeshSceneNode* level = smgr->addAnimatedMeshSceneNode(levelMesh);
	
	if (level)
		level->setMaterialFlag(EMF_LIGHTING, false);

	CreateNewtonBox(World, node, 1.f);
	CreateNewtonMesh(World, level);

	smgr->addCameraSceneNodeFPS();
	device->getCursorControl()->setVisible(false);

	while(device->run())
	{
		int fps = driver->getFPS();

		NewtonUpdate(World, 1.f / (float) fps);

		driver->beginScene(true, true, SColor(255,100,101,140));

		smgr->drawAll();
		guienv->drawAll();

		stringw title(L"My Demo [");
		title += fps;
		title += L" FPS]";

		device->setWindowCaption(title.c_str());

		driver->endScene();
	}

	device->drop();

	NewtonDestroyAllBodies(World);
	NewtonDestroy(World);

	return 0;
}

Here is screenshot (I have used wolf.md2 as a box model and level.3ds as level mesh):

MyIrrNewtDemoScreen1.png