#include #include #include #include // isspace() #include // strlen() #include #include #include #include #include #include #include "WFMtl.hh" using namespace std; #define WHITESPACE " \n\r\t\v" #define DEBUGGL void WFMtl::clear() { m_data = map< string, vector< vector > >(); m_currentMaterialName = ""; m_attributesPushed = false; } int WFMtl::filesize(const char * filename) { struct stat st; if (stat(filename, &st)) return -1; return st.st_size; } bool WFMtl::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); } /* DEBUG */ map > >::iterator it = m_data.begin(); while (it != m_data.end()) { cout << "Material '" << it->first << "':" << endl; for (int i = 0; i < it->second.size(); i++) { cout << " "; for (int j = 0; j < it->second[i].size(); j++) { cout << '\'' << it->second[i][j] << "' "; } cout << endl; } it++; } /* END DEBUG */ ifs.close(); return true; } string WFMtl::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 WFMtl::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) { if ( (lineParts.size() >= 2) && (lineParts[0] == "newmtl") ) { m_currentMaterialName = lineParts[1]; } else if (m_currentMaterialName != "") { m_data[m_currentMaterialName].push_back(lineParts); } } } string WFMtl::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; } void WFMtl::renderBegin(const string & mtlname) { map< string, vector< vector > >::iterator it = m_data.find(mtlname); if (it == m_data.end()) return; vector< vector > & stmts = it->second; int num_stmts = stmts.size(); bool foundTexture = false; bool didSomething = false; 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 == "map_Kd") /* load a diffuse texture */ { /* TODO: figure out how i want to load the texture */ foundTexture = true; didSomething = true; } } if (didSomething) { pushAttributes(); 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); } } } void WFMtl::pushAttributes() { if (m_attributesPushed) return; m_attributesPushed = true; #ifdef DEBUGGL cout << " glPushAttrib(GL_LIGHTING_BIT | GL_TEXTURE_BIT)" << endl; #endif glPushAttrib(GL_LIGHTING_BIT | GL_TEXTURE_BIT); } void WFMtl::renderEnd(const string & mtlname) { map< string, vector< vector > >::iterator it = m_data.find(mtlname); if (it == m_data.end()) return; if (m_attributesPushed) { #ifdef DEBUGGL cout << " glPopAttrib()" << endl; #endif glPopAttrib(); } }