#ifndef MTLREADER_H #define MTLREADER_H #include #include #include #include #include "../../../geo/Point2.h" #include "../../../geo/Point3.h" /** * prase .mtl files */ class MTLReader { public: struct Material { std::string textureFile = ""; Point3 diffuse = Point3(1,1,1); float alpha = 1.0; }; Material* cur = nullptr; std::unordered_map map; /** ctor. use readXYZ() */ MTLReader() { ; } /** read .mtl from the given file */ void readFile(const std::string& file) { std::ifstream is(file); std::string line; while(getline(is, line)) {parseLine(line);} is.close(); } /** read mtl from the given data string (.mtl file contents) */ void readData(const char* data) { readData(std::string(data)); } /** read mtl from the given data string (.mtl file contents) */ void readData(const std::string& data) { std::stringstream is(data); std::string line; while(getline(is, line)) {parseLine(line);} } /** get the given material */ const Material& getMaterial(const std::string& mat) const { const auto& it = map.find(mat); if (it == map.end()) {throw Exception("material not available");} return it->second; } private: template void split(const std::string &s, char delim, Out result) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { *(result++) = item; } } void replaceAll(std::string& str, const std::string& from, const std::string& to) { size_t start_pos = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { size_t end_pos = start_pos + from.length(); str.replace(start_pos, end_pos, to); start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } /** remove empty strings from the vector */ std::vector nonEmpty(const std::vector& src) { std::vector res; for (const std::string& s : src) { if (!s.empty()) {res.push_back(s);} } return res; } std::vector split(const std::string &s, char delim) { std::vector elems; split(s, delim, std::back_inserter(elems)); return elems; } /** parse one line of the .obj file */ void parseLine(std::string line) { if (line.length() < 2) {return;} // remove leading "#" while (line[0] == ' ' || line[0] == '\t') { line.erase(line.begin()); } // remove other linebreaks replaceAll(line, "\r", ""); const std::vector tokens = nonEmpty(split(line, ' ')); const std::string token = tokens.front(); if ("newmtl" == token) { const std::string id = tokens[1]; map[id] = Material(); cur = &map[id]; } else if ("map_Ka" == token) { const std::string texFile = tokens[1]; cur->textureFile = texFile; } else if ("map_Kd" == token) { const std::string texFile = tokens[1]; cur->textureFile = texFile; } else if ("Kd" == token) { cur->diffuse.x = std::stof(tokens[1]); cur->diffuse.y = std::stof(tokens[2]); cur->diffuse.z = std::stof(tokens[3]); } else if ("d" == token) { cur->alpha = std::stof(tokens[1]); } } }; #endif // MTLREADER_H