import svn:externals

This commit is contained in:
Josh Holtrop 2010-12-19 00:11:13 -05:00
parent d3da66da4b
commit 7b057bcf86
17 changed files with 2275 additions and 0 deletions

88
FileLoader/FileLoader.h Normal file
View File

@ -0,0 +1,88 @@
#ifndef FILELOADER_H
#define FILELOADER_H FILELOADER_H
#include <string>
#include <iostream>
class FileLoader
{
public:
class Path
{
public:
std::string fullPath;
std::string shortPath;
Path() { }
Path(const std::string & full_path,
const std::string & short_path)
: fullPath(full_path), shortPath(short_path) { }
std::string toString() const
{
std::string ret;
if (shortPath != "")
ret += shortPath + ",";
if (fullPath != "")
ret += fullPath;
return ret;
}
};
class Buffer
{
public:
char * data;
int size;
Buffer(int sz)
{
size = sz;
data = new char[size];
_refcnt = new int;
*_refcnt = 1;
m_alloced = true;
}
Buffer(char * data, int sz)
{
size = sz;
this->data = data;
m_alloced = false;
}
void copy(const Buffer & other)
{
data = other.data;
size = other.size;
m_alloced = other.m_alloced;
if (m_alloced)
{
_refcnt = other._refcnt;
(*_refcnt)++;
}
}
Buffer(const Buffer & other) { copy(other); }
Buffer & operator=(const Buffer & other)
{
copy(other);
return *this;
}
~Buffer()
{
if (m_alloced)
{
(*_refcnt)--;
if (*_refcnt < 1)
{
delete _refcnt;
delete data;
}
}
}
protected:
int * _refcnt;
bool m_alloced;
};
virtual int getSize(const Path & path) = 0;
virtual Buffer load(const Path & path) = 0;
};
#endif

12
OdeWorld/Makefile Normal file
View File

@ -0,0 +1,12 @@
TARGET := OdeWorld.o
SOURCES := $(wildcard *.cc)
HEADERS := $(wildcard *.h)
all: $(TARGET)
$(TARGET): $(SOURCES) $(HEADERS)
$(CXX) -c -o $@ $(CXXFLAGS) $(SOURCES)
clean:
-rm -f *~ *.o

660
OdeWorld/OdeWorld.cc Normal file
View File

@ -0,0 +1,660 @@
#include "OdeWorld.h"
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm> /* std::sort() */
#include <GL/gl.h>
using namespace std;
#define WORLD_STEP 0.001
/* used by ODE to perform collision detection */
void OdeWorld_collide_callback(void * data, dGeomID o1, dGeomID o2)
{
const int maxNumContacts = 4;
static dContact contact[maxNumContacts];
OdeWorld * ow = (OdeWorld *) data;
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.1;
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);
}
}
void OdeWorld_pick_collide_callback(void * data, dGeomID o1, dGeomID o2)
{
dContactGeom contact_geom;
OdeWorld * ow = (OdeWorld *) data;
int num = dCollide(o1, o2, 1, &contact_geom, sizeof(contact_geom));
if (num > 0)
{
dGeomID other = o1 == ow->m_pick_ray ? o2 : o1;
ow->m_pick_points.push_back(
new OdeWorld::PickedObject(other, contact_geom));
}
}
OdeWorld::OdeWorld()
{
m_world = dWorldCreate();
dWorldSetAutoDisableFlag(m_world, 1);
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);
}
OdeWorld::Object * OdeWorld::createObject(bool is_static, float scale)
{
return new Object(is_static, this, m_world, m_space, scale);
}
/* push an OpenGL matrix onto the matrix stack for a given
* ODE body position and rotation */
void OdeWorld::pushTransform(const dReal * pos, const dReal * R)
{
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);
}
dBodyID OdeWorld::createBody()
{
dBodyID id = dBodyCreate(m_world);
m_bodies[id] = 1;
return id;
}
void OdeWorld::enableAllBodies()
{
for (std::map<dBodyID, int>::iterator it = m_bodies.begin();
it != m_bodies.end();
it++)
{
dBodyEnable(it->first);
}
}
dJointID OdeWorld::createAMotor(dBodyID b1, dBodyID b2)
{
dJointID j = dJointCreateAMotor(m_world, 0);
dJointAttach(j, b1, b2);
return j;
}
dJointID OdeWorld::createHinge(dBodyID b1, dBodyID b2,
dReal anchor_x, dReal anchor_y, dReal anchor_z,
dReal axis_x, dReal axis_y, dReal axis_z)
{
dJointID j = dJointCreateHinge(m_world, 0);
dJointAttach(j, b1, b2);
dJointSetHingeAnchor(j, anchor_x, anchor_y, anchor_z);
dJointSetHingeAxis(j, axis_x, axis_y, axis_z);
return j;
}
static bool RPPickedObjectComparator(const refptr<OdeWorld::PickedObject> & one,
const refptr<OdeWorld::PickedObject> & two)
{
return one->dist < two->dist;
}
refptr< vector< OdeWorld::PickedObjectRef > > OdeWorld::pickObjects(
float start_x, float start_y, float start_z,
float dir_x, float dir_y, float dir_z)
{
m_pick_ray = dCreateRay(0, dInfinity);
dGeomRaySet(m_pick_ray, start_x, start_y, start_z, dir_x, dir_y, dir_z);
m_pick_points.clear();
dSpaceCollide2(m_pick_ray, (dGeomID) m_space,
this, OdeWorld_pick_collide_callback);
std::sort(m_pick_points.begin(), m_pick_points.end(),
RPPickedObjectComparator);
dGeomDestroy(m_pick_ray);
return new vector<OdeWorld::PickedObjectRef>(m_pick_points);
}
OdeWorld::PickedObjectRef OdeWorld::pickOne(
float start_x, float start_y, float start_z,
float dir_x, float dir_y, float dir_z,
OdeWorld::Object * o)
{
dGeomID pick_ray = dCreateRay(0, dInfinity);
dGeomRaySet(pick_ray, start_x, start_y, start_z, dir_x, dir_y, dir_z);
PickedObjectRef por;
bool found_one = false;
dContactGeom contact_geom;
for (vector<dGeomID>::iterator it = o->getGeoms().begin();
it != o->getGeoms().end();
it++)
{
dGeomID g = *it;
int num = dCollide(pick_ray, g, 1, &contact_geom, sizeof(contact_geom));
if (num > 0 && (!found_one || contact_geom.depth < por->dist))
{
por = new OdeWorld::PickedObject(g, contact_geom);
found_one = true;
}
}
dGeomDestroy(pick_ray);
return por;
}
void OdeWorld::destroyBody(dBodyID body)
{
m_bodies.erase(body);
dBodyDestroy(body);
enableAllBodies();
}
OdeWorld::Object::Object(bool is_static, OdeWorld * ode_world,
dWorldID world, dSpaceID space, float scale)
{
m_is_static = is_static;
m_world = world;
m_space = space;
m_body = 0;
m_scale = scale;
m_ode_world = ode_world;
dMassSetZero(&m_mass);
for (int i = 0; i < 3; i++)
m_position[i] = 0.0;
for (int j = 0; j < 3; j++)
for (int i = 0; i < 4; i++)
m_rotation[j * 4 + i] = (j == i) ? 1.0 : 0.0;
}
OdeWorld::Object::Object(const OdeWorld::Object & orig)
{
m_is_static = orig.m_is_static;
m_world = orig.m_world;
m_space = orig.m_space;
m_scale = orig.m_scale;
m_ode_world = orig.m_ode_world;
for (int i = 0; i < 3; i++)
m_position[i] = orig.m_position[i];
for (int i = 0; i < 12; i++)
m_rotation[i] = orig.m_rotation[i];
/* make a copy of the ODE body */
if (orig.m_body != 0)
{
m_body = m_ode_world->createBody();
m_mass = orig.m_mass;
dBodySetMass(m_body, &m_mass);
const dReal * pos = dBodyGetPosition(orig.m_body);
dBodySetPosition(m_body, pos[0], pos[1], pos[2]);
const dReal * rot = dBodyGetRotation(orig.m_body);
dBodySetRotation(m_body, rot);
dBodySetAutoDisableFlag(m_body,
dBodyGetAutoDisableFlag(orig.m_body));
dBodySetAutoDisableLinearThreshold(m_body,
dBodyGetAutoDisableLinearThreshold(orig.m_body));
dBodySetAutoDisableAngularThreshold(m_body,
dBodyGetAutoDisableAngularThreshold(orig.m_body));
dBodySetAutoDisableSteps(m_body,
dBodyGetAutoDisableSteps(orig.m_body));
dBodySetAutoDisableTime(m_body,
dBodyGetAutoDisableTime(orig.m_body));
int finite_rotation_mode = dBodyGetFiniteRotationMode(orig.m_body);
dBodySetFiniteRotationMode(m_body, finite_rotation_mode);
if (finite_rotation_mode)
{
dVector3 finite_rotation_axis;
dBodyGetFiniteRotationAxis(orig.m_body, finite_rotation_axis);
dBodySetFiniteRotationAxis(m_body,
finite_rotation_axis[0],
finite_rotation_axis[1],
finite_rotation_axis[2]);
}
dBodySetGravityMode(m_body, dBodyGetGravityMode(orig.m_body));
}
else
{
m_body = 0;
}
/* make a copy of the ODE geoms */
for (int i = 0, sz = orig.m_geoms.size(); i < sz; i++)
{
m_geoms.push_back(cloneGeom(orig.m_geoms[i], m_body));
}
}
OdeWorld::Object::~Object()
{
for (int i = 0, sz = m_geoms.size(); i < sz; i++)
dGeomDestroy(m_geoms[i]);
if (m_body != 0)
m_ode_world->destroyBody(m_body);
}
dGeomID OdeWorld::Object::cloneGeom(dGeomID geom, dBodyID body)
{
dGeomID id = 0;
dSpaceID space = dGeomGetSpace(geom);
switch (dGeomGetClass(geom))
{
case dSphereClass:
id = dCreateSphere(space, dGeomSphereGetRadius(geom));
break;
case dBoxClass:
{
dVector3 size;
dGeomBoxGetLengths(geom, size);
id = dCreateBox(space, size[0], size[1], size[2]);
}
break;
case dCylinderClass:
{
dReal radius, length;
dGeomCylinderGetParams(geom, &radius, &length);
id = dCreateCylinder(space, radius, length);
}
break;
case dCapsuleClass:
{
dReal radius, length;
dGeomCapsuleGetParams(geom, &radius, &length);
id = dCreateCapsule(space, radius, length);
}
break;
case dPlaneClass:
{
dVector4 params;
dGeomPlaneGetParams(geom, params);
id = dCreatePlane(space,
params[0], params[1], params[2], params[3]);
}
break;
case dGeomTransformClass:
{
dGeomID old_inner_geom = dGeomTransformGetGeom(geom);
dGeomID new_inner_geom = cloneGeom(old_inner_geom, body);
if (new_inner_geom != 0)
{
id = dCreateGeomTransform(space);
dGeomTransformSetGeom(id, new_inner_geom);
dGeomTransformSetCleanup(id,
dGeomTransformGetCleanup(geom));
dGeomTransformSetInfo(id, dGeomTransformGetInfo(geom));
}
}
break;
case dRayClass:
case dTriMeshClass:
case dSimpleSpaceClass:
case dHashSpaceClass:
/* unsupported for cloning */
break;
}
if (id != 0)
{
if (dGeomGetBody(geom) != 0)
{
/* if the original geom was attached to a body
* (i.e., a non-static geom), then attach it to the new body */
dGeomSetBody(id, body);
}
else if (dGeomGetClass(id) != dPlaneClass)
{
/* if the original geom was static, then copy the
* position and rotation to the new geom */
const dReal * pos = dGeomGetPosition(geom);
const dReal * rot = dGeomGetRotation(geom);
dGeomSetPosition(id, pos[0], pos[1], pos[2]);
dGeomSetRotation(id, rot);
}
dGeomSetData(id, dGeomGetData(geom));
}
return id;
}
bool OdeWorld::Object::addBox(refptr< std::vector<float> > args)
{
if (args->size() != 9)
return false;
dGeomID id = dCreateBox(0,
m_scale * (*args)[0],
m_scale * (*args)[1],
m_scale * (*args)[2]);
dGeomSetData(id, this);
dMass mass;
dMassSetBox(&mass, 1.0,
m_scale * (*args)[0],
m_scale * (*args)[1],
m_scale * (*args)[2]);
setupGeom(id, &mass,
(*args)[3], (*args)[4], (*args)[5],
(*args)[6], (*args)[7], (*args)[8]);
return true;
}
bool OdeWorld::Object::addSphere(refptr< std::vector<float> > args)
{
if (args->size() != 4)
return false;
dGeomID id = dCreateSphere(0, m_scale * (*args)[0]);
dGeomSetData(id, this);
dMass mass;
dMassSetSphere(&mass, 1.0, m_scale * (*args)[0]);
setupGeom(id, &mass,
(*args)[1], (*args)[2], (*args)[3],
0.0, 0.0, 0.0);
return true;
}
bool OdeWorld::Object::addCylinder(refptr< std::vector<float> > args)
{
if (args->size() != 8)
return false;
dGeomID id = dCreateCylinder(0, m_scale * (*args)[0], m_scale * (*args)[1]);
dGeomSetData(id, this);
dMass mass;
dMassSetCylinder(&mass, 1.0, 3, m_scale * (*args)[0], m_scale * (*args)[1]);
setupGeom(id, &mass,
(*args)[2], (*args)[3], (*args)[4],
(*args)[5], (*args)[6], (*args)[7]);
return true;
}
bool OdeWorld::Object::addCapsule(refptr< std::vector<float> > args)
{
if (args->size() != 8)
return false;
dGeomID id = dCreateCapsule(0,
m_scale * (*args)[0], m_scale * (*args)[1]);
dGeomSetData(id, this);
dMass mass;
dMassSetCapsule(&mass, 1.0, 3, m_scale * (*args)[0],
m_scale * (*args)[1]);
setupGeom(id, &mass,
(*args)[2], (*args)[3], (*args)[4],
(*args)[5], (*args)[6], (*args)[7]);
return true;
}
bool OdeWorld::Object::addPlane(refptr< std::vector<float> > args)
{
float a, b, c, d;
if (args->size() == 6)
{
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);
a = rotated_plane_direction[0];
b = rotated_plane_direction[1];
c = rotated_plane_direction[2];
d = m_scale * (a * (*args)[0] + b * (*args)[1] + c * (*args)[2]);
}
else if (args->size() == 4)
{
a = (*args)[0];
b = (*args)[1];
c = (*args)[2];
d = (*args)[3];
}
else
{
return false;
}
dGeomID id = dCreatePlane(m_space, a, b, c, d);
dGeomSetData(id, this);
m_geoms.push_back(id);
return true;
}
void OdeWorld::Object::setupGeom(dGeomID geom, dMass * mass,
float locx, float locy, float locz,
float rotx, float roty, float rotz)
{
locx = m_scale * locx;
locy = m_scale * locy;
locz = m_scale * locz;
dMatrix3 rot;
dRFromEulerAngles(rot, rotx, roty, rotz);
dGeomSetRotation(geom, rot);
dGeomSetPosition(geom, locx, locy, locz);
dGeomID transform = dCreateGeomTransform(m_space);
dGeomTransformSetCleanup(transform, 1);
dGeomTransformSetInfo(transform, 1);
dGeomTransformSetGeom(transform, geom);
dGeomSetData(transform, this);
m_geoms.push_back(transform);
if (!m_is_static)
{
/* attach the geometry to the body */
if (m_body == 0)
m_body = m_ode_world->createBody();
dGeomSetBody(transform, m_body);
dMassRotate(mass, rot);
dMassTranslate(mass, locx, locy, locz);
dMassAdd(&m_mass, mass);
}
}
const dReal * OdeWorld::Object::getPosition()
{
if (m_body != 0)
{
return dBodyGetPosition(m_body);
}
else if (m_geoms.size() > 0)
{
if (dGeomGetClass(m_geoms[0]) != dPlaneClass)
return dGeomGetPosition(m_geoms[0]);
}
return m_position;
}
const dReal * OdeWorld::Object::getRotation()
{
if (m_body != 0)
{
return dBodyGetRotation(m_body);
}
else if (m_geoms.size() > 0)
{
if (dGeomGetClass(m_geoms[0]) != dPlaneClass)
return dGeomGetRotation(m_geoms[0]);
}
return m_rotation;
}
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);
enableBody();
}
}
m_position[0] = x;
m_position[1] = y;
m_position[2] = z;
}
void OdeWorld::Object::getPosition(double * x, double * y, double * z)
{
const dReal * pos = NULL;
if (m_is_static)
{
if (m_geoms.size() > 0)
{
if (dGeomGetClass(m_geoms[0]) == dPlaneClass)
pos = &m_position[0];
else
pos = dGeomGetPosition(m_geoms[0]);
}
}
else
{
if (m_body != 0)
pos = dBodyGetPosition(m_body);
}
if (pos != NULL)
{
*x = pos[0];
*y = pos[1];
*z = pos[2];
}
else
{
*x = m_position[0];
*y = m_position[1];
*z = m_position[2];
}
}
void OdeWorld::Object::setRotation(dReal x, dReal y, dReal z)
{
dMatrix3 r;
dRFromEulerAngles(r, x, y, z);
if (m_is_static)
{
for (int i = 0, sz = m_geoms.size(); i < sz; i++)
dGeomSetRotation(m_geoms[i], r);
}
else
{
if (m_body != 0)
{
dBodySetRotation(m_body, r);
enableBody();
}
}
}
void OdeWorld::Object::addForce(dReal fx, dReal fy, dReal fz)
{
if (m_body != 0)
{
dBodyAddForce(m_body, fx, fy, fz);
enableBody();
}
}
void OdeWorld::Object::addForceRel(dReal fx, dReal fy, dReal fz)
{
if (m_body != 0)
{
dBodyAddRelForce(m_body, fx, fy, fz);
enableBody();
}
}
void OdeWorld::Object::addTorque(dReal fx, dReal fy, dReal fz)
{
if (m_body != 0)
{
dBodyAddTorque(m_body, fx, fy, fz);
enableBody();
}
}
void OdeWorld::Object::addTorqueRel(dReal fx, dReal fy, dReal fz)
{
if (m_body != 0)
{
dBodyAddRelTorque(m_body, fx, fy, fz);
enableBody();
}
}
void OdeWorld::Object::finalize()
{
if (m_body != 0)
{
#if 0
cerr << "Warning: translating mass by ("
<< (-m_mass.c[0]) << ", "
<< (-m_mass.c[1]) << ", "
<< (-m_mass.c[2]) << ")" << endl;
#endif
dMassTranslate(&m_mass, -m_mass.c[0], -m_mass.c[1], -m_mass.c[2]);
dBodySetMass(m_body, &m_mass);
}
}
void OdeWorld::Object::setMass(dReal newmass)
{
if (m_body != 0)
{
dMassAdjust(&m_mass, newmass);
dBodySetMass(m_body, &m_mass);
enableBody();
}
}
void OdeWorld::Object::enableBody()
{
if (m_body != 0)
{
dBodyEnable(m_body);
}
}

204
OdeWorld/OdeWorld.h Normal file
View File

@ -0,0 +1,204 @@
#ifndef ODEWORLD_H
#define ODEWORLD_H
#include <ode/ode.h>
#include <vector>
#include <string>
#include <map>
#include "refptr/refptr.h"
#ifdef DEBUG_AMOTOR
#include <iostream>
using namespace std;
#endif
class OdeWorld
{
public:
enum GeomType { BOX, SPHERE, PLANE, CYLINDER, CAPSULE };
class Object
{
public:
Object(bool is_static, OdeWorld * ode_world,
dWorldID world, dSpaceID space, float scale = 1.0f);
Object(const Object & orig);
~Object();
void setPosition(double x, double y, double z);
void getPosition(double * x, double * y, double * z);
void setRotation(dReal x, dReal y, dReal z);
const dReal * getPosition();
const dReal * getRotation();
bool addBox(refptr< std::vector<float> > args);
bool addSphere(refptr< std::vector<float> > args);
bool addCylinder(refptr< std::vector<float> > args);
bool addCapsule(refptr< std::vector<float> > args);
bool addPlane(refptr< std::vector<float> > args);
void addForce(dReal fx, dReal fy, dReal fz);
void addForceRel(dReal fx, dReal fy, dReal fz);
void addTorque(dReal fx, dReal fy, dReal fz);
void addTorqueRel(dReal fx, dReal fy, dReal fz);
void finalize();
dReal getMass() { return m_mass.mass; }
void setMass(dReal newmass);
void enableBody();
dBodyID getBody() { return m_body; }
void setGravityMode(bool enabled)
{
if (m_body != 0)
{
dBodySetGravityMode(m_body, enabled);
}
}
void setUserData(void * user_data)
{
m_user_data = user_data;
}
void * getUserData() { return m_user_data; }
std::vector<dGeomID> & getGeoms() { return m_geoms; }
protected:
bool m_is_static;
dBodyID m_body;
dMass m_mass;
dWorldID m_world;
dSpaceID m_space;
std::vector<dGeomID> m_geoms;
float m_scale;
dReal m_position[3];
dReal m_rotation[12];
OdeWorld * m_ode_world;
void * m_user_data;
void setupGeom(dGeomID geom, dMass * mass,
float locx, float locy, float locz,
float rotx, float roty, float rotz);
dGeomID cloneGeom(dGeomID geom, dBodyID body);
};
class PickedObject
{
public:
Object * obj;
float dist;
float pos[3];
float normal[3];
PickedObject(dGeomID geom, dContactGeom & contact)
{
obj = (Object *) dGeomGetData(geom);
dist = contact.depth;
pos[0] = contact.pos[0];
pos[1] = contact.pos[1];
pos[2] = contact.pos[2];
normal[0] = contact.normal[0];
normal[1] = contact.normal[1];
normal[2] = contact.normal[2];
}
};
typedef refptr<PickedObject> PickedObjectRef;
OdeWorld();
~OdeWorld();
Object * createObject(bool is_static, float scale = 1.0f);
void setGravity(float x, float y, float z)
{
dWorldSetGravity(m_world, x, y, z);
enableAllBodies();
}
void step();
void enableAllBodies();
dWorldID getWorldID() { return m_world; }
dJointID createAMotor(dBodyID b1, dBodyID b2);
dJointID createHinge(dBodyID b1, dBodyID b2,
dReal anchor_x, dReal anchor_y, dReal anchor_z,
dReal axis_x, dReal axis_y, dReal axis_z);
void setAMotorNumAxes(dJointID j, int num_axes)
{
#ifdef DEBUG_AMOTOR
cout << "num axes: " << num_axes << endl;
#endif
dJointSetAMotorNumAxes(j, num_axes);
}
void setAMotorAngle(dJointID j, int anum, dReal val)
{
#ifdef DEBUG_AMOTOR
cout << "angle: " << val << endl;
#endif
dJointSetAMotorAngle(j, anum, val);
}
void setAMotorAxis(dJointID j, int anum, int rel,
dReal x, dReal y, dReal z)
{
#ifdef DEBUG_AMOTOR
cout << "axis: " << anum << ", " << rel
<< ", (" << x << ", " << y << ", " << z << ")" << endl;
#endif
dJointSetAMotorAxis(j, anum, rel, x, y, z);
}
void setAMotorLoStop(dJointID j, dReal val)
{
#ifdef DEBUG_AMOTOR
cout << "lo stop: " << val << endl;
#endif
dJointSetAMotorParam(j, dParamLoStop, val);
}
void setAMotorHiStop(dJointID j, dReal val)
{
#ifdef DEBUG_AMOTOR
cout << "hi stop: " << val << endl;
#endif
dJointSetAMotorParam(j, dParamHiStop, val);
}
void setAMotorVel(dJointID j, dReal val)
{
#ifdef DEBUG_AMOTOR
cout << "vel: " << val << endl;
#endif
dJointSetAMotorParam(j, dParamVel, val);
}
void setAMotorFMax(dJointID j, dReal val)
{
#ifdef DEBUG_AMOTOR
cout << "fmax: " << val << endl;
#endif
dJointSetAMotorParam(j, dParamFMax, val);
}
void setAMotorBounce(dJointID j, dReal val)
{
#ifdef DEBUG_AMOTOR
cout << "bounce: " << val << endl;
#endif
dJointSetAMotorParam(j, dParamBounce, val);
}
refptr< std::vector<PickedObjectRef> > pickObjects(
float start_x, float start_y, float start_z,
float dir_x, float dir_y, float dir_z);
PickedObjectRef pickOne(
float start_x, float start_y, float start_z,
float dir_x, float dir_y, float dir_z,
Object * o);
friend void OdeWorld_collide_callback(void * data,
dGeomID o1, dGeomID o2);
friend void OdeWorld_pick_collide_callback(void * data,
dGeomID o1, dGeomID o2);
static void pushTransform(const dReal * pos, const dReal * R);
protected:
dBodyID createBody();
void destroyBody(dBodyID body);
dWorldID m_world;
dSpaceID m_space;
dJointGroupID m_contactJointGroup;
std::map<dBodyID, int> m_bodies;
dGeomID m_pick_ray;
std::vector< refptr<PickedObject> > m_pick_points;
};
#endif

12
PhyObj/Makefile Normal file
View File

@ -0,0 +1,12 @@
TARGET := PhyObj.o
SOURCES := $(wildcard *.cc)
HEADERS := $(wildcard *.h)
all: $(TARGET)
$(TARGET): $(SOURCES) $(HEADERS)
$(CXX) -c -o $@ $(CXXFLAGS) $(SOURCES)
clean:
-rm -f *~ *.o

106
PhyObj/PhyObj.cc Normal file
View File

@ -0,0 +1,106 @@
#include "PhyObj.h"
#include <vector>
#include <string>
#include <sstream>
using namespace std;
#define WHITESPACE " \t\r\n\f"
/********** static utility functions **********/
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;
}
/********** PhyObj::Geom functions **********/
PhyObj::Geom::Geom()
{
m_type = NONE;
}
PhyObj::Geom::Geom(PhyObj::GeomType type, refptr< vector<float> > args)
{
m_type = type;
m_args = args;
}
/********** PhyObj functions **********/
void PhyObj::load(FileLoader * fileLoader, const FileLoader::Path & path)
{
FileLoader::Buffer buff = fileLoader->load(path);
if (buff.size <= 0)
return;
string str(buff.data, buff.size);
stringstream istr(str, ios_base::in);
while (!istr.eof())
{
string line;
getline(istr, 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;
refptr< vector<float> > args = new vector<float>();
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;
}
GeomType geom_type = NONE;
if (type == "cube")
{
geom_type = BOX;
}
else if (type == "sphere")
{
geom_type = SPHERE;
}
else if (type == "capsule")
{
geom_type = CAPSULE;
}
else if (type == "plane")
{
geom_type = PLANE;
}
if (geom_type != NONE)
{
m_geoms.push_back(new Geom(geom_type, args));
}
}
}

40
PhyObj/PhyObj.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef PHYOBJ_H
#define PHYOBJ_H
#include "refptr/refptr.h"
#include "FileLoader/FileLoader.h"
#include <vector>
class PhyObj
{
public:
/* Types */
enum GeomType { NONE, BOX, SPHERE, PLANE, CAPSULE };
class Geom
{
public:
/* Constructors */
Geom();
Geom(GeomType type, refptr< std::vector<float> > args);
/* Methods */
GeomType getType() { return m_type; }
refptr< std::vector<float> > getArgs() { return m_args; }
protected:
GeomType m_type;
refptr< std::vector<float> > m_args;
};
/* Methods */
void load(FileLoader * fileLoader, const FileLoader::Path & path);
size_t getNumGeoms() { return m_geoms.size(); }
refptr<Geom> getGeom(int i) { return m_geoms[i]; }
protected:
std::vector< refptr<Geom> > m_geoms;
};
#endif

12
TextureCache/Makefile Normal file
View File

@ -0,0 +1,12 @@
TARGET := TextureCache.o
SOURCES := $(wildcard *.cc)
HEADERS := $(wildcard *.h)
all: $(TARGET)
$(TARGET): $(SOURCES) $(HEADERS)
$(CXX) -c -o $@ $(CXXFLAGS) $(SOURCES)
clean:
-rm -f *~ *.o

View File

@ -0,0 +1,143 @@
#include <SDL.h>
#include <SDL_image.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream>
#include "TextureCache.h"
#include "TextureLoader/TextureLoader.h"
#include "FileLoader/FileLoader.h"
using namespace std;
//#define DEBUG_GL_ERROR
#ifdef DEBUG_GL_ERROR
#define checkGLError() checkGLErrorLine(__FUNCTION__, __LINE__)
static void checkGLErrorLine(const char * function, int line)
{
GLenum err = glGetError();
if (err != 0)
{
cerr << "gl error in " << function
<< ": " << err << " (0x" << hex << err << ") at line "
<< dec << line << endl;
}
}
#else
#define checkGLError()
#endif
TextureCache::~TextureCache()
{
}
GLuint TextureCache::load(const FileLoader::Path & path,
FileLoader & fileLoader, bool mipmaps,
int mode, int quality)
{
string filename = path.shortPath;
if (filename == "")
filename = path.fullPath;
if (filename == "")
return 0;
map<string,GLuint>::iterator it = m_cache.find(filename);
if (it != m_cache.end())
{
return it->second;
}
GLuint tex = loadTexture(path, fileLoader, mipmaps, mode, quality);
if (tex > 0)
{
m_cache[filename] = tex;
}
return tex;
}
GLuint TextureCache::loadTexture(const FileLoader::Path & path,
FileLoader & fileLoader, bool mipmaps,
int mode, int quality)
{
checkGLError();
GLuint texture;
FileLoader::Buffer buff = fileLoader.load(path);
if (buff.size <= 0)
return 0;
SDL_RWops * ops = SDL_RWFromMem(buff.data, buff.size);
SDL_Surface * temp = IMG_Load_RW(ops, true);
if (!temp)
{
cerr << "Failed to load image ('" << path.fullPath << "', '"
<< path.shortPath << "'): " << IMG_GetError() << endl;
return 0;
}
SDL_PixelFormat fmt;
fmt.palette = NULL;
fmt.BitsPerPixel = 32;
fmt.BytesPerPixel = 4;
fmt.Rmask = 0x000000FF;
fmt.Gmask = 0x0000FF00;
fmt.Bmask = 0x00FF0000;
fmt.Amask = 0xFF000000;
fmt.Rshift = 0;
fmt.Gshift = 8;
fmt.Bshift = 16;
fmt.Ashift = 24;
SDL_Surface * texsurf = SDL_ConvertSurface(temp, &fmt, SDL_SWSURFACE);
SDL_FreeSurface(temp);
if (!texsurf)
{
cerr << "Image was not converted properly!" << endl;
return 0;
}
unsigned int * pixels = new unsigned int[texsurf->w * texsurf->h];
int y;
unsigned int dstOffset = texsurf->w * (texsurf->h - 1);
unsigned int srcOffset = 0;
for (y = 0; y < texsurf->h; y++)
{
memcpy(pixels + dstOffset,
((unsigned int *)texsurf->pixels) + srcOffset,
texsurf->w << 2);
dstOffset -= texsurf->w;
srcOffset += texsurf->w;
}
glGenTextures(1, &texture);
checkGLError();
glBindTexture(GL_TEXTURE_2D, texture);
checkGLError();
glTexImage2D(GL_TEXTURE_2D, 0, 4, texsurf->w, texsurf->h, 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixels);
if (quality > 0)
{
checkGLError();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
checkGLError();
}
else
{
checkGLError();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
checkGLError();
}
checkGLError();
if (mipmaps)
{
checkGLError();
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA,
texsurf->w, texsurf->h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
checkGLError();
}
SDL_FreeSurface(texsurf);
delete[] pixels;
checkGLError();
return texture;
}

View File

@ -0,0 +1,30 @@
#ifndef TEXTURECACHE_H
#define TEXTURECACHE_H TEXTURECACHE_H
#include <SDL.h>
#include <GL/gl.h>
#include <map>
#include <string>
#include "TextureLoader/TextureLoader.h"
#include "FileLoader/FileLoader.h"
class TextureCache : public TextureLoader
{
public:
virtual ~TextureCache();
virtual GLuint load(const FileLoader::Path & path,
FileLoader & fileLoader, bool mipmaps = true,
int mode = GL_DECAL, int quality = 1);
protected:
/* methods */
GLuint loadTexture(const FileLoader::Path & path,
FileLoader & fileLoader, bool mipmaps,
int mode, int quality);
/* data */
std::map< std::string, GLuint > m_cache;
};
#endif

View File

@ -0,0 +1,18 @@
#ifndef TEXTURELOADER_H
#define TEXTURELOADER_H TEXTURELOADER_H
#include <string>
#include <GL/gl.h>
#include "FileLoader/FileLoader.h"
class TextureLoader
{
public:
virtual GLuint load(
const FileLoader::Path & path,
FileLoader & fileLoader, bool mipmaps = true,
int mode = GL_DECAL, int quality = 1) = 0;
};
#endif

99
refptr/refptr.h Normal file
View File

@ -0,0 +1,99 @@
#ifndef REFPTR_H
#define REFPTR_H REFPTR_H
/* Author: Josh Holtrop
* Purpose: Provide a reference-counting pointer-like first order
* C++ object that will free the object it is pointing to when
* all references to it have been destroyed.
* This implementation does not solve the circular reference problem.
* I was not concerned with that when developing this class.
*/
#include <stdlib.h> /* NULL */
template <typename T>
class refptr
{
public:
refptr<T>();
refptr<T>(T * ptr);
refptr<T>(const refptr<T> & orig);
refptr<T> & operator=(const refptr<T> & orig);
refptr<T> & operator=(T * ptr);
~refptr<T>();
T & operator*() const { return *m_ptr; }
T * operator->() const { return m_ptr; }
bool isNull() const { return m_ptr == NULL; }
private:
void cloneFrom(const refptr<T> & orig);
void destroy();
T * m_ptr;
int * m_refCount;
};
template <typename T> refptr<T>::refptr()
{
m_ptr = NULL;
m_refCount = NULL;
}
template <typename T> refptr<T>::refptr(T * ptr)
{
m_ptr = ptr;
m_refCount = new int;
*m_refCount = 1;
}
template <typename T> refptr<T>::refptr(const refptr<T> & orig)
{
cloneFrom(orig);
}
template <typename T> refptr<T> & refptr<T>::operator=(const refptr<T> & orig)
{
destroy();
cloneFrom(orig);
return *this;
}
template <typename T> refptr<T> & refptr<T>::operator=(T * ptr)
{
destroy();
m_ptr = ptr;
m_refCount = new int;
*m_refCount = 1;
return *this;
}
template <typename T> void refptr<T>::cloneFrom(const refptr<T> & orig)
{
this->m_ptr = orig.m_ptr;
this->m_refCount = orig.m_refCount;
if (m_refCount != NULL)
(*m_refCount)++;
}
template <typename T> refptr<T>::~refptr()
{
destroy();
}
template <typename T> void refptr<T>::destroy()
{
if (m_refCount != NULL)
{
if (*m_refCount <= 1)
{
delete m_ptr;
delete m_refCount;
}
else
{
(*m_refCount)--;
}
}
}
#endif

10
wfobj/Makefile Normal file
View File

@ -0,0 +1,10 @@
TARGET := WFObj.o
all: $(TARGET)
%.o: %.cc
$(CXX) -c -o $@ $(CPPFLAGS) $(CXXFLAGS) $<
clean:
-rm -f *~ *.o

18
wfobj/Makefile.driver Normal file
View File

@ -0,0 +1,18 @@
CXX := g++
CXXFLAGS := -O2
SOURCE := WFObj.cc driver.cc
OBJS := $(SOURCE:.cc=.o)
LDFLAGS := -lGL
TARGET := driver
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) -o $@ $^ $(LDFLAGS)
%.o: %.cc %.hh
$(CXX) -c -o $@ $< $(CXXFLAGS)
clean:
-rm -f *~ *.o $(TARGET)

703
wfobj/WFObj.cc Normal file
View File

@ -0,0 +1,703 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h> // isspace()
#include <string.h> // strlen()
#include <GL/gl.h>
#include <vector>
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <sstream>
#include "WFObj.h"
using namespace std;
#define WHITESPACE " \n\r\t\v"
//#define DEBUGGL
/****** static functions ******/
static string trimString(string s)
{
size_t lastpos = s.find_last_not_of(WHITESPACE);
if (lastpos == string::npos)
return "";
s.erase(lastpos + 1);
s.erase(0, s.find_first_not_of(WHITESPACE));
return s;
}
static string stripFirstToken(string & input)
{
size_t firstnonspace = input.find_first_not_of(WHITESPACE);
if (firstnonspace == string::npos)
return "";
size_t spaceafter = input.find_first_of(WHITESPACE, firstnonspace);
string token = input.substr(firstnonspace, spaceafter - firstnonspace);
input.erase(0, spaceafter);
return token;
}
static vector<string> splitString(const string & str, char delim)
{
vector<string> ret;
string s = str;
size_t pos;
while ( (pos = s.find(delim)) != string::npos )
{
string t = s.substr(0, pos);
ret.push_back(t);
s.erase(0, pos + 1);
}
if (s != "")
ret.push_back(s);
return ret;
}
static string basePath(const string & str)
{
string path = str;
size_t pos;
if ( (pos = path.find_last_of("/\\")) != string::npos )
{
path.erase(pos + 1);
return path;
}
return "";
}
//#define DEBUG_GL_ERROR
#ifdef DEBUG_GL_ERROR
#define checkGLError() checkGLErrorLine(__FUNCTION__, __LINE__)
static void checkGLErrorLine(const char * function, int line)
{
GLenum err = glGetError();
if (err != 0)
{
cerr << "gl error in " << function
<< ": " << err << " (0x" << hex << err << ") at line "
<< dec << line << endl;
}
}
#else
#define checkGLError()
#endif
/****** WFObj functions ******/
WFObj::WFObj()
{
init();
}
WFObj::WFObj(FileLoader & fileLoader)
{
init(&fileLoader);
}
WFObj::WFObj(TextureLoader & textureLoader)
{
init(NULL, &textureLoader);
}
WFObj::WFObj(FileLoader & fileLoader, TextureLoader & textureLoader)
{
init(&fileLoader, &textureLoader);
}
void WFObj::init (FileLoader * fileLoader,
TextureLoader * textureLoader)
{
m_fileLoader = fileLoader;
if (m_fileLoader == NULL)
{
m_fileLoader = new WFFileLoader();
m_iCreatedFileLoader = true;
}
else
{
m_iCreatedFileLoader = false;
}
m_textureLoader = textureLoader;
}
WFObj::~WFObj()
{
if (m_iCreatedFileLoader)
delete m_fileLoader;
}
void WFObj::clear()
{
m_data = std::vector< std::vector<std::string> >();
m_loadedVertex = false;
}
bool WFObj::load(const FileLoader::Path & path)
{
clear();
FileLoader::Buffer buff = m_fileLoader->load(path);
if (buff.size <= 0)
return false;
m_path = path;
string str(buff.data, buff.size);
stringstream istr(str, ios_base::in);
load(istr, buff.size);
return true;
}
bool WFObj::load(std::istream & istr, unsigned int size)
{
char buf[size+1];
string buildup;
while (istr.good())
{
istr.getline(buf, size+1);
string input = trimString(buf);
int sz = input.size();
if (sz == 0 || input[0] == '#')
continue;
if (input[sz-1] == '\\')
{
input[sz-1] = ' ';
buildup = input;
continue;
}
if (buildup != "")
input = buildup + input;
buildup = "";
processInputLine(input);
}
return true;
}
void WFObj::processInputLine(const std::string & input)
{
string line = input;
vector<string> lineParts;
for (;;)
{
string token = stripFirstToken(line);
if (token == "")
break;
lineParts.push_back(token);
}
if (lineParts.size() > 0)
m_data.push_back(lineParts);
}
GLuint WFObj::render(bool doTextureInfo, bool enableBlending)
{
checkGLError();
GLuint list = glGenLists(1);
glNewList(list, GL_COMPILE);
int len = m_data.size();
enum { VERTEX, VERTEX_TEXTURE, VERTEX_NORMAL, VERTEX_TYPES };
vector<Vertex> vertices[VERTEX_TYPES];
int numVertsLast = 0;
bool inFace = false;
bool inMaterial = false;
string currentMaterialName;
WFMtl material(this);
for (int i = 0; i < len; i++)
{
string type = m_data[i][0];
if (type == "v")
{
Vertex v = readVertex(m_data[i]);
updateAABB(v.getData());
vertices[VERTEX].push_back(v);
}
else if (type == "vt")
vertices[VERTEX_TEXTURE].push_back(readVertex(m_data[i]));
else if (type == "vn")
vertices[VERTEX_NORMAL].push_back(readVertex(m_data[i]));
else if (type == "f")
{
int numVerts = m_data[i].size() - 1;
if (inFace && (numVerts != numVertsLast || numVertsLast > 4))
{
#ifdef DEBUGGL
cout << "glEnd()" << endl;
#endif
glEnd();
inFace = false;
}
if (!inFace)
{
if (numVerts == 3)
{
#ifdef DEBUGGL
cout << "glBegin(GL_TRIANGLES)" << endl;
#endif
glBegin(GL_TRIANGLES);
}
else if (numVerts == 4)
{
#ifdef DEBUGGL
cout << "glBegin(GL_QUADS)" << endl;
#endif
glBegin(GL_QUADS);
}
else
{
#ifdef DEBUGGL
cout << "glBegin(GL_POLYGON)" << endl;
#endif
glBegin(GL_POLYGON);
}
inFace = true;
}
for (int v = 1; v <= numVerts; v++)
{
int vertexIndices[3] = {0, 0, 0};
parseVertexIndices(m_data[i][v], vertexIndices);
for (int j = 0; j < 3; j++)
{
if (vertexIndices[j] < 0)
vertexIndices[j] += vertices[j].size() + 1;
}
bool valid = true;
for (int j = 0; j < 3; j++)
{
if (vertexIndices[j] > (int) vertices[j].size())
{
valid = false;
break;
}
}
if (vertexIndices[VERTEX] <= 0)
valid = false;
if (!valid)
continue;
if (vertexIndices[VERTEX_NORMAL] != 0)
{
/* a normal is present */
#ifdef DEBUGGL
cout << " glNormal3f(" <<
vertices[VERTEX_NORMAL][vertexIndices[VERTEX_NORMAL]-1]
[0] << ", " <<
vertices[VERTEX_NORMAL][vertexIndices[VERTEX_NORMAL]-1]
[1] << ", " <<
vertices[VERTEX_NORMAL][vertexIndices[VERTEX_NORMAL]-1]
[2] << ")" << endl;
#endif
glNormal3fv(vertices[VERTEX_NORMAL]
[vertexIndices[VERTEX_NORMAL]-1].getData());
}
if (vertexIndices[VERTEX_TEXTURE] != 0)
{
/* a texture coordinate is present */
#ifdef DEBUGGL
cout << " glTexCoord2f(" <<
vertices[VERTEX_TEXTURE][vertexIndices[VERTEX_TEXTURE]-1]
[0] << ", " <<
vertices[VERTEX_TEXTURE][vertexIndices[VERTEX_TEXTURE]-1]
[1] << ')' << endl;
#endif
glTexCoord2fv(vertices[VERTEX_TEXTURE]
[vertexIndices[VERTEX_TEXTURE]-1].getData());
}
#ifdef DEBUGGL
cout << " glVertex3f(" <<
vertices[VERTEX][vertexIndices[VERTEX]-1][0] << ", " <<
vertices[VERTEX][vertexIndices[VERTEX]-1][1] << ", " <<
vertices[VERTEX][vertexIndices[VERTEX]-1][2] << ")" <<
" [" << vertexIndices[VERTEX] << "]" << endl;
#endif
glVertex3fv(vertices[VERTEX][vertexIndices[VERTEX]-1].getData());
}
numVertsLast = numVerts;
}
else if (type == "usemtl")
{
if (inFace)
{
#ifdef DEBUGGL
cout << "glEnd()" << endl;
#endif
glEnd();
inFace = false;
}
if (inMaterial)
{
material.renderEnd(currentMaterialName, doTextureInfo,
enableBlending);
inMaterial = false;
}
if (m_data[i].size() >= 2)
{
currentMaterialName = m_data[i][1];
material.renderBegin(currentMaterialName, doTextureInfo,
enableBlending);
inMaterial = true;
}
}
else if (type == "mtllib")
{
if (m_data[i].size() >= 2)
{
FileLoader::Path path(
basePath(m_path.fullPath) + m_data[i][1],
m_data[i][1]);
material.load(path);
}
}
}
if (inFace)
{
#ifdef DEBUGGL
cout << "glEnd()" << endl;
#endif
glEnd();
inFace = false;
}
if (inMaterial)
{
material.renderEnd(currentMaterialName, doTextureInfo, enableBlending);
inMaterial = false;
}
glEndList();
checkGLError();
return list;
}
void WFObj::updateAABB(const float * const vertex)
{
if (m_loadedVertex)
{
if (vertex[0] < m_aabb[0])
m_aabb[0] = vertex[0];
else if (vertex[0] > m_aabb[3])
m_aabb[3] = vertex[0];
if (vertex[1] < m_aabb[1])
m_aabb[1] = vertex[1];
else if (vertex[1] > m_aabb[4])
m_aabb[4] = vertex[1];
if (vertex[2] < m_aabb[2])
m_aabb[2] = vertex[2];
else if (vertex[2] > m_aabb[5])
m_aabb[5] = vertex[2];
}
else
{
m_aabb[0] = m_aabb[3] = vertex[0];
m_aabb[1] = m_aabb[4] = vertex[1];
m_aabb[2] = m_aabb[5] = vertex[2];
m_loadedVertex = true;
}
}
WFObj::Vertex WFObj::readVertex(const vector<string> & parts)
{
int partslen = parts.size();
Vertex v;
for (int i = 1; i < partslen && i <= 4; i++)
{
sscanf(parts[i].c_str(), "%f", &v[i - 1]);
}
return v;
}
void WFObj::parseVertexIndices(const string & vtxref, int * ret)
{
vector<string> parts = splitString(vtxref, '/');
int num = parts.size();
for (int i = 0; i < num && i < 3; i++)
sscanf(parts[i].c_str(), "%d", ret + i);
}
/****** WFMtl functions ******/
void WFObj::WFMtl::clear()
{
m_data = map< string, vector< vector<string> > >();
m_currentMaterialName = "";
m_attributesPushed = false;
}
bool WFObj::WFMtl::load(const FileLoader::Path & path)
{
clear();
FileLoader::Buffer buff = m_obj->m_fileLoader->load(path);
if (buff.size <= 0)
return false;
m_path = path;
string str(buff.data, buff.size);
stringstream istr(str, ios_base::in);
load(istr, buff.size);
return true;
}
bool WFObj::WFMtl::load(std::istream & istr, unsigned int size)
{
char buf[size+1];
string buildup;
while (istr.good())
{
istr.getline(buf, size+1);
string input = trimString(buf);
int sz = input.size();
if (sz == 0 || input[0] == '#')
continue;
if (input[sz-1] == '\\')
{
input[sz-1] = ' ';
buildup = input;
continue;
}
if (buildup != "")
input = buildup + input;
buildup = "";
processInputLine(input);
}
return true;
}
void WFObj::WFMtl::processInputLine(const std::string & input)
{
string line = input;
vector<string> lineParts;
for (;;)
{
string token = stripFirstToken(line);
if (token == "")
break;
lineParts.push_back(token);
}
if (lineParts.size() > 0)
{
if ( (lineParts.size() >= 2) && (lineParts[0] == "newmtl") )
{
m_currentMaterialName = lineParts[1];
}
else if (m_currentMaterialName != "")
{
m_data[m_currentMaterialName].push_back(lineParts);
}
}
}
void WFObj::WFMtl::renderBegin(const string & mtlname, bool doTextureInfo,
bool enableBlending)
{
map< string, vector< vector<string> > >::iterator it = m_data.find(mtlname);
if (it == m_data.end())
return;
vector< vector<string> > & stmts = it->second;
int num_stmts = stmts.size();
bool foundTexture = false;
bool didSomething = false;
checkGLError();
for (int i = 0; i < num_stmts; i++)
{
string & type = stmts[i][0];
if (type == "Ka") /* set ambient color */
{
if ( (stmts[i].size() == 4) && (stmts[i][1] != "spectral") )
{
pushAttributes();
float mat[4] = {0.0f, 0.0f, 0.0f, 1.0f};
for (int j = 0; j < 3; j++)
sscanf(stmts[i][j+1].c_str(), "%f", &mat[j]);
#ifdef DEBUGGL
cout << " glMaterialfv(GL_FRONT, GL_AMBIENT, {";
for (int j = 0; j < 4; j++)
cout << mat[j] << (j < 3 ? ", " : "})");
cout << endl;
#endif
glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
didSomething = true;
}
}
else if (type == "Kd") /* set diffuse color */
{
if ( (stmts[i].size() == 4) && (stmts[i][1] != "spectral") )
{
pushAttributes();
float mat[4] = {0.0f, 0.0f, 0.0f, 1.0f};
for (int j = 0; j < 3; j++)
sscanf(stmts[i][j+1].c_str(), "%f", &mat[j]);
#ifdef DEBUGGL
cout << " glMaterialfv(GL_FRONT, GL_DIFFUSE, {";
for (int j = 0; j < 4; j++)
cout << mat[j] << (j < 3 ? ", " : "})");
cout << endl;
#endif
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
didSomething = true;
}
}
else if (type == "Ks") /* set specular color */
{
if ( (stmts[i].size() == 4) && (stmts[i][1] != "spectral") )
{
pushAttributes();
float mat[4] = {0.0f, 0.0f, 0.0f, 1.0f};
for (int j = 0; j < 3; j++)
sscanf(stmts[i][j+1].c_str(), "%f", &mat[j]);
#ifdef DEBUGGL
cout << " glMaterialfv(GL_FRONT, GL_SPECULAR, {";
for (int j = 0; j < 4; j++)
cout << mat[j] << (j < 3 ? ", " : "})");
cout << endl;
#endif
glMaterialfv(GL_FRONT, GL_SPECULAR, mat);
didSomething = true;
}
}
else if (type == "Ns") /* set shininess */
{
if (stmts[i].size() == 2)
{
pushAttributes();
GLfloat shininess = 0.0f;
sscanf(stmts[i][1].c_str(), "%f", &shininess);
#ifdef DEBUGGL
cout << " glMaterialf(GL_FRONT, GL_SHININESS, "
<< shininess << ")" << endl;
#endif
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
didSomething = true;
}
}
else if (type == "map_Kd") /* load a diffuse texture */
{
if (doTextureInfo)
{
if (stmts[i].size() == 2)
{
if (m_obj->m_textureLoader != NULL)
{
FileLoader::Path path(
basePath(m_path.fullPath + stmts[i][1]),
stmts[i][1]);
GLuint tex = m_obj->m_textureLoader->load(path,
*m_obj->m_fileLoader);
if (tex > 0)
{
pushAttributes(); /* jh 2009-11-16 */
#ifdef DEBUGGL
cout << " glBindTexture(GL_TEXTURE_2D, " << tex << ")" << endl;
#endif
glBindTexture(GL_TEXTURE_2D, tex);
foundTexture = true;
didSomething = true;
}
}
}
}
}
}
checkGLError();
if (didSomething)
{
pushAttributes();
if (doTextureInfo)
{
if (enableBlending)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
if (foundTexture)
{
#ifdef DEBUGGL
cout << " glEnable(GL_TEXTURE_2D)" << endl;
#endif
glEnable(GL_TEXTURE_2D);
}
else
{
#ifdef DEBUGGL
cout << " glDisable(GL_TEXTURE_2D)" << endl;
#endif
glDisable(GL_TEXTURE_2D);
}
}
}
checkGLError();
}
void WFObj::WFMtl::pushAttributes()
{
if (m_attributesPushed)
return;
m_attributesPushed = true;
#ifdef DEBUGGL
cout << " glPushAttrib(GL_LIGHTING_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT)"
<< endl;
#endif
checkGLError();
glPushAttrib(GL_LIGHTING_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
checkGLError();
}
void WFObj::WFMtl::renderEnd(const string & mtlname, bool doTextureInfo,
bool enableBlending)
{
map< string, vector< vector<string> > >::iterator it = m_data.find(mtlname);
if (it == m_data.end())
return;
if (m_attributesPushed)
{
#ifdef DEBUGGL
cout << " glPopAttrib()" << endl;
#endif
checkGLError();
glPopAttrib();
checkGLError();
m_attributesPushed = false;
}
}
/****** WFFileLoader functions ******/
int WFObj::WFFileLoader::getSize(const Path & path)
{
struct stat st;
if (path.fullPath == "")
return -1;
if (stat(path.fullPath.c_str(), &st))
return -2;
return st.st_size;
}
FileLoader::Buffer WFObj::WFFileLoader::load(const Path & path)
{
int size = getSize(path);
if (size > 0)
{
int fd = open(path.fullPath.c_str(), O_RDONLY);
if (fd > 0)
{
Buffer buf(size);
int num_read = read(fd, buf.data, size);
close(fd);
if (num_read > 0)
return buf;
}
}
return Buffer(0);
}

92
wfobj/WFObj.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef WFOBJ_H
#define WFOBJ_H
#include "FileLoader/FileLoader.h"
#include "TextureLoader/TextureLoader.h"
#include <GL/gl.h>
#include <vector>
#include <string>
#include <map>
class WFObj
{
public:
WFObj();
WFObj(FileLoader & fileLoader);
WFObj(TextureLoader & textureLoader);
WFObj(FileLoader & fileLoader, TextureLoader & textureLoader);
~WFObj();
class WFMtl
{
public:
WFMtl(WFObj * obj) { m_obj = obj; }
bool load(const FileLoader::Path & path);
void renderBegin(const std::string & mtlname,
bool doTextureInfo = true,
bool enableBlending = false);
void renderEnd(const std::string & mtlname,
bool doTextureInfo = true,
bool enableBlending = false);
protected:
/* methods */
void clear();
void processInputLine(const std::string & input);
void pushAttributes();
bool load(std::istream & istr, unsigned int size);
/* variables */
std::map< std::string, std::vector< std::vector<std::string> > > m_data;
std::string m_currentMaterialName;
bool m_attributesPushed;
FileLoader::Path m_path;
WFObj * m_obj;
};
class WFFileLoader : public FileLoader
{
public:
virtual int getSize(const Path & path);
virtual Buffer load(const Path & path);
};
bool load(const FileLoader::Path & path);
GLuint render(bool doTextureInfo = true,
bool enableBlending = false);
const float * const getAABB() { return m_aabb; }
protected:
/* types */
class Vertex
{
public:
float operator[](int idx) const { return data[idx]; }
float & operator[](int idx) { return data[idx]; }
float * getData() { return data; }
private:
float data[4];
};
/* methods */
void init(FileLoader * fileLoader = NULL,
TextureLoader * textureLoader = NULL);
void clear();
void processInputLine(const std::string & input);
Vertex readVertex(const std::vector<std::string> & parts);
void parseVertexIndices(const std::string & vtxref, int * ret);
void updateAABB(const float * const vertex);
bool load(std::istream & istr, unsigned int size);
/* variables */
std::vector< std::vector<std::string> > m_data;
FileLoader::Path m_path;
float m_aabb[6];
bool m_loadedVertex;
FileLoader * m_fileLoader;
TextureLoader * m_textureLoader;
bool m_iCreatedFileLoader;
};
#endif

28
wfobj/driver.cc Normal file
View File

@ -0,0 +1,28 @@
#include <GL/gl.h>
#include <iostream>
#include "WFObj.hh"
using namespace std;
GLuint loadTexture(const char * texture)
{
cout << "got texture request: '" << texture << "'" << endl;
return 33;
}
int main(int argc, char * argv[])
{
WFObj w;
if (argc < 2)
{
cout << "Usage: " << argv[0] << " <filename>" << endl;
return -2;
}
if (!w.load(argv[1], &loadTexture))
{
cout << "Couldn't open '" << argv[1] << "'!" << endl;
return -1;
}
w.render();
return 0;
}