From 14aca0a2e821027dc59ff38a8390b946c5fce483 Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 26 Jan 2008 21:34:35 +0000 Subject: [PATCH] initial import git-svn-id: svn://anubis/misc/wfobj@19 bd8a9e45-a331-0410-811e-c64571078777 --- Makefile | 17 ++++ WFObj.cc | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ WFObj.hh | 35 +++++++ driver.cc | 21 +++++ 4 files changed, 346 insertions(+) create mode 100644 Makefile create mode 100644 WFObj.cc create mode 100644 WFObj.hh create mode 100644 driver.cc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4481ea5 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ + +CXX := g++ +CXXFLAGS := -O2 +TARGET := WFObj.o +SOURCE := WFObj.cc +LIBS := -lGL + +all: $(TARGET) driver + +$(TARGET): $(SOURCE) $(SOURCE:.cc=.hh) + $(CXX) -c -o $@ $< $(CXXFLAGS) + +driver: driver.cc $(TARGET) + $(CXX) -o $@ $< $(TARGET) $(CXXFLAGS) $(LIBS) + +clean: + -rm -f *~ *.o diff --git a/WFObj.cc b/WFObj.cc new file mode 100644 index 0000000..7ef037a --- /dev/null +++ b/WFObj.cc @@ -0,0 +1,273 @@ + +#include +#include +#include +#include // isspace() +#include // strlen() +#include +#include +#include +#include +#include +#include "WFObj.hh" +using namespace std; + +#define WHITESPACE " \n\r\t\v" +#define DEBUGGL + +int WFObj::filesize(const char * filename) +{ + struct stat st; + if (stat(filename, &st)) + return -1; + return st.st_size; +} + +bool WFObj::load(const string & filename) +{ + int size = filesize(filename.c_str()); + if (size < 1) + return false; + + ifstream ifs(filename.c_str()); + if (!ifs.is_open()) + return false; + char buf[size+1]; + + string buildup; + while (ifs.good()) + { + ifs.getline(buf, size+1); + string input = trim(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); + } + + ifs.close(); + return true; +} + +string WFObj::trim(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; +} + +void WFObj::processInputLine(const std::string & input) +{ + string line = input; + vector lineParts; + for (;;) + { + string token = stripFirstToken(line); + if (token == "") + break; + lineParts.push_back(token); + } + if (lineParts.size() > 0) + m_data.push_back(lineParts); +} + +string WFObj::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; +} + +GLuint WFObj::render() +{ + GLuint list = glGenLists(1); + glNewList(list, GL_COMPILE); + int len = m_data.size(); + enum { VERTEX, VERTEX_TEXTURE, VERTEX_NORMAL, VERTEX_TYPES }; + vector vertices[VERTEX_TYPES]; + int numVertsLast = 0; + bool inFace = false; + for (int i = 0; i < len; i++) + { + string type = m_data[i][0]; + if (type == "v") + vertices[VERTEX].push_back(readVertex(m_data[i])); + 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] > 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; + } + } + else if (type == "mtllib") + { + } + } + if (inFace) + { +#ifdef DEBUGGL + cout << "glEnd()" << endl; +#endif + glEnd(); + inFace = false; + } + glEndList(); + return list; +} + +WFObj::Vertex WFObj::readVertex(const vector & parts) +{ + int partslen = parts.size(); + Vertex v; + for (int i = 1; i < partslen; i++) + { + sscanf(parts[i].c_str(), "%f", &v[i - 1]); + } + return v; +} + +void WFObj::parseVertexIndices(const string & vtxref, int * ret) +{ + vector parts = splitString(vtxref, '/'); + int num = parts.size(); + for (int i = 0; i < num && i < 3; i++) + sscanf(parts[i].c_str(), "%d", ret + i); +} + +vector WFObj::splitString(const string & str, char delim) +{ + vector 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; +} diff --git a/WFObj.hh b/WFObj.hh new file mode 100644 index 0000000..55d53da --- /dev/null +++ b/WFObj.hh @@ -0,0 +1,35 @@ + +#include +#include +#include + +class WFObj +{ +public: + bool load(const std::string & filename); + GLuint render(); + +private: + /* types */ + class Vertex + { + public: + float operator[](int idx) const { return data[idx]; } + const float & operator[](int idx) { return data[idx]; } + float * getData() { return data; } + private: + float data[4]; + }; + + /* methods */ + std::string trim(std::string s); + int filesize(const char * filename); + void processInputLine(const std::string & input); + std::string stripFirstToken(std::string & input); + Vertex readVertex(const std::vector & parts); + void parseVertexIndices(const std::string & vtxref, int * ret); + std::vector splitString(const std::string & str, char delim); + + /* variables */ + std::vector< std::vector > m_data; +}; diff --git a/driver.cc b/driver.cc new file mode 100644 index 0000000..f339a97 --- /dev/null +++ b/driver.cc @@ -0,0 +1,21 @@ + +#include +#include "WFObj.hh" +using namespace std; + +int main(int argc, char * argv[]) +{ + WFObj w; + if (argc < 2) + { + cout << "Usage: " << argv[0] << " " << endl; + return -2; + } + if (!w.load(argv[1])) + { + cout << "Couldn't open '" << argv[1] << "'!" << endl; + return -1; + } + w.render(); + return 0; +}