212 lines
7.5 KiB
C++
212 lines
7.5 KiB
C++
/*
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
Copyright (c) 2007-2010 by Wenzel Jakob and others.
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License Version 3
|
|
as published by the Free Software Foundation.
|
|
|
|
Mitsuba 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define BOOST_FILESYSTEM_NO_LIB
|
|
#define BOOST_SYSTEM_NO_LIB
|
|
|
|
#include <mitsuba/core/plugin.h>
|
|
#include <mitsuba/core/fstream.h>
|
|
#include <mitsuba/render/scene.h>
|
|
#include <boost/filesystem/fstream.hpp>
|
|
#include "converter.h"
|
|
|
|
std::string copyTexture(GeometryConverter *cvt, const fs::path &textureDir, std::string filename) {
|
|
SLog(EInfo, "Copying texture \"%s\" ..", filename.c_str());
|
|
|
|
boost::filesystem::path path = boost::filesystem::path(filename);
|
|
fs::path targetPath = textureDir / path.leaf();
|
|
fs::path resolved = filename;
|
|
|
|
if (!fs::exists(targetPath)) {
|
|
ref<FileResolver> fRes = Thread::getThread()->getFileResolver();
|
|
if (!fs::exists(resolved)) {
|
|
resolved = fRes->resolve(path.leaf());
|
|
if (!fs::exists(resolved)) {
|
|
SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), resolved.file_string().c_str());
|
|
resolved = cvt->locateResource(path.leaf());
|
|
targetPath = targetPath.parent_path() / resolved.leaf();
|
|
if (resolved.empty())
|
|
SLog(EError, "Unable to locate a resource -- aborting conversion.");
|
|
}
|
|
}
|
|
|
|
if (fs::complete(resolved) != fs::complete(targetPath)) {
|
|
ref<FileStream> input = new FileStream(resolved, FileStream::EReadOnly);
|
|
ref<FileStream> output = new FileStream(targetPath, FileStream::ETruncReadWrite);
|
|
input->copyTo(output);
|
|
output->close();
|
|
input->close();
|
|
}
|
|
}
|
|
|
|
return targetPath.leaf();
|
|
}
|
|
|
|
void addMaterial(GeometryConverter *cvt, std::ostream &os, const std::string &mtlName,
|
|
const fs::path &texturesDir, const Spectrum &diffuseValue,
|
|
const std::string &diffuseMap, const std::string maskMap) {
|
|
if (mtlName == "")
|
|
return;
|
|
SLog(EInfo, "Copying material \"%s\" ..", mtlName.c_str());
|
|
std::string indent = "";
|
|
|
|
if (maskMap != "") {
|
|
indent = "\t";
|
|
os << "\t<bsdf id=\"" << mtlName << "\" type=\"mask\">" << endl;
|
|
os << "\t\t<texture name=\"opacity\" type=\"ldrtexture\">" << endl;
|
|
os << "\t\t\t<string name=\"filename\" value=\"textures/" << copyTexture(cvt, texturesDir, maskMap) << "\"/>" << endl;
|
|
os << "\t\t</texture>" << endl;
|
|
os << "\t\t<bsdf type=\"lambertian\">" << endl;
|
|
} else {
|
|
os << "\t<bsdf id=\"" << mtlName << "\" type=\"lambertian\">" << endl;
|
|
}
|
|
|
|
if (diffuseMap == "") {
|
|
Float r, g, b;
|
|
diffuseValue.toLinearRGB(r, g, b);
|
|
os << indent << "\t\t<rgb name=\"reflectance\" value=\""
|
|
<< r << " " << g << " " << b << "\"/>" << endl;
|
|
} else {
|
|
os << indent << "\t\t<texture name=\"reflectance\" type=\"ldrtexture\">" << endl
|
|
<< indent << "\t\t\t<string name=\"filename\" value=\"textures/" << copyTexture(cvt, texturesDir, diffuseMap) << "\"/>" << endl
|
|
<< indent << "\t\t</texture>" << endl;
|
|
}
|
|
|
|
os << indent << "\t</bsdf>" << endl << endl;
|
|
|
|
if (maskMap != "")
|
|
os << "\t</bsdf>" << endl;
|
|
}
|
|
|
|
void parseMaterials(GeometryConverter *cvt, std::ostream &os, const fs::path &texturesDir,
|
|
const fs::path &mtlFileName, std::set<std::string> &mtlList) {
|
|
SLog(EInfo, "Loading OBJ materials from \"%s\" ..", mtlFileName.file_string().c_str());
|
|
fs::ifstream is(mtlFileName);
|
|
if (is.bad() || is.fail())
|
|
SLog(EError, "Unexpected I/O error while accessing material file '%s'!",
|
|
mtlFileName.file_string().c_str());
|
|
std::string buf, line;
|
|
std::string mtlName;
|
|
Spectrum diffuse(0.0f);
|
|
std::string diffuseMap, maskMap;
|
|
|
|
while (is >> buf) {
|
|
if (buf == "newmtl") {
|
|
mtlList.insert(mtlName);
|
|
addMaterial(cvt, os, mtlName, texturesDir, diffuse, diffuseMap, maskMap);
|
|
std::getline(is, line);
|
|
mtlName = trim(line.substr(1, line.length()-1));
|
|
diffuse = Spectrum(0.0f);
|
|
diffuseMap = "";
|
|
maskMap = "";
|
|
} else if (buf == "Kd") {
|
|
Float r, g, b;
|
|
is >> r >> g >> b;
|
|
if (cvt->m_srgb)
|
|
diffuse.fromSRGB(r, g, b);
|
|
else
|
|
diffuse.fromLinearRGB(r, g, b);
|
|
} else if (buf == "map_Kd") {
|
|
std::getline(is, line);
|
|
diffuseMap = trim(line.substr(1, line.length()-1));
|
|
} else if (buf == "map_d") {
|
|
std::getline(is, line);
|
|
maskMap = trim(line.substr(1, line.length()-1));
|
|
} else {
|
|
/* Ignore */
|
|
std::getline(is, line);
|
|
}
|
|
}
|
|
addMaterial(cvt, os, mtlName, texturesDir, diffuse, diffuseMap, maskMap);
|
|
}
|
|
|
|
void GeometryConverter::convertOBJ(const fs::path &inputFile,
|
|
std::ostream &os,
|
|
const fs::path &textureDirectory,
|
|
const fs::path &meshesDirectory) {
|
|
|
|
fs::ifstream is(inputFile);
|
|
if (is.bad() || is.fail())
|
|
SLog(EError, "Could not open OBJ file '%s'!", inputFile.file_string().c_str());
|
|
|
|
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << endl;
|
|
os << "<!--" << endl << endl;
|
|
os << "\tAutomatically converted from Wavefront OBJ" << endl << endl;
|
|
os << "-->" << endl << endl;
|
|
os << "<scene>" << endl;
|
|
os << "\t<integrator id=\"integrator\" type=\"direct\"/>" << endl << endl;
|
|
|
|
std::string buf, line;
|
|
std::set<std::string> mtlList;
|
|
while (is >> buf) {
|
|
if (buf == "mtllib" && m_importMaterials) {
|
|
std::getline(is, line);
|
|
std::string mtlName = trim(line.substr(1, line.length()-1));
|
|
ref<FileResolver> fRes = Thread::getThread()->getFileResolver()->clone();
|
|
fRes->addPath(fs::complete(fRes->resolve(inputFile)).parent_path());
|
|
fs::path fullMtlName = fRes->resolve(mtlName);
|
|
if (fs::exists(fullMtlName))
|
|
parseMaterials(this, os, textureDirectory, fullMtlName, mtlList);
|
|
else
|
|
SLog(EWarn, "Could not find referenced material library '%s'", mtlName.c_str());
|
|
} else {
|
|
/* Ignore */
|
|
std::getline(is, line);
|
|
}
|
|
}
|
|
|
|
Properties objProps("obj");
|
|
objProps.setString("filename", inputFile.file_string());
|
|
|
|
ref<Shape> rootShape = static_cast<Shape *> (PluginManager::getInstance()->
|
|
createObject(Shape::m_theClass, objProps));
|
|
SAssert(rootShape->isCompound());
|
|
|
|
int ctr = 0;
|
|
while (true) {
|
|
TriMesh *mesh = static_cast<TriMesh *>(rootShape->getElement(ctr++));
|
|
if (!mesh)
|
|
break;
|
|
os << "\t<shape id=\"" << mesh->getName() << "\" type=\"serialized\">" << endl;
|
|
|
|
if (!m_geometryFile) {
|
|
std::string filename = mesh->getName() + std::string(".serialized");
|
|
SLog(EInfo, "Saving \"%s\"", filename.c_str());
|
|
ref<FileStream> stream = new FileStream(meshesDirectory / filename, FileStream::ETruncReadWrite);
|
|
stream->setByteOrder(Stream::ELittleEndian);
|
|
mesh->serialize(stream);
|
|
stream->close();
|
|
os << "\t\t<string name=\"filename\" value=\"meshes/" << filename.c_str() << "\"/>" << endl;
|
|
} else {
|
|
m_geometryDict.push_back(m_geometryFile->getPos());
|
|
SLog(EInfo, "Saving mesh \"%s\"", mesh->getName().c_str());
|
|
mesh->serialize(m_geometryFile);
|
|
os << "\t\t<string name=\"filename\" value=\"" << m_geometryFileName.filename() << "\"/>" << endl;
|
|
os << "\t\t<integer name=\"shapeIndex\" value=\"" << (m_geometryDict.size()-1) << "\"/>" << endl;
|
|
}
|
|
|
|
if (mesh->getBSDF() != NULL &&
|
|
mtlList.find(mesh->getBSDF()->getName()) != mtlList.end()) {
|
|
const std::string &matID = mesh->getBSDF()->getName();
|
|
os << "\t\t<ref name=\"bsdf\" id=\"" << matID << "\"/>" << endl;
|
|
}
|
|
os << "\t</shape>" << endl << endl;
|
|
}
|
|
os << "</scene>" << endl;
|
|
}
|