#include "OdeWorld.h" #include #include #include #include using namespace std; #define WORLD_STEP 0.001 #define WHITESPACE " \t\r\n\f" static string trim(const string & orig) { string result = orig; size_t pos = result.find_first_not_of(WHITESPACE); if (pos == string::npos) { result = ""; } else { if (pos > 0) result = result.substr(pos, result.length() - pos); pos = result.find_last_not_of(WHITESPACE); if (pos < result.length() - 1) result = result.substr(0, pos + 1); } return result; } /* used by ODE to perform collision detection */ void OdeWorld_collide_callback(void * data, dGeomID o1, dGeomID o2) { const int maxNumContacts = 4; OdeWorld * ow = (OdeWorld *) data; static dContact contact[maxNumContacts]; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if ((b1 == b2) || (b1 && b2 && dAreConnected(b1, b2))) return; int num = dCollide(o1, o2, maxNumContacts, &contact[0].geom, sizeof(contact[0])); for (int i = 0; i < num; i++) { contact[i].surface.mode = dContactSlip1 | dContactSlip2 | dContactBounce | dContactSoftERP | dContactSoftCFM | dContactApprox1; contact[i].surface.mu = 0.5; contact[i].surface.slip1 = 0.0; contact[i].surface.slip2 = 0.0; contact[i].surface.soft_erp = 0.8; contact[i].surface.soft_cfm = 0.01; contact[i].surface.bounce = 0.0; dJointID joint = dJointCreateContact(ow->m_world, ow->m_contactJointGroup, contact + i); dJointAttach(joint, b1, b2); } } OdeWorld::OdeWorld() { m_world = dWorldCreate(); m_space = dHashSpaceCreate(0); m_contactJointGroup = dJointGroupCreate(0); setGravity(0, 0, -9.81); } OdeWorld::~OdeWorld() { dJointGroupDestroy(m_contactJointGroup); dSpaceDestroy(m_space); dWorldDestroy(m_world); } /* invokes ODE to do physics on our world */ void OdeWorld::step() { dSpaceCollide(m_space, this, OdeWorld_collide_callback); dWorldQuickStep(m_world, WORLD_STEP); dJointGroupEmpty(m_contactJointGroup); } vector OdeWorld::loadPhy(const std::string & path, dBodyID * body, bool is_static) { vector ret; ifstream ifs(path.c_str()); if (ifs.is_open()) { while (!ifs.eof()) { string line; getline(ifs, line); line = trim(line); if (line == "" || line[0] == '#') continue; size_t pos = line.find_first_of(WHITESPACE); if (pos == string::npos) continue; string type = line.substr(0, pos); pos = line.find("\"", pos); if (pos == string::npos) continue; size_t pos2 = line.find("\"", pos + 1); if (pos2 == string::npos) continue; string name = line.substr(pos + 1, pos2 - pos - 1); pos = pos2 + 1; vector args; for (;;) { pos = line.find_first_not_of(WHITESPACE, pos); if (pos == string::npos) break; pos2 = line.find_first_of(WHITESPACE, pos); string n = line.substr(pos, pos2 - pos); float f = atof(n.c_str()); args.push_back(f); if (pos2 == string::npos) break; pos = pos2 + 1; } if (type == "cube") { ret.push_back(addCube(name, is_static, body, args)); } else if (type == "sphere") { ret.push_back(addSphere(name, is_static, body, args)); } else if (type == "cylinder") { ret.push_back(addCylinder(name, is_static, body, args)); } else if (type == "plane") { ret.push_back(addPlane(name, is_static, body, args)); } } } return ret; } dGeomID OdeWorld::addCube(const string & name, bool is_static, dBodyID * body, const vector args) { if (args.size() != 9) return 0; dGeomID id = dCreateBox(0, args[0], args[1], args[2]); dMass mass; dMassSetBox(&mass, 1.0, args[0], args[1], args[2]); setupGeom(name, is_static, body, id, &mass, args[3], args[4], args[5], args[6], args[7], args[8]); return id; } dGeomID OdeWorld::addSphere(const string & name, bool is_static, dBodyID * body, const vector args) { if (args.size() != 4) return 0; dGeomID id = dCreateSphere(0, args[0]); dMass mass; dMassSetSphere(&mass, 1.0, args[0]); setupGeom(name, is_static, body, id, &mass, args[1], args[2], args[3], 0.0, 0.0, 0.0); return id; } dGeomID OdeWorld::addCylinder(const string & name, bool is_static, dBodyID * body, const vector args) { if (args.size() != 8) return 0; dGeomID id = dCreateCylinder(0, args[0], args[1]); dMass mass; dMassSetCylinder(&mass, 1.0, 3, args[0], args[1]); setupGeom(name, is_static, body, id, &mass, args[2], args[3], args[4], args[5], args[6], args[7]); return id; } dGeomID OdeWorld::addCCylinder(const string & name, bool is_static, dBodyID * body, const vector args) { if (args.size() != 8) return 0; dGeomID id = dCreateCCylinder(0, args[0], args[1]); dMass mass; dMassSetCappedCylinder(&mass, 1.0, 3, args[0], args[1]); setupGeom(name, is_static, body, id, &mass, args[2], args[3], args[4], args[5], args[6], args[7]); return id; } dGeomID OdeWorld::addPlane(const string & name, bool is_static, dBodyID * body, const vector args) { if (args.size() != 6) return 0; dMatrix3 r; dRFromEulerAngles(r, args[3], args[4], args[5]); dVector3 default_plane_direction = {0, 0, 1, 0}; dVector3 rotated_plane_direction; dMultiply0(rotated_plane_direction, default_plane_direction, r, 1, 3, 3); float a = rotated_plane_direction[0]; float b = rotated_plane_direction[1]; float c = rotated_plane_direction[2]; float d = a * args[0] + b * args[1] + c * args[2]; dGeomID id = dCreatePlane(m_space, a, b, c, d); return id; } void OdeWorld::setupGeom(const std::string & name, bool is_static, dBodyID * body, dGeomID geom, dMass * mass, float locx, float locy, float locz, float rotx, float roty, float rotz) { dMatrix3 rot; dRFromEulerAngles(rot, rotx, roty, rotz); dGeomSetRotation(geom, rot); dGeomSetPosition(geom, locx, locy, locz); if (!is_static) { /* attach the geometry to the body */ if (*body == 0) *body = dBodyCreate(m_world); dGeomId transform = dCreateGeomTransform(m_space); dGeomTransformSetGeom(transform, geom); dGeomTransformSetCleanup(transform, 1); dGeomSetBody(transform, *body); dMassRotate(mass, rot); dMassTranslate(mass, locx, locy, locz); dMass origmass; dBodyGetMass(*body, &origmass); dMassAdd(&origmass, mass); dBodySetMass(*body, &origmass); } } /* push an OpenGL matrix onto the matrix stack for a given * ODE body position and rotation */ void OdeWorld::pushTransform(const float pos[3], const float R[12]) { GLfloat matrix[16]; matrix[0] = R[0]; matrix[1] = R[4]; matrix[2] = R[8]; matrix[3] = 0; matrix[4] = R[1]; matrix[5] = R[5]; matrix[6] = R[9]; matrix[7] = 0; matrix[8] = R[2]; matrix[9] = R[6]; matrix[10] = R[10]; matrix[11] = 0; matrix[12] = pos[0]; matrix[13] = pos[1]; matrix[14] = pos[2]; matrix[15] = 1; glPushMatrix(); glMultMatrixf(matrix); } OdeWorld::Object::Object(bool is_static) { m_is_static = is_static; } void OdeWorld::Object::setPosition(double x, double y, double z) { if (m_is_static) { for (int i = 0, sz = m_geoms.size(); i < sz; i++) dGeomSetPosition(m_geoms[i], x, y, z); } else { if (m_body != 0) dBodySetPosition(m_body, x, y, z); } } void OdeWorld::Object::getPosition(double * x, double * y, double * z) { const dReal * pos = NULL; if (m_is_static) { if (m_geoms.size() > 0) pos = dGeomGetPosition(m_geoms[0]); } else { if (m_body != 0) pos = dBodyGetPosition(body); } if (pos != NULL) { *x = pos[0]; *y = pos[1]; *z = pos[2]; } }