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;
}