/* 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; }