I started with the wiki ode tutorial and have sort of integrated parts of an ode demo.
Initially I was trying to use 'addCubeSceneNode()' and 'addSphereSceneNode()', but I got strange behaviour.
If I alter the following code to only generate cylinders then they don't seem to collide, but work fine in an assortment.
The most annoying thing is that some nodes just hang near the generation points and never disappear.
Code: Select all
#include <iostream>
#include <string>
#include <map>
#include <time.h>
#include <irrlicht.h>
#include <ode/ode.h>
using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
class node {
public:
dBodyID body;
dGeomID geom;
ISceneNode* snode;
int life;
node() { life = 0; }
node(std::string s) { life = 0; }
};
std::map <std::string, node*> nodes;
static dWorldID world;
static dSpaceID space;
static dJointGroupID contactgroup;
dGeomID geom_ground;
irr::core::vector3df rot;
int obj_id = 0;
bool keys[irr::KEY_KEY_CODES_COUNT];
int get_rand(int from, int range) { return rand() % range + from; }
void nearCallback(void* node, dGeomID o1, dGeomID o2)
{
int i=0;
dBodyID b1=dGeomGetBody(o1);
dBodyID b2=dGeomGetBody(o2);
int MAX_CONTACTS = 8;
if(b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact))return;
dContact contact[MAX_CONTACTS];
for(i=0;i<MAX_CONTACTS;++i)
{
contact[i].surface.mode=dContactBounce | dContactSoftCFM;
contact[i].surface.mu=dInfinity;
contact[i].surface.mu2=0;
contact[i].surface.bounce=.1;
contact[i].surface.bounce_vel=.1;
contact[i].surface.soft_cfm=.01;
}
int numc=dCollide(o1,o2,MAX_CONTACTS,&contact[0].geom,sizeof(dContact));
if(numc>0)
{
for(i=0;i<numc;i++)
{
dJointID c=dJointCreateContact(world,contactgroup,&contact[i]);
dJointAttach(c,b1,b2);
}
}
}
void setPosition(dGeomID geom)
{
dReal * ode_pos =(dReal*)dGeomGetPosition(geom);
ISceneNode *node = (ISceneNode*)dGeomGetData(geom);
vector3df pos((irr::f32)ode_pos[0],(irr::f32)ode_pos[1],(irr::f32)ode_pos[2]);
node->setPosition(pos);
dQuaternion result;
dGeomGetQuaternion(geom, result);
irr::core::quaternion quat(result[1],result[2],result[3],result[0]);
quat.toEuler(rot);
vector3df degrees(rot.X*180/PI,rot.Y*180/PI,rot.Z*180/PI);
node->setRotation(degrees);
}
void add_box(dWorldID &world,dSpaceID &space,ISceneNode* node,dBodyID &body,dGeomID &geom)
{
vector3df extend = (node->getBoundingBox()).getExtent();
vector3df pos=node->getPosition();
geom=dCreateBox(space,(dReal)extend.X,(dReal)extend.Y,(dReal)extend.Z);
dGeomSetPosition(geom,pos.X,pos.Y,pos.Z);
dGeomSetData(geom,node);
body=dBodyCreate(world);
dMass mass;
dMassSetBox(&mass,2.0,(dReal)extend.X,(dReal)extend.Y,(dReal)extend.Z);
dBodySetMass(body,&mass);
dGeomSetBody(geom,body);
dBodySetPosition(body,pos.X,pos.Y,pos.Z);
dBodySetData(body,node);
}
void add_sphere(dWorldID &world,dSpaceID &space,ISceneNode* node,dBodyID &body,dGeomID &geom)
{
vector3df pos=node->getPosition();
float RADIUS = 1.5f;
geom = dCreateSphere (space,RADIUS);
dGeomSetPosition(geom,pos.X,pos.Y,pos.Z);
dGeomSetData(geom,node);
body=dBodyCreate(world);
dMass mass;
dMassSetSphere(&mass,2.0,RADIUS);
dBodySetMass(body,&mass);
dGeomSetBody(geom,body);
dBodySetPosition(body,pos.X,pos.Y,pos.Z);
dBodySetData(body,node);
}
void add_cylinder(dWorldID &world,dSpaceID &space,ISceneNode* node,dBodyID &body,dGeomID &geom)
{
vector3df pos=node->getPosition();
float WMASS = 0.2f;
float RADIUS = 1.5f;
float HEIGHT = 2.0f;
geom = dCreateCylinder(space, RADIUS, HEIGHT);
dGeomSetPosition(geom,pos.X,pos.Y,pos.Z);
dGeomSetData(geom,node);
body=dBodyCreate(world);
dMass mass;
dMassSetCylinder (&mass,WMASS,3,RADIUS, HEIGHT);
dBodySetMass(body,&mass);
dGeomSetBody(geom,body);
dBodySetPosition(body,pos.X,pos.Y,pos.Z);
dBodySetData(body,node);
}
void add_obj(ISceneManager* smgr)
{
int type = get_rand(0, 3);
cout << "rand: " << type << endl;
std::string name = "obj_" + obj_id;
obj_id++;
nodes.insert(std::map<std::string,node*>::value_type(name, new node()));
IAnimatedMesh* mesh;
if(type==0) {
mesh = smgr->getMesh("media/box.x");
}
else if(type==1) {
mesh = smgr->getMesh("media/sphere.x");
}
else {
mesh = smgr->getMesh("media/cylinder.x");
}
nodes[name]->snode = smgr->addAnimatedMeshSceneNode( mesh );
nodes[name]->snode->setPosition(vector3df(0.0+get_rand(1, 5),20.0+get_rand(1, 5),-10+get_rand(1, 5)));
//nodes[name]->snode->setPosition(vector3df(0.0,20.0,-10));
//nodes[name]->snode->setScale(vector3df(0.25,0.25,0.25));
nodes[name]->snode->setMaterialFlag(EMF_LIGHTING, true);
nodes[name]->snode->getMaterial(0).Shininess = 20.0f;
nodes[name]->snode->getMaterial(0).SpecularColor.set(128,255,0,0);
nodes[name]->snode->getMaterial(0).AmbientColor.set(128,0,155,0);
nodes[name]->snode->getMaterial(0).DiffuseColor.set(128,128,0,0);
nodes[name]->snode->getMaterial(0).EmissiveColor.set(128,255,0,0);
nodes[name]->snode->setMaterialType( video::EMT_SOLID );
if(type==0) {
add_box(world,space,nodes[name]->snode,nodes[name]->body,nodes[name]->geom);
}
else if(type==1) {
add_sphere(world,space,nodes[name]->snode,nodes[name]->body,nodes[name]->geom);
}
else {
add_cylinder(world,space,nodes[name]->snode,nodes[name]->body,nodes[name]->geom);
}
}
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event) {
if(event.EventType == irr::EET_KEY_INPUT_EVENT){
keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
return false;
}
return false;
}
};
int handle_input(ISceneManager* smgr)
{
if(keys[KEY_KEY_W]) { }
if(keys[KEY_KEY_S]) { }
if(keys[KEY_KEY_A]) {
add_obj(smgr);
}
if(keys[KEY_KEY_D]) { }
if(keys[KEY_ESCAPE]) {
return 1;
}
return 0;
}
int main()
{
srand ( time(NULL) );
dInitODE();
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,-10.0,0);
dWorldSetCFM (world,1e-5);
dWorldSetAutoDisableFlag (world,1);
IrrlichtDevice *device = createDevice(EDT_OPENGL);
IVideoDriver* video = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
MyEventReceiver rv;
device->setEventReceiver(&rv);
for(int x=0; x<irr::KEY_KEY_CODES_COUNT; x++) keys[x] = false;
// LIGHTING
smgr->setAmbientLight(video::SColorf(0.3,0.3,0.3,1));
ILightSceneNode* light1 = smgr->addLightSceneNode( 0, core::vector3df(0,40,-20), video::SColorf(0.9f,0.9f,0.9f), 100.0f, 1 );
//We create a plane geom at level zero so the boxes won't drop off the screen.
geom_ground=dCreatePlane(space,0,1,0,1);
smgr->addCameraSceneNode(0, vector3df(0,20,-40), vector3df(0,5,0));
while(device->run() && device) {
if(handle_input(smgr)) {
device->closeDevice();
}
for( std::map<std::string, node*>::iterator ii=nodes.begin(); ii!=nodes.end(); ++ii)
{
node *n = (*ii).second;
setPosition(n->geom);
n->life++;
if(n->life>1000) {
dBodyDestroy (n->body);
dGeomDestroy (n->geom);
n->snode->remove();
nodes.erase(ii);
}
}
video->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
guienv->drawAll();
dSpaceCollide(space,0,&nearCallback);
dWorldQuickStep(world,0.025);
dJointGroupEmpty(contactgroup);
video->endScene();
}
dWorldDestroy(world);
dCloseODE();
device->drop();
return 0;
}
Code: Select all
Target = run
Sources = main.cpp
# general compiler settings
CPPFLAGS = -I../../include -I/usr/X11R6/include -I /home/ai/z_ode/ode-0.11.1/include
CXXFLAGS = -O3 -ffast-math
#CXXFLAGS = -g -Wall
#default target is Linux
all: all_linux
ifeq ($(HOSTTYPE), x86_64)
LIBSELECT=64
endif
# target specific settings
all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -lode
all_linux clean_linux: SYSTEM=Linux
all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm
all_win32 clean_win32: SYSTEM=Win32-gcc
all_win32 clean_win32: SUF=.exe
# name of the binary - only valid for targets which set SYSTEM
#DESTPATH = ../../bin/$(SYSTEM)/$(Target)$(SUF)
DESTPATH = $(Target)$(SUF)
all_linux all_win32:
$(warning Building...)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS)
clean: clean_linux clean_win32
$(warning Cleaning...)
clean_linux clean_win32:
@$(RM) $(DESTPATH)
.PHONY: all all_win32 clean clean_linux clean_win32