146 lines
3.5 KiB
C++
146 lines
3.5 KiB
C++
/*
|
||
* © Copyright 2014 – Urheberrechtshinweis
|
||
* Alle Rechte vorbehalten / All Rights Reserved
|
||
*
|
||
* Programmcode ist urheberrechtlich geschuetzt.
|
||
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
|
||
* Keine Verwendung ohne explizite Genehmigung.
|
||
* (vgl. § 106 ff UrhG / § 97 UrhG)
|
||
*/
|
||
|
||
#ifndef MTLREADER_H
|
||
#define MTLREADER_H
|
||
|
||
#include <vector>
|
||
#include <unordered_map>
|
||
#include <string>
|
||
#include <fstream>
|
||
#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<std::string, Material> 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<typename Out>
|
||
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<std::string> nonEmpty(const std::vector<std::string>& src) {
|
||
std::vector<std::string> res;
|
||
for (const std::string& s : src) {
|
||
if (!s.empty()) {res.push_back(s);}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
std::vector<std::string> split(const std::string &s, char delim) {
|
||
std::vector<std::string> 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<std::string> 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
|