#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 void WFObj::clear() { m_data = std::vector< std::vector >(); } 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) { clear(); 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 <= 4; 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; }