diff options
Diffstat (limited to 'libs/assimp/code/AssetLib/3MF/D3MFExporter.cpp')
-rw-r--r-- | libs/assimp/code/AssetLib/3MF/D3MFExporter.cpp | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/libs/assimp/code/AssetLib/3MF/D3MFExporter.cpp b/libs/assimp/code/AssetLib/3MF/D3MFExporter.cpp new file mode 100644 index 0000000..42cd991 --- /dev/null +++ b/libs/assimp/code/AssetLib/3MF/D3MFExporter.cpp @@ -0,0 +1,403 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER + +#include "D3MFExporter.h" + +#include <assimp/Exceptional.h> +#include <assimp/StringUtils.h> +#include <assimp/scene.h> +#include <assimp/DefaultLogger.hpp> +#include <assimp/Exporter.hpp> +#include <assimp/IOStream.hpp> +#include <assimp/IOSystem.hpp> + +#include "3MFXmlTags.h" +#include "D3MFOpcPackage.h" + +#ifdef ASSIMP_USE_HUNTER +#include <zip/zip.h> +#else +#include <contrib/zip/src/zip.h> +#endif + +namespace Assimp { + +void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { + if (nullptr == pIOSystem) { + throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile)); + } + D3MF::D3MFExporter myExporter(pFile, pScene); + if (myExporter.validate()) { + if (pIOSystem->Exists(pFile)) { + if (!pIOSystem->DeleteFile(pFile)) { + throw DeadlyExportError("File exists, cannot override : " + std::string(pFile)); + } + } + bool ok = myExporter.exportArchive(pFile); + if (!ok) { + throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile)); + } + } +} + +namespace D3MF { + +D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) : + mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() { + // empty +} + +D3MFExporter::~D3MFExporter() { + for (size_t i = 0; i < mRelations.size(); ++i) { + delete mRelations[i]; + } + mRelations.clear(); +} + +bool D3MFExporter::validate() { + if (mArchiveName.empty()) { + return false; + } + + if (nullptr == mScene) { + return false; + } + + return true; +} + +bool D3MFExporter::exportArchive(const char *file) { + bool ok(true); + + m_zipArchive = zip_open(file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + if (nullptr == m_zipArchive) { + return false; + } + + ok |= exportContentTypes(); + ok |= export3DModel(); + ok |= exportRelations(); + + zip_close(m_zipArchive); + m_zipArchive = nullptr; + + return ok; +} + +bool D3MFExporter::exportContentTypes() { + mContentOutput.clear(); + + mContentOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + mContentOutput << std::endl; + mContentOutput << "<Types xmlns = \"http://schemas.openxmlformats.org/package/2006/content-types\">"; + mContentOutput << std::endl; + mContentOutput << "<Default Extension = \"rels\" ContentType = \"application/vnd.openxmlformats-package.relationships+xml\" />"; + mContentOutput << std::endl; + mContentOutput << "<Default Extension = \"model\" ContentType = \"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\" />"; + mContentOutput << std::endl; + mContentOutput << "</Types>"; + mContentOutput << std::endl; + zipContentType(XmlTag::CONTENT_TYPES_ARCHIVE); + + return true; +} + +bool D3MFExporter::exportRelations() { + mRelOutput.clear(); + + mRelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + mRelOutput << std::endl; + mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"; + + for (size_t i = 0; i < mRelations.size(); ++i) { + if (mRelations[i]->target[0] == '/') { + mRelOutput << "<Relationship Target=\"" << mRelations[i]->target << "\" "; + } else { + mRelOutput << "<Relationship Target=\"/" << mRelations[i]->target << "\" "; + } + mRelOutput << "Id=\"" << mRelations[i]->id << "\" "; + mRelOutput << "Type=\"" << mRelations[i]->type << "\" />"; + mRelOutput << std::endl; + } + mRelOutput << "</Relationships>"; + mRelOutput << std::endl; + + zipRelInfo("_rels", ".rels"); + mRelOutput.flush(); + + return true; +} + +bool D3MFExporter::export3DModel() { + mModelOutput.clear(); + + writeHeader(); + mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\"" + << " xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">" + << std::endl; + mModelOutput << "<" << XmlTag::resources << ">"; + mModelOutput << std::endl; + + writeMetaData(); + + writeBaseMaterials(); + + writeObjects(); + + mModelOutput << "</" << XmlTag::resources << ">"; + mModelOutput << std::endl; + writeBuild(); + + mModelOutput << "</" << XmlTag::model << ">\n"; + + OpcPackageRelationship *info = new OpcPackageRelationship; + info->id = "rel0"; + info->target = "/3D/3DModel.model"; + info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; + mRelations.push_back(info); + + zipModel("3D", "3DModel.model"); + mModelOutput.flush(); + + return true; +} + +void D3MFExporter::writeHeader() { + mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + mModelOutput << std::endl; +} + +void D3MFExporter::writeMetaData() { + if (nullptr == mScene->mMetaData) { + return; + } + + const unsigned int numMetaEntries(mScene->mMetaData->mNumProperties); + if (0 == numMetaEntries) { + return; + } + + const aiString *key = nullptr; + const aiMetadataEntry *entry(nullptr); + for (size_t i = 0; i < numMetaEntries; ++i) { + mScene->mMetaData->Get(i, key, entry); + std::string k(key->C_Str()); + aiString value; + mScene->mMetaData->Get(k, value); + mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">"; + mModelOutput << value.C_Str(); + mModelOutput << "</" << XmlTag::meta << ">" << std::endl; + } +} + +void D3MFExporter::writeBaseMaterials() { + mModelOutput << "<basematerials id=\"1\">\n"; + std::string strName, hexDiffuseColor, tmp; + for (size_t i = 0; i < mScene->mNumMaterials; ++i) { + aiMaterial *mat = mScene->mMaterials[i]; + aiString name; + if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) { + strName = "basemat_" + ai_to_string(i); + } else { + strName = name.C_Str(); + } + aiColor4D color; + if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) { + hexDiffuseColor.clear(); + tmp.clear(); + // rgbs % + if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) { + + hexDiffuseColor = ai_rgba2hex( + (int)((ai_real)color.r) * 255, + (int)((ai_real)color.g) * 255, + (int)((ai_real)color.b) * 255, + (int)((ai_real)color.a) * 255, + true); + + } else { + hexDiffuseColor = "#"; + tmp = ai_decimal_to_hexa((ai_real)color.r); + hexDiffuseColor += tmp; + tmp = ai_decimal_to_hexa((ai_real)color.g); + hexDiffuseColor += tmp; + tmp = ai_decimal_to_hexa((ai_real)color.b); + hexDiffuseColor += tmp; + tmp = ai_decimal_to_hexa((ai_real)color.a); + hexDiffuseColor += tmp; + } + } else { + hexDiffuseColor = "#FFFFFFFF"; + } + + mModelOutput << "<base name=\"" + strName + "\" " + " displaycolor=\"" + hexDiffuseColor + "\" />\n"; + } + mModelOutput << "</basematerials>\n"; +} + +void D3MFExporter::writeObjects() { + if (nullptr == mScene->mRootNode) { + return; + } + + aiNode *root = mScene->mRootNode; + for (unsigned int i = 0; i < root->mNumChildren; ++i) { + aiNode *currentNode(root->mChildren[i]); + if (nullptr == currentNode) { + continue; + } + mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">"; + mModelOutput << std::endl; + for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) { + aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]]; + if (nullptr == currentMesh) { + continue; + } + writeMesh(currentMesh); + } + mBuildItems.push_back(i); + + mModelOutput << "</" << XmlTag::object << ">"; + mModelOutput << std::endl; + } +} + +void D3MFExporter::writeMesh(aiMesh *mesh) { + if (nullptr == mesh) { + return; + } + + mModelOutput << "<" + << XmlTag::mesh + << ">" << "\n"; + mModelOutput << "<" + << XmlTag::vertices + << ">" << "\n"; + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + writeVertex(mesh->mVertices[i]); + } + mModelOutput << "</" + << XmlTag::vertices << ">" + << "\n"; + + const unsigned int matIdx(mesh->mMaterialIndex); + + writeFaces(mesh, matIdx); + + mModelOutput << "</" + << XmlTag::mesh << ">" + << "\n"; +} + +void D3MFExporter::writeVertex(const aiVector3D &pos) { + mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />"; + mModelOutput << std::endl; +} + +void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) { + if (nullptr == mesh) { + return; + } + + if (!mesh->HasFaces()) { + return; + } + mModelOutput << "<" + << XmlTag::triangles << ">" + << "\n"; + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + aiFace ¤tFace = mesh->mFaces[i]; + mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\"" + << currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2] + << "\" pid=\"1\" p1=\"" + ai_to_string(matIdx) + "\" />"; + mModelOutput << "\n"; + } + mModelOutput << "</" + << XmlTag::triangles + << ">"; + mModelOutput << "\n"; +} + +void D3MFExporter::writeBuild() { + mModelOutput << "<" + << XmlTag::build + << ">" + << "\n"; + + for (size_t i = 0; i < mBuildItems.size(); ++i) { + mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>"; + mModelOutput << "\n"; + } + mModelOutput << "</" << XmlTag::build << ">"; + mModelOutput << "\n"; +} + +void D3MFExporter::zipContentType(const std::string &filename) { + addFileInZip(filename, mContentOutput.str()); +} + +void D3MFExporter::zipModel(const std::string &folder, const std::string &modelName) { + const std::string entry = folder + "/" + modelName; + addFileInZip(entry, mModelOutput.str()); +} + +void D3MFExporter::zipRelInfo(const std::string &folder, const std::string &relName) { + const std::string entry = folder + "/" + relName; + addFileInZip(entry, mRelOutput.str()); +} + +void D3MFExporter::addFileInZip(const std::string& entry, const std::string& content) { + if (nullptr == m_zipArchive) { + throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr."); + } + + zip_entry_open(m_zipArchive, entry.c_str()); + zip_entry_write(m_zipArchive, content.c_str(), content.size()); + zip_entry_close(m_zipArchive); +} + +} // Namespace D3MF +} // Namespace Assimp + +#endif // ASSIMP_BUILD_NO_3MF_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT |