Files
squidout/src/game/Rendering/OBJ.cpp
T

427 lines
9.6 KiB
C++

/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Rendering/OBJ.h"
bool dd::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\": %s", m_Path.string().c_str(), strerror(errno));
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 dd::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;
unsigned int currentLine = 0;
std::string line;
while (std::getline(file, line))
{
currentLine++;
if (line.length() == 0)
continue;
std::stringstream ss(line);
std::string prefix;
ss >> prefix;
// Create a new material definition
if (prefix == "newmtl")
{
MaterialInfo mat;
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;
}
// Diffuse texture
if (prefix == "map_Kd")
{
MaterialInfo::ColorMap colorMap;
std::string fileName;
std::string arg;
while (ss >> arg)
{
ParseColorMap(currentLine, ss, prefix, arg, colorMap);
}
// HACK: Should we really have to specify the full FilePath here?
colorMap.FileName = (m_MaterialPath.branch_path() / colorMap.FileName).string();
currentMaterial->DiffuseTexture = colorMap;
continue;
}
// Specular map
if (prefix == "map_Ks")
{
MaterialInfo::ColorMap colorMap;
std::string fileName;
std::string arg;
while (ss >> arg)
{
ParseColorMap(currentLine, ss, prefix, arg, colorMap);
}
// HACK: Should we really have to specify the full FilePath here?
colorMap.FileName = (m_MaterialPath.branch_path() / colorMap.FileName).string();
currentMaterial->SpecularMap = colorMap;
continue;
}
// Normal map (bump map)
if (prefix == "bump" || prefix == "map_Bump" )
{
MaterialInfo::BumpMap bumpMap;
std::string fileName;
std::string arg;
while (ss >> arg)
{
ParseBumpMap(currentLine, ss, prefix, arg, bumpMap);
}
// HACK: Should we really have to specify the full FilePath here?
bumpMap.FileName = (m_MaterialPath.branch_path() / bumpMap.FileName).string();
currentMaterial->NormalMap = bumpMap;
continue;
}
}
}
void dd::OBJ::ParseTextureMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::TextureMap &textureMap)
{
if (arg == "-blendu")
{
std::string val;
ss >> val;
if (val == "off")
textureMap.blendu = false;
else if (val == "on")
textureMap.blendu = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else if (arg == "-blendv")
{
std::string val;
ss >> val;
if (val == "off")
textureMap.blendv = false;
else if (val == "on")
textureMap.blendv = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else if (arg == "-clamp")
{
std::string val;
ss >> val;
if (val == "off")
textureMap.clamp = false;
else if (val == "on")
textureMap.clamp = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else if (arg == "-o")
{
float u, v, w;
if (ss >> u >> v >> w)
{
textureMap.o = std::make_tuple(u, v, w);
}
else
{
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
}
else if (arg == "-s")
{
float u, v, w;
if (ss >> u >> v >> w)
{
textureMap.s = std::make_tuple(u, v, w);
}
else
{
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
}
// Assume unrecognized options is part of the file name
else
{
if (!textureMap.FileName.empty())
textureMap.FileName += " ";
textureMap.FileName += arg;
}
}
void dd::OBJ::ParseColorMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::ColorMap &colorMap)
{
if (arg == "-cc")
{
if (prefix != "map_Kd" || prefix != "map_Ks")
{
LOG_ERROR("Invalid MTL argument \"%s\" to option \"%s\" on line %i", arg.c_str(), prefix.c_str(), line);
return;
}
std::string val;
if (ss >> val)
{
if (val == "off")
colorMap.cc = false;
else if (val == "on")
colorMap.cc = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else
{
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
}
else
{
ParseTextureMap(line, ss, prefix, arg, colorMap);
}
}
void dd::OBJ::ParseBumpMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::BumpMap &bumpMap)
{
if (arg == "-bm")
{
if (prefix != "bump")
{
LOG_ERROR("Invalid MTL argument \"%s\" to option \"%s\" on line %i", arg.c_str(), prefix.c_str(), line);
return;
}
float val;
if (ss >> val)
bumpMap.bm = val;
else
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
else
{
ParseTextureMap(line, ss, prefix, arg, bumpMap);
}
}