226 lines
4.7 KiB
C++
226 lines
4.7 KiB
C++
#include "OBJ.h"
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|