/* 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_USE #include "converter.h" class ImporterDOMErrorHandler : public DOMErrorHandler { public: inline ImporterDOMErrorHandler() { } bool handleError(const DOMError& domError) { SLog(EWarn, "%s (line %i, char %i): %s", XMLString::transcode(domError.getLocation()->getURI()), domError.getLocation()->getLineNumber(), domError.getLocation()->getColumnNumber(), XMLString::transcode(domError.getMessage())); if (domError.getSeverity() != DOMError::DOM_SEVERITY_WARNING) SLog(EError, "Encountered a critical DOM error -- giving up!"); return true; } }; void findRemovals(DOMNode *node, std::set &removals) { if (node) { char *nodeName = XMLString::transcode(node->getNodeName()); if (strcmp(nodeName, "ref") == 0) { XMLString::release(&nodeName); return; } XMLString::release(&nodeName); if (node->getNodeType() == DOMNode::ELEMENT_NODE && node->hasAttributes()) { DOMNamedNodeMap *attributes = node->getAttributes(); for (size_t i=0; igetLength(); ++i) { DOMAttr *attribute = (DOMAttr*) attributes->item(i); char *name = XMLString::transcode(attribute->getName()); char *value = XMLString::transcode(attribute->getValue()); if (strcmp(name, "id") == 0) removals.insert(value); XMLString::release(&name); XMLString::release(&value); } } for (DOMNode *child = node->getFirstChild(); child != 0; child=child->getNextSibling()) findRemovals(child, removals); } } bool cleanupPass(DOMNode *node, const std::set &removals) { if (node) { char *nodeName = XMLString::transcode(node->getNodeName()); if (strcmp(nodeName, "ref") == 0) { XMLString::release(&nodeName); return false; } if (node->getNodeType() == DOMNode::ELEMENT_NODE && node->hasAttributes()) { DOMNamedNodeMap *attributes = node->getAttributes(); for (size_t i=0; igetLength(); ++i) { DOMAttr *attribute = (DOMAttr*) attributes->item(i); char *name = XMLString::transcode(attribute->getName()); char *value = XMLString::transcode(attribute->getValue()); if (strcmp(name, "id") == 0 && removals.find(value) != removals.end()) { XMLString::release(&name); XMLString::release(&value); return true; /* Remove this node */ } XMLString::release(&name); XMLString::release(&value); } XMLString::release(&nodeName); } else if (node->getNodeType() == DOMNode::TEXT_NODE) { return true; } DOMNode *child = node->getFirstChild(); while (child) { DOMNode *next = child->getNextSibling(); bool doRemove = cleanupPass(child, removals); if (doRemove) node->removeChild(child); child = next; } } return false; } void GeometryConverter::convert(const fs::path &inputFile, const fs::path &outputDirectory, const fs::path &sceneName, const fs::path &adjustmentFile) { fs::path textureDirectory = "textures"; fs::path meshesDirectory = "meshes"; fs::path outputFile = sceneName; this->m_outputDirectory = outputDirectory; if (!outputDirectory.empty()) { textureDirectory = outputDirectory / "textures"; meshesDirectory = outputDirectory / "meshes"; outputFile = outputDirectory / sceneName; } if (m_packGeometry) { m_geometryFileName = outputDirectory / sceneName; m_geometryFileName.replace_extension(".serialized"); m_geometryFile = new FileStream(m_geometryFileName, FileStream::ETruncReadWrite); m_geometryFile->setByteOrder(Stream::ELittleEndian); } if (!fs::exists(textureDirectory)) { SLog(EInfo, "Creating directory \"%s\" ..", textureDirectory.file_string().c_str()); fs::create_directory(textureDirectory); } if (!fs::exists(meshesDirectory) && !m_packGeometry) { SLog(EInfo, "Creating directory \"%s\" ..", meshesDirectory.file_string().c_str()); fs::create_directory(meshesDirectory); } std::ostringstream os; SLog(EInfo, "Beginning conversion .."); std::string extension = boost::to_lower_copy(fs::extension(inputFile)); if (extension == ".dae" || extension == ".zae") { convertCollada(inputFile, os, textureDirectory, meshesDirectory); } else if (extension == ".obj") { convertOBJ(inputFile, os, textureDirectory, meshesDirectory); } else { SLog(EError, "Unknown input format (must end in either .DAE, .ZAE or .OBJ)"); } if (!adjustmentFile.empty()) { SLog(EInfo, "Applying adjustments .."); static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull }; DOMImplementationLS *impl = DOMImplementationRegistry::getDOMImplementation(gLS); DOMLSParser *parser = impl->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0); DOMConfiguration *conf(parser->getDomConfig()); ImporterDOMErrorHandler errorHandler; conf->setParameter(XMLUni::fgDOMErrorHandler, &errorHandler); std::string xmlString = os.str(); MemBufInputSource* memBufIS = new MemBufInputSource((const XMLByte*) xmlString.c_str(), xmlString.length(), "bufID", false); Wrapper4InputSource *wrapper = new Wrapper4InputSource(memBufIS, false); XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc = parser->parse(wrapper); XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *adj = parser->parseURI(adjustmentFile.file_string().c_str()); if (adj == NULL) SLog(EError, "Could not parse adjustments file!"); std::set removals, emptyList; cleanupPass(adj, emptyList); findRemovals(adj, removals); cleanupPass(doc, removals); DOMElement *docRoot = doc->getDocumentElement(); DOMElement *adjRoot = adj->getDocumentElement(); DOMNode *insertBeforeNode = NULL; for (DOMNode *child = docRoot->getFirstChild(); child != 0; child=child->getNextSibling()) { char *name = XMLString::transcode(child->getNodeName()); if (strcmp(name, "shape") == 0) { insertBeforeNode = child; break; } XMLString::release(&name); } if (insertBeforeNode == NULL) { /* No shape node found, use the camera node instead */ for (DOMNode *child = docRoot->getFirstChild(); child != 0; child=child->getNextSibling()) { char *name = XMLString::transcode(child->getNodeName()); if (strcmp(name, "camera") == 0) { insertBeforeNode = child; break; } XMLString::release(&name); } SAssertEx(insertBeforeNode != NULL, "Internal error while applying adjustments: cannot find shape/camera node"); } for (DOMNode *child = adjRoot->getFirstChild(); child != 0; child=child->getNextSibling()) if (child->getNodeType() == DOMNode::ELEMENT_NODE) docRoot->insertBefore(doc->importNode(child, true), insertBeforeNode); DOMLSSerializer *serializer = impl->createLSSerializer(); DOMConfiguration *serConf(serializer->getDomConfig()); DOMLSOutput *output = impl->createLSOutput(); serConf->setParameter(XMLUni::fgDOMErrorHandler, &errorHandler); serConf->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true); XMLFormatTarget *target = new LocalFileFormatTarget(outputFile.file_string().c_str()); output->setByteStream(target); serializer->write(doc, output); delete output; delete target; delete wrapper; delete memBufIS; delete serializer; parser->release(); } else { fs::ofstream ofile(outputFile); if (ofile.fail()) SLog(EError, "Could not write to \"%s\"!", outputFile.file_string().c_str()); ofile << os.str(); ofile.close(); } if (m_geometryFile) { for (size_t i=0; iwriteUInt(m_geometryDict[i]); m_geometryFile->writeUInt((uint32_t) m_geometryDict.size()); m_geometryFile->close(); } m_filename = outputFile; }