Files
escape-the-dawn/Escape-the-Dawn/OBJ.cpp
T

231 lines
4.7 KiB
C++

#include "OBJ.h"
OBJ::OBJ()
{
m_CurrentMaterial = nullptr;
}
bool OBJ::LoadFromFile(std::string filename)
{
m_Path = boost::filesystem::path(filename);
// http://paulbourke.net/dataformats/obj/
std::ifstream file(m_Path.string());
if (!file.is_open()) {
LOG_ERROR("Failed to open .obj \"%s\"", m_Path.string().c_str());
return false;
}
LOG_INFO("Parsing .obj \"%s\"", m_Path.string().c_str());
std::string line;
while (std::getline(file, line)) {
if (line.length() == 0)
continue;
std::stringstream ss(line);
std::string prefix;
ss >> prefix;
// Ignore comments
if (prefix == "#")
continue;
// Material files
if (prefix == "mtllib") {
std::string materialFilename;
ss >> materialFilename;
m_MaterialPath = m_Path.branch_path() / materialFilename;
ParseMaterial();
continue;
}
// Material statement
if (prefix == "usemtl") {
std::string material;
ss >> material;
m_CurrentMaterial = &Materials[material];
continue;
}
// Vertices
if (prefix == "v") {
float x, y, z;
ss >> x >> y >> z;
Vertices.push_back(std::make_tuple(x, y, z));
continue;
}
// Normals
if (prefix == "vn") {
float x, y, z;
ss >> x >> y >> z;
Normals.push_back(std::make_tuple(x, y, z));
}
// Texture coordinates
if (prefix == "vt") {
float u, v, w;
ss >> u >> v >> w;
TextureCoords.push_back(std::make_tuple(u, v, w));
}
// Face definitions
if (prefix == "f") {
Face face;
face.Material = m_CurrentMaterial;
std::string faceDefString;
while (ss >> faceDefString) {
std::stringstream ss2(faceDefString);
FaceDefinition faceDef = { 0, 0, 0 };
ss2 >> faceDef.VertexIndex;
ss2.ignore(); // Ignore first delimiter
if (!ss2)
continue;
if (ss2.peek() == '/') {
ss2.ignore();
ss2 >> faceDef.NormalIndex;
} else {
ss2 >> faceDef.TextureCoordIndex;
ss2.ignore();
ss2 >> faceDef.NormalIndex;
}
face.Definitions.push_back(faceDef);
}
Faces.push_back(face);
}
}
return true;
}
void OBJ::ParseMaterial()
{
// http://paulbourke.net/dataformats/mtl/
std::ifstream file(m_MaterialPath.string());
if (!file.is_open()) {
LOG_ERROR("Failed to open .mtl \"%s\"", m_MaterialPath.string().c_str());
return;
}
LOG_INFO("Parsing .mtl \"%s\"", m_MaterialPath.string().c_str());
std::string currentMaterialName;
MaterialInfo* currentMaterial = nullptr;
std::string line;
while (std::getline(file, line)) {
if (line.length() == 0)
continue;
std::stringstream ss(line);
std::string prefix;
ss >> prefix;
// Create a new material definition
if (prefix == "newmtl") {
MaterialInfo mat =
{
"",
std::make_tuple(0.2f, 0.2f, 0.2f),
std::make_tuple(0.8f, 0.8f, 0.8f),
std::make_tuple(1.0f, 1.0f, 1.0f),
std::make_tuple(1.0f, 1.0f, 1.0f),
1.0f,
1.0f,
0.0f,
0,
};
ss >> currentMaterialName;
LOG_INFO("Parsing material %s", currentMaterialName.c_str());
Materials[currentMaterialName] = mat;
currentMaterial = &Materials[currentMaterialName];
continue;
}
if (!currentMaterial)
continue;
// Ambient color
if (prefix == "Ka") {
float r, g, b;
ss >> r >> g >> b;
currentMaterial->AmbientColor = std::make_tuple(r, g, b);
continue;
}
// Diffuse color
if (prefix == "Kd") {
float r, g, b;
ss >> r >> g >> b;
currentMaterial->DiffuseColor = std::make_tuple(r, g, b);
continue;
}
// Specular color
if (prefix == "Ks") {
float r, g, b;
ss >> r >> g >> b;
currentMaterial->SpecularColor = std::make_tuple(r, g, b);
continue;
}
// Transmission filter
if (prefix == "Tf") {
std::stringstream ss2;
ss2 << ss.str();
std::string command;
ss2 >> command;
if (command == "xyz") {
// TODO: "The "Ks xyz" statement specifies the specular reflectivity using CIEXYZ values."
}
else if (command == "spectral") {
// TODO: "The "Tf spectral" statement specifies the transmission filter using a spectral curve."
} else {
float r, g, b;
ss >> r;
// G and B are optional
if (!(ss >> g >> b))
{
g = r;
b = r;
}
currentMaterial->TransmissionFilter = std::make_tuple(r, g, b);
}
continue;
}
// Optical density
if (prefix == "Ni") {
ss >> currentMaterial->OpticalDensity;
continue;
}
// Alpha
if (prefix == "d" || prefix == "Tr") {
ss >> currentMaterial->Alpha;
continue;
}
// Shininess
if (prefix == "Ns") {
ss >> currentMaterial->Shininess;
continue;
}
// Illumination model
if (prefix == "illum") {
int illum = 0;
ss >> illum;
currentMaterial->IlluminationModel = illum;
continue;
}
// Texture file
// TODO:
if (prefix == "map_Ka" || prefix == "map_Kd") {
ss >> currentMaterial->TextureFile;
continue;
}
}
}