Compare commits

...

13 Commits
v2.0 ... master

Author SHA1 Message Date
Josh Holtrop
e4dc0f4d36 error loading object file when "usemtl" references an undefined material 2011-05-27 15:39:53 -04:00
Josh Holtrop
e6b8c17345 initialize WFObj::Buffer parameters 2011-05-21 23:32:39 -04:00
Josh Holtrop
1ecc6d749b specify GL_GLEXT_PROTOTYPES in build environment 2011-05-16 15:54:35 -04:00
Josh Holtrop
08e558482f add resolvePath() to find files rel to .obj path 2011-05-16 15:32:11 -04:00
Josh Holtrop
1918cc89bf changed loadfile and loadtexture to load() params 2011-05-16 15:24:00 -04:00
Josh Holtrop
e999bf67b7 add texture support 2011-05-16 15:16:40 -04:00
Josh Holtrop
01a90fdef7 change VertexRef elements to unsigned values to fix compile warnings 2011-05-16 15:01:36 -04:00
Josh Holtrop
c5c76f0033 compile with -Wall, fix a warning 2011-05-16 15:00:43 -04:00
Josh Holtrop
1c17d3b398 Merge branch 'master' of ssh://holtrop.homelinux.com/wfobj 2011-05-04 20:38:53 -04:00
Josh Holtrop
6bdaecd9f7 add GL_INCLUDE_FILE capability 2011-05-04 20:38:38 -04:00
Josh Holtrop
2fcba86aad add doTextures() 2011-05-04 19:44:09 -04:00
Josh Holtrop
2ffcdfb3dc remove draw(); add get*() methods for client access 2011-05-04 16:12:00 -04:00
Josh Holtrop
4e76817336 make Material a public subclass, remove renderMaterial() 2011-05-04 15:50:18 -04:00
3 changed files with 92 additions and 89 deletions

View File

@ -1,6 +1,6 @@
# vim:filetype=python # vim:filetype=python
env = Environment(LIBS = ['GL']) env = Environment(LIBS = ['GL'], CXXFLAGS = ['-Wall', '-DGL_GLEXT_PROTOTYPES'])
env.Program('driver', Glob('*.cc')) env.Program('driver', Glob('*.cc'))

107
WFObj.cc
View File

@ -1,6 +1,4 @@
#define GL_GLEXT_PROTOTYPES
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
@ -8,7 +6,6 @@
#include <ctype.h> /* isspace() */ #include <ctype.h> /* isspace() */
#include <string.h> /* strlen() */ #include <string.h> /* strlen() */
#include <stdlib.h> /* atoi */ #include <stdlib.h> /* atoi */
#include <GL/gl.h>
#include <vector> #include <vector>
#include <string> #include <string>
@ -100,14 +97,8 @@ static void checkGLErrorLine(const char * function, int line)
/****** WFObj functions ******/ /****** WFObj functions ******/
WFObj::WFObj(loadfile_t lf, loadtexture_t lt) WFObj::WFObj()
{ {
m_loadfile = lf;
m_loadtexture = lt;
if (m_loadfile == NULL)
{
m_loadfile = loadfile;
}
if (m_valid) if (m_valid)
{ {
glDeleteBuffers(1, &m_data_vbo); glDeleteBuffers(1, &m_data_vbo);
@ -123,18 +114,24 @@ WFObj::~WFObj()
void WFObj::clear() void WFObj::clear()
{ {
for (int i = 0; i < sizeof(m_vertices)/sizeof(m_vertices[0]); i++) for (size_t i = 0; i < sizeof(m_vertices)/sizeof(m_vertices[0]); i++)
m_vertices[i].clear(); m_vertices[i].clear();
m_faces.clear(); m_faces.clear();
m_face_indices.clear();
m_materials.clear(); m_materials.clear();
m_valid = false; m_valid = false;
m_path = ""; m_path = "";
m_current_material_name = ""; m_current_material_name = "";
} }
bool WFObj::load(const char *fname) bool WFObj::load(const char *fname, loadfile_t lf, loadtexture_t lt)
{ {
m_loadfile = lf;
m_loadtexture = lt;
if (m_loadfile == NULL)
{
m_loadfile = loadfile;
}
clear(); clear();
Buffer buff; Buffer buff;
@ -217,7 +214,10 @@ void WFObj::processInputLine(const std::string & input)
else if (type == "f") else if (type == "f")
{ {
if (m_faces.find(m_current_material_name) == m_faces.end()) if (m_faces.find(m_current_material_name) == m_faces.end())
{
m_faces[m_current_material_name] = vector<Face>(); m_faces[m_current_material_name] = vector<Face>();
m_num_materials = m_faces.size();
}
vector<Face> faces = readFaces(tokens); vector<Face> faces = readFaces(tokens);
for (vector<Face>::iterator it = faces.begin(); it != faces.end(); it++) for (vector<Face>::iterator it = faces.begin(); it != faces.end(); it++)
m_faces[m_current_material_name].push_back(*it); m_faces[m_current_material_name].push_back(*it);
@ -339,7 +339,7 @@ WFObj::VertexRef WFObj::readVertexRef(const std::string ref)
void WFObj::loadMaterial(const std::string & name) void WFObj::loadMaterial(const std::string & name)
{ {
Buffer buff; Buffer buff;
string path = (name[0] != '/') ? basePath(m_path) + name : name; string path = resolvePath(name);
if (!m_loadfile(path.c_str(), buff)) if (!m_loadfile(path.c_str(), buff))
{ {
cerr << "WFObj: error: couldn't open material file '" << path << "'" cerr << "WFObj: error: couldn't open material file '" << path << "'"
@ -370,7 +370,7 @@ void WFObj::loadMaterial(const std::string & name)
else if (tokens[0] == "Ns") else if (tokens[0] == "Ns")
{ {
m_materials[mat_name].shininess = atof(tokens[1].c_str()); m_materials[mat_name].shininess = atof(tokens[1].c_str());
m_materials[mat_name].flags |= Material::MAT_SHININESS; m_materials[mat_name].flags |= Material::SHININESS_BIT;
} }
else if (tokens[0] == "Ka") else if (tokens[0] == "Ka")
{ {
@ -380,7 +380,7 @@ void WFObj::loadMaterial(const std::string & name)
m_materials[mat_name].ambient[i] = m_materials[mat_name].ambient[i] =
atof(tokens[i + 1].c_str()); atof(tokens[i + 1].c_str());
m_materials[mat_name].ambient[3] = 1.0; m_materials[mat_name].ambient[3] = 1.0;
m_materials[mat_name].flags |= Material::MAT_AMBIENT; m_materials[mat_name].flags |= Material::AMBIENT_BIT;
} }
else else
cerr << "WFObj: error: 'Ka' material directive requires" cerr << "WFObj: error: 'Ka' material directive requires"
@ -394,7 +394,7 @@ void WFObj::loadMaterial(const std::string & name)
m_materials[mat_name].diffuse[i] = m_materials[mat_name].diffuse[i] =
atof(tokens[i + 1].c_str()); atof(tokens[i + 1].c_str());
m_materials[mat_name].diffuse[3] = 1.0; m_materials[mat_name].diffuse[3] = 1.0;
m_materials[mat_name].flags |= Material::MAT_DIFFUSE; m_materials[mat_name].flags |= Material::DIFFUSE_BIT;
} }
else else
cerr << "WFObj: error: 'Kd' material directive requires" cerr << "WFObj: error: 'Kd' material directive requires"
@ -408,7 +408,7 @@ void WFObj::loadMaterial(const std::string & name)
m_materials[mat_name].specular[i] = m_materials[mat_name].specular[i] =
atof(tokens[i + 1].c_str()); atof(tokens[i + 1].c_str());
m_materials[mat_name].specular[3] = 1.0; m_materials[mat_name].specular[3] = 1.0;
m_materials[mat_name].flags |= Material::MAT_SPECULAR; m_materials[mat_name].flags |= Material::SPECULAR_BIT;
} }
else else
cerr << "WFObj: error: 'Ks' material directive requires" cerr << "WFObj: error: 'Ks' material directive requires"
@ -418,9 +418,15 @@ void WFObj::loadMaterial(const std::string & name)
{ {
/* ignore these parameters */ /* ignore these parameters */
} }
else if (tokens[0] == "map_Kd")
{
m_materials[mat_name].texture = loadTexture(resolvePath(tokens[1]));
if (m_materials[mat_name].texture != 0)
m_materials[mat_name].flags |= Material::TEXTURE_BIT;
}
else else
{ {
cerr << "WFObj: error: unrecognized material directive: '" cerr << "WFObj: warning: unrecognized material directive: '"
<< tokens[0] << "'" << endl; << tokens[0] << "'" << endl;
} }
} }
@ -456,6 +462,12 @@ bool WFObj::buildVBO()
it != m_faces.end(); it != m_faces.end();
it++) it++)
{ {
if (m_materials.find(it->first) == m_materials.end())
{
cerr << "Material '" << it->first << "' referenced in '"
<< m_path << "' is not defined." << endl;
return false;
}
for (vector<Face>::iterator fit = it->second.begin(); for (vector<Face>::iterator fit = it->second.begin();
fit != it->second.end(); fit != it->second.end();
fit++) fit++)
@ -529,7 +541,8 @@ bool WFObj::buildVBO()
vid++; vid++;
} }
} }
m_face_indices[it->first] = make_pair(first, vid - first); m_materials[it->first].first_vertex = first;
m_materials[it->first].num_vertices = vid - first;
} }
glGenBuffers(1, &m_data_vbo); glGenBuffers(1, &m_data_vbo);
glGenBuffers(1, &m_index_vbo); glGenBuffers(1, &m_index_vbo);
@ -545,52 +558,26 @@ bool WFObj::buildVBO()
return true; return true;
} }
void WFObj::draw() void WFObj::bindBuffers()
{ {
if (!m_valid)
return;
glBindBuffer(GL_ARRAY_BUFFER, m_data_vbo); glBindBuffer(GL_ARRAY_BUFFER, m_data_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_vbo);
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
size_t stride = sizeof(GLfloat) * m_n_floats_per_vref;
glVertexPointer(3, GL_FLOAT, stride, NULL);
glNormalPointer(GL_FLOAT, stride, (GLvoid *) (sizeof(GLfloat) * 3));
if (m_do_textures)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, stride,
(GLvoid *) (sizeof(GLfloat) * 6));
}
for (map<string, vector<Face> >::iterator it = m_faces.begin();
it != m_faces.end();
it++)
{
glPushAttrib(GL_LIGHTING_BIT);
renderMaterial(m_materials[it->first]);
glDrawElements(GL_TRIANGLES, m_face_indices[it->first].second,
GL_UNSIGNED_SHORT,
(GLvoid *) (sizeof(GLshort) * m_face_indices[it->first].first));
glPopAttrib();
}
glPopClientAttrib();
} }
void WFObj::renderMaterial(const WFObj::Material & m) GLuint WFObj::loadTexture(const std::string & path)
{ {
if (m.flags & Material::MAT_SHININESS) if (m_loadtexture == NULL)
glMaterialf(GL_FRONT, GL_SHININESS, m.shininess); return 0;
if (m.flags & Material::MAT_AMBIENT) if (m_textures.find(path) != m_textures.end())
glMaterialfv(GL_FRONT, GL_AMBIENT, &m.ambient[0]); return m_textures[path];
if (m.flags & Material::MAT_DIFFUSE) GLuint id = m_loadtexture(path.c_str());
glMaterialfv(GL_FRONT, GL_DIFFUSE, &m.diffuse[0]); m_textures[path] = id;
if (m.flags & Material::MAT_SPECULAR) return id;
glMaterialfv(GL_FRONT, GL_SPECULAR, &m.specular[0]); }
if (m.flags & Material::MAT_TEXTURE)
{ string WFObj::resolvePath(const string & name)
cerr << "WFObj: error: textured materials not implemented yet" << endl; {
} return (name[0] != '/') ? basePath(m_path) + name : name;
} }
bool WFObj::VertexRef::operator<(const VertexRef & other) const bool WFObj::VertexRef::operator<(const VertexRef & other) const

72
WFObj.h
View File

@ -2,7 +2,12 @@
#ifndef WFOBJ_H #ifndef WFOBJ_H
#define WFOBJ_H #define WFOBJ_H
#ifdef GL_INCLUDE_FILE
#include GL_INCLUDE_FILE
#else
#include <GL/gl.h> #include <GL/gl.h>
#endif
#include <vector> #include <vector>
#include <string> #include <string>
#include <map> #include <map>
@ -14,7 +19,7 @@ public:
class Buffer class Buffer
{ {
public: public:
Buffer() : m_alloc(false) {} Buffer() : m_alloc(false) {data = NULL; length = 0;}
~Buffer() { if (m_alloc) delete data; } ~Buffer() { if (m_alloc) delete data; }
uint8_t *data; uint8_t *data;
size_t length; size_t length;
@ -28,20 +33,48 @@ public:
bool m_alloc; bool m_alloc;
}; };
class Material
{
public:
enum {
SHININESS_BIT = 0x01,
AMBIENT_BIT = 0x02,
DIFFUSE_BIT = 0x04,
SPECULAR_BIT = 0x08,
TEXTURE_BIT = 0x10
};
Material() : flags(0) {}
GLfloat shininess;
GLfloat ambient[4];
GLfloat diffuse[4];
GLfloat specular[4];
GLuint texture;
int flags;
int first_vertex;
int num_vertices;
};
typedef bool (*loadfile_t)(const char *fname, Buffer & buff); typedef bool (*loadfile_t)(const char *fname, Buffer & buff);
typedef GLuint (*loadtexture_t)(const char *fname); typedef GLuint (*loadtexture_t)(const char *fname);
enum { VERTEX, VERTEX_TEXTURE, VERTEX_NORMAL, VERTEX_TYPES }; enum { VERTEX, VERTEX_TEXTURE, VERTEX_NORMAL, VERTEX_TYPES };
/* constructors */ /* constructors */
WFObj(loadfile_t lf = NULL, loadtexture_t lt = NULL); WFObj();
~WFObj(); ~WFObj();
/* methods */ /* methods */
bool load(const char *fname); bool load(const char *fname, loadfile_t lf = NULL, loadtexture_t lt = NULL);
bool load(const Buffer &buff); bool load(const Buffer &buff);
const float * const getAABB() { return m_aabb; } const float * const getAABB() { return m_aabb; }
void draw(); size_t getStride() { return sizeof(GLfloat) * m_n_floats_per_vref; }
size_t getVertexOffset() { return 0; }
size_t getNormalOffset() { return 3 * sizeof(GLfloat); }
size_t getTextureCoordOffset() { return 6 * sizeof(GLfloat); }
void bindBuffers();
size_t getNumMaterials() { return m_num_materials; }
std::map<std::string, Material> & getMaterials() { return m_materials; }
bool doTextures() { return m_do_textures; }
protected: protected:
/* types */ /* types */
@ -59,9 +92,9 @@ protected:
{ {
public: public:
VertexRef() : vertex(0), texture(0), normal(0) {} VertexRef() : vertex(0), texture(0), normal(0) {}
int vertex; size_t vertex;
int texture; size_t texture;
int normal; size_t normal;
bool operator<(const VertexRef & other) const; bool operator<(const VertexRef & other) const;
}; };
@ -71,25 +104,6 @@ protected:
VertexRef vertices[3]; VertexRef vertices[3];
}; };
class Material
{
public:
enum {
MAT_SHININESS = 0x01,
MAT_AMBIENT = 0x02,
MAT_DIFFUSE = 0x04,
MAT_SPECULAR = 0x08,
MAT_TEXTURE = 0x10
};
Material() : flags(0) {}
GLfloat shininess;
GLfloat ambient[4];
GLfloat diffuse[4];
GLfloat specular[4];
std::string texture;
int flags;
};
/* methods */ /* methods */
void clear(); void clear();
void processInputLine(const std::string & input); void processInputLine(const std::string & input);
@ -101,12 +115,12 @@ protected:
std::string getLine(const Buffer & buff, size_t idx, size_t *update_idx); std::string getLine(const Buffer & buff, size_t idx, size_t *update_idx);
void loadMaterial(const std::string & name); void loadMaterial(const std::string & name);
bool buildVBO(); bool buildVBO();
void renderMaterial(const Material & m); GLuint loadTexture(const std::string & path);
std::string resolvePath(const std::string & name);
/* variables */ /* variables */
std::vector<Vertex> m_vertices[VERTEX_TYPES]; std::vector<Vertex> m_vertices[VERTEX_TYPES];
std::map< std::string, std::vector< Face > > m_faces; std::map< std::string, std::vector< Face > > m_faces;
std::map< std::string, std::pair<int, int> > m_face_indices;
std::map< std::string, Material > m_materials; std::map< std::string, Material > m_materials;
float m_aabb[6]; float m_aabb[6];
std::string m_path; std::string m_path;
@ -117,6 +131,8 @@ protected:
GLuint m_data_vbo, m_index_vbo; GLuint m_data_vbo, m_index_vbo;
bool m_do_textures; bool m_do_textures;
size_t m_n_floats_per_vref; size_t m_n_floats_per_vref;
size_t m_num_materials;
std::map<std::string, GLuint> m_textures;
}; };
#endif #endif