From 18f47b3603ffcd5405f3322db5db2501e9a94985 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 11 Mar 2014 04:19:01 +0100 Subject: [PATCH] OBJ class for representing .obj files. --- Escape-the-Dawn/Escape-the-Dawn.vcxproj | 2 + .../Escape-the-Dawn.vcxproj.filters | 2 + Escape-the-Dawn/OBJ.cpp | 217 ++++++++++++++++++ Escape-the-Dawn/OBJ.h | 64 ++++++ 4 files changed, 285 insertions(+) create mode 100644 Escape-the-Dawn/OBJ.cpp create mode 100644 Escape-the-Dawn/OBJ.h diff --git a/Escape-the-Dawn/Escape-the-Dawn.vcxproj b/Escape-the-Dawn/Escape-the-Dawn.vcxproj index 5ba9649..ad8b4ce 100644 --- a/Escape-the-Dawn/Escape-the-Dawn.vcxproj +++ b/Escape-the-Dawn/Escape-the-Dawn.vcxproj @@ -104,6 +104,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/Escape-the-Dawn/Escape-the-Dawn.vcxproj.filters b/Escape-the-Dawn/Escape-the-Dawn.vcxproj.filters index 80dae46..70e92ec 100644 --- a/Escape-the-Dawn/Escape-the-Dawn.vcxproj.filters +++ b/Escape-the-Dawn/Escape-the-Dawn.vcxproj.filters @@ -44,6 +44,7 @@ GUI + @@ -142,6 +143,7 @@ + diff --git a/Escape-the-Dawn/OBJ.cpp b/Escape-the-Dawn/OBJ.cpp new file mode 100644 index 0000000..fb1ae79 --- /dev/null +++ b/Escape-the-Dawn/OBJ.cpp @@ -0,0 +1,217 @@ +#include "OBJ.h" + +OBJ::OBJ() +{ + m_CurrentMaterial = nullptr; +} + +void OBJ::LoadFromFile(std::string filename) +{ + m_Path = boost::filesystem::path(filename); + LOG_INFO("Parsing .obj \"%s\"", m_Path.c_str()); + + // http://paulbourke.net/dataformats/obj/ + std::ifstream file(m_Path.string()); + + 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 = { -1, -1, -1 }; + + 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); + } + } +} + +void OBJ::ParseMaterial() +{ + // http://paulbourke.net/dataformats/mtl/ + std::ifstream file(m_MaterialPath.string()); + + 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); + 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; + } + } +} diff --git a/Escape-the-Dawn/OBJ.h b/Escape-the-Dawn/OBJ.h new file mode 100644 index 0000000..a8f241f --- /dev/null +++ b/Escape-the-Dawn/OBJ.h @@ -0,0 +1,64 @@ +#ifndef OBJ_h__ +#define OBJ_h__ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "logging.h" + +class OBJ +{ +public: + struct MaterialInfo + { + std::string TextureFile; + std::tuple AmbientColor; + std::tuple DiffuseColor; + std::tuple SpecularColor; + std::tuple TransmissionFilter; + float OpticalDensity; + float Alpha; + float Shininess; + int IlluminationModel; + }; + + struct FaceDefinition + { + int VertexIndex; + int TextureCoordIndex; + int NormalIndex; + }; + + struct Face + { + std::vector Definitions; + MaterialInfo* Material; + }; + + OBJ(); + OBJ(std::string filename) { LoadFromFile(filename); } + + std::vector> Vertices; + std::vector> Normals; + std::vector> TextureCoords; + std::vector Faces; + std::map Materials; + + void LoadFromFile(std::string filename); + +private: + boost::filesystem::path m_Path; + boost::filesystem::path m_MaterialPath; + MaterialInfo* m_CurrentMaterial; + + void ParseMaterial(); +}; + +#endif // OBJ_h__ \ No newline at end of file