diff --git a/Makefile b/Makefile index 4d801a2..b6432bd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CXX := g++ CXXFLAGS := -O2 -SOURCE := WFObj.cc WFMtl.cc driver.cc +SOURCE := WFObj.cc driver.cc OBJS := $(SOURCE:.cc=.o) LDFLAGS := -lGL TARGET := driver @@ -11,8 +11,8 @@ all: $(TARGET) $(TARGET): $(OBJS) $(CXX) -o $@ $^ $(LDFLAGS) -%.o: %.cc - $(CXX) -c -o $@ $^ $(CXXFLAGS) +%.o: %.cc %.hh + $(CXX) -c -o $@ $< $(CXXFLAGS) clean: -rm -f *~ *.o $(TARGET) diff --git a/WFMtl.cc b/WFMtl.cc deleted file mode 100644 index 6c588bd..0000000 --- a/WFMtl.cc +++ /dev/null @@ -1,251 +0,0 @@ - -#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(); - } -} - diff --git a/WFMtl.hh b/WFMtl.hh deleted file mode 100644 index 281127a..0000000 --- a/WFMtl.hh +++ /dev/null @@ -1,27 +0,0 @@ - -#include -#include -#include -#include - -class WFMtl -{ -public: - bool load(const std::string & filename); - void renderBegin(const std::string & mtlname); - void renderEnd(const std::string & mtlname); - -private: - /* methods */ - void clear(); - std::string trim(std::string s); - int filesize(const char * filename); - void processInputLine(const std::string & input); - std::string stripFirstToken(std::string & input); - void pushAttributes(); - - /* variables */ - std::map< std::string, std::vector< std::vector > > m_data; - std::string m_currentMaterialName; - bool m_attributesPushed; -}; diff --git a/WFObj.cc b/WFObj.cc index f9ecc0a..ef511c1 100644 --- a/WFObj.cc +++ b/WFObj.cc @@ -7,15 +7,68 @@ #include #include #include +#include #include #include #include "WFObj.hh" -#include "WFMtl.hh" 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 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; +} + +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 ""; +} + +/****** WFObj functions ******/ + void WFObj::clear() { m_data = std::vector< std::vector >(); @@ -29,7 +82,7 @@ int WFObj::filesize(const char * filename) return st.st_size; } -bool WFObj::load(const string & filename) +bool WFObj::load(const string & filename, loadTextureFunc_t loadTexture) { clear(); @@ -46,7 +99,7 @@ bool WFObj::load(const string & filename) while (ifs.good()) { ifs.getline(buf, size+1); - string input = trim(buf); + string input = trimString(buf); int sz = input.size(); if (sz == 0 || input[0] == '#') continue; @@ -63,18 +116,11 @@ bool WFObj::load(const string & filename) } ifs.close(); + m_loadTexture = loadTexture; + m_fileName = filename; 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) { @@ -91,16 +137,6 @@ void WFObj::processInputLine(const std::string & input) 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() { @@ -247,7 +283,7 @@ GLuint WFObj::render() { if (m_data[i].size() >= 2) { - material.load(m_data[i][1]); + material.load(basePath(m_fileName) + m_data[i][1], m_loadTexture); } } } @@ -287,18 +323,235 @@ void WFObj::parseVertexIndices(const string & vtxref, int * ret) sscanf(parts[i].c_str(), "%d", ret + i); } -vector WFObj::splitString(const string & str, char delim) + + + +/****** WFMtl functions ******/ + +void WFMtl::clear() { - 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; + 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, WFObj::loadTextureFunc_t loadTexture) +{ + 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 = 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); + } + + /* 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(); + m_loadTexture = loadTexture; + m_fileName = filename; + return true; +} + +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); + } + } +} + +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 */ + if (stmts[i].size() == 2) + { + GLuint tex = m_loadTexture( (basePath(m_fileName) + + stmts[i][1]).c_str() ); + if (tex > 0) + { +#ifdef DEBUGGL + cout << " glBindTexture(GL_TEXTURE_2D, " << tex << ")" << endl; +#endif + glBindTexture(GL_TEXTURE_2D, tex); + 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(); + } +} + diff --git a/WFObj.hh b/WFObj.hh index e2cad68..f5dde51 100644 --- a/WFObj.hh +++ b/WFObj.hh @@ -2,11 +2,13 @@ #include #include #include +#include class WFObj { public: - bool load(const std::string & filename); + typedef GLuint (*loadTextureFunc_t)(const char * texture); + bool load(const std::string & filename, loadTextureFunc_t loadTexture); GLuint render(); private: @@ -23,14 +25,36 @@ private: /* methods */ void clear(); - 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; + loadTextureFunc_t m_loadTexture; + std::string m_fileName; +}; + + +class WFMtl +{ +public: + bool load(const std::string & filename, WFObj::loadTextureFunc_t loadTexture); + void renderBegin(const std::string & mtlname); + void renderEnd(const std::string & mtlname); + +private: + /* methods */ + void clear(); + int filesize(const char * filename); + void processInputLine(const std::string & input); + void pushAttributes(); + + /* variables */ + std::map< std::string, std::vector< std::vector > > m_data; + std::string m_currentMaterialName; + bool m_attributesPushed; + WFObj::loadTextureFunc_t m_loadTexture; + std::string m_fileName; }; diff --git a/driver.cc b/driver.cc index f339a97..eeb8d54 100644 --- a/driver.cc +++ b/driver.cc @@ -1,8 +1,15 @@ +#include #include #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; @@ -11,7 +18,7 @@ int main(int argc, char * argv[]) cout << "Usage: " << argv[0] << " " << endl; return -2; } - if (!w.load(argv[1])) + if (!w.load(argv[1], &loadTexture)) { cout << "Couldn't open '" << argv[1] << "'!" << endl; return -1;