From db81b925d776103326128bf629cbdda576a223e7 Mon Sep 17 00:00:00 2001 From: sanine Date: Sat, 16 Apr 2022 11:55:09 -0500 Subject: move 3rd-party librarys into libs/ and add built-in honeysuckle --- libs/assimp/code/AssetLib/STL/STLExporter.cpp | 233 +++++++++++ libs/assimp/code/AssetLib/STL/STLExporter.h | 81 ++++ libs/assimp/code/AssetLib/STL/STLLoader.cpp | 575 ++++++++++++++++++++++++++ libs/assimp/code/AssetLib/STL/STLLoader.h | 123 ++++++ 4 files changed, 1012 insertions(+) create mode 100644 libs/assimp/code/AssetLib/STL/STLExporter.cpp create mode 100644 libs/assimp/code/AssetLib/STL/STLExporter.h create mode 100644 libs/assimp/code/AssetLib/STL/STLLoader.cpp create mode 100644 libs/assimp/code/AssetLib/STL/STLLoader.h (limited to 'libs/assimp/code/AssetLib/STL') diff --git a/libs/assimp/code/AssetLib/STL/STLExporter.cpp b/libs/assimp/code/AssetLib/STL/STLExporter.cpp new file mode 100644 index 0000000..9bbc206 --- /dev/null +++ b/libs/assimp/code/AssetLib/STL/STLExporter.cpp @@ -0,0 +1,233 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + + + +#if !defined(ASSIMP_BUILD_NO_EXPORT) && !defined(ASSIMP_BUILD_NO_STL_EXPORTER) + +#include "STLExporter.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace Assimp; + +namespace Assimp { + +// ------------------------------------------------------------------------------------------------ +// Worker function for exporting a scene to Stereolithograpy. Prototyped and registered in Exporter.cpp +void ExportSceneSTL(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties ) +{ + bool exportPointClouds = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); + + // invoke the exporter + STLExporter exporter(pFile, pScene, exportPointClouds ); + + if (exporter.mOutput.fail()) { + throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); + } + + // we're still here - export successfully completed. Write the file. + std::unique_ptr outfile (pIOSystem->Open(pFile,"wt")); + if (outfile == nullptr) { + throw DeadlyExportError("could not open output .stl file: " + std::string(pFile)); + } + + outfile->Write( exporter.mOutput.str().c_str(), static_cast(exporter.mOutput.tellp()),1); +} +void ExportSceneSTLBinary(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties ) +{ + bool exportPointClouds = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); + + // invoke the exporter + STLExporter exporter(pFile, pScene, exportPointClouds, true); + + if (exporter.mOutput.fail()) { + throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); + } + + // we're still here - export successfully completed. Write the file. + std::unique_ptr outfile (pIOSystem->Open(pFile,"wb")); + if (outfile == nullptr) { + throw DeadlyExportError("could not open output .stl file: " + std::string(pFile)); + } + + outfile->Write( exporter.mOutput.str().c_str(), static_cast(exporter.mOutput.tellp()),1); +} + +} // end of namespace Assimp + +static const char *SolidToken = "solid"; +static const char *EndSolidToken = "endsolid"; + +// ------------------------------------------------------------------------------------------------ +STLExporter::STLExporter(const char* _filename, const aiScene* pScene, bool exportPointClouds, bool binary) +: filename(_filename) +, endl("\n") +{ + // make sure that all formatting happens using the standard, C locale and not the user's current locale + const std::locale& l = std::locale("C"); + mOutput.imbue(l); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); + if (binary) { + char buf[80] = {0} ; + buf[0] = 'A'; buf[1] = 's'; buf[2] = 's'; buf[3] = 'i'; buf[4] = 'm'; buf[5] = 'p'; + buf[6] = 'S'; buf[7] = 'c'; buf[8] = 'e'; buf[9] = 'n'; buf[10] = 'e'; + mOutput.write(buf, 80); + unsigned int meshnum = 0; + for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + for (unsigned int j = 0; j < pScene->mMeshes[i]->mNumFaces; ++j) { + meshnum++; + } + } + AI_SWAP4(meshnum); + mOutput.write((char *)&meshnum, 4); + + if (exportPointClouds) { + throw DeadlyExportError("This functionality is not yet implemented for binary output."); + } + + for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + WriteMeshBinary(pScene->mMeshes[i]); + } + } else { + + // Exporting only point clouds + if (exportPointClouds) { + WritePointCloud("Assimp_Pointcloud", pScene ); + return; + } + + // Export the assimp mesh + const std::string name = "AssimpScene"; + mOutput << SolidToken << " " << name << endl; + for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + WriteMesh(pScene->mMeshes[ i ]); + } + mOutput << EndSolidToken << " " << name << endl; + } +} + +// ------------------------------------------------------------------------------------------------ +void STLExporter::WritePointCloud(const std::string &name, const aiScene* pScene) { + mOutput << " " << SolidToken << " " << name << endl; + aiVector3D nor; + mOutput << " facet normal " << nor.x << " " << nor.y << " " << nor.z << endl; + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + aiMesh *mesh = pScene->mMeshes[i]; + if (nullptr == mesh) { + continue; + } + + for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { + const aiVector3D& v = mesh->mVertices[a]; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; + } + } + mOutput << EndSolidToken << " " << name << endl; +} + +// ------------------------------------------------------------------------------------------------ +void STLExporter::WriteMesh(const aiMesh* m) +{ + for (unsigned int i = 0; i < m->mNumFaces; ++i) { + const aiFace& f = m->mFaces[i]; + + // we need per-face normals. We specified aiProcess_GenNormals as pre-requisite for this exporter, + // but nonetheless we have to expect per-vertex normals. + aiVector3D nor; + if (m->mNormals) { + for(unsigned int a = 0; a < f.mNumIndices; ++a) { + nor += m->mNormals[f.mIndices[a]]; + } + nor.NormalizeSafe(); + } + mOutput << " facet normal " << nor.x << " " << nor.y << " " << nor.z << endl; + mOutput << " outer loop" << endl; + for(unsigned int a = 0; a < f.mNumIndices; ++a) { + const aiVector3D& v = m->mVertices[f.mIndices[a]]; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; + } + + mOutput << " endloop" << endl; + mOutput << " endfacet" << endl << endl; + } +} + +void STLExporter::WriteMeshBinary(const aiMesh* m) +{ + for (unsigned int i = 0; i < m->mNumFaces; ++i) { + const aiFace& f = m->mFaces[i]; + // we need per-face normals. We specified aiProcess_GenNormals as pre-requisite for this exporter, + // but nonetheless we have to expect per-vertex normals. + aiVector3D nor; + if (m->mNormals) { + for(unsigned int a = 0; a < f.mNumIndices; ++a) { + nor += m->mNormals[f.mIndices[a]]; + } + nor.Normalize(); + } + // STL binary files use 4-byte floats. This may possibly cause loss of precision + // for clients using 8-byte doubles + float nx = (float) nor.x; + float ny = (float) nor.y; + float nz = (float) nor.z; + AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz); + mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4); + for(unsigned int a = 0; a < f.mNumIndices; ++a) { + const aiVector3D& v = m->mVertices[f.mIndices[a]]; + float vx = (float) v.x, vy = (float) v.y, vz = (float) v.z; + AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz); + mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4); + } + char dummy[2] = {0}; + mOutput.write(dummy, 2); + } +} + +#endif diff --git a/libs/assimp/code/AssetLib/STL/STLExporter.h b/libs/assimp/code/AssetLib/STL/STLExporter.h new file mode 100644 index 0000000..066dcfe --- /dev/null +++ b/libs/assimp/code/AssetLib/STL/STLExporter.h @@ -0,0 +1,81 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @file STLExporter.h + * Declares the exporter class to write a scene to a Stereolithography (STL) file + */ +#pragma once +#ifndef AI_STLEXPORTER_H_INC +#define AI_STLEXPORTER_H_INC + +#include + +struct aiScene; +struct aiNode; +struct aiMesh; + +namespace Assimp { + +// ------------------------------------------------------------------------------------------------ +/** Helper class to export a given scene to a STL file. */ +// ------------------------------------------------------------------------------------------------ +class STLExporter { +public: + /// Constructor for a specific scene to export + STLExporter(const char *filename, const aiScene *pScene, bool exportPOintClouds, bool binary = false); + + /// public string-streams to write all output into + std::ostringstream mOutput; + +private: + void WritePointCloud(const std::string &name, const aiScene *pScene); + void WriteMesh(const aiMesh *m); + void WriteMeshBinary(const aiMesh *m); + +private: + const std::string filename; + const std::string endl; +}; + +} // namespace Assimp + +#endif diff --git a/libs/assimp/code/AssetLib/STL/STLLoader.cpp b/libs/assimp/code/AssetLib/STL/STLLoader.cpp new file mode 100644 index 0000000..8de57f1 --- /dev/null +++ b/libs/assimp/code/AssetLib/STL/STLLoader.cpp @@ -0,0 +1,575 @@ +/* +--------------------------------------------------------------------------- +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. +--------------------------------------------------------------------------- +*/ + +/** @file Implementation of the STL importer class */ + +#ifndef ASSIMP_BUILD_NO_STL_IMPORTER + +#include "STLLoader.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace Assimp; + +namespace { + +static const aiImporterDesc desc = { + "Stereolithography (STL) Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, + "stl" +}; + +// A valid binary STL buffer should consist of the following elements, in order: +// 1) 80 byte header +// 2) 4 byte face count +// 3) 50 bytes per face +static bool IsBinarySTL(const char *buffer, unsigned int fileSize) { + if (fileSize < 84) { + return false; + } + + const char *facecount_pos = buffer + 80; + uint32_t faceCount(0); + ::memcpy(&faceCount, facecount_pos, sizeof(uint32_t)); + const uint32_t expectedBinaryFileSize = faceCount * 50 + 84; + + return expectedBinaryFileSize == fileSize; +} + +static const size_t BufferSize = 500; +static const char UnicodeBoundary = 127; + +// An ascii STL buffer will begin with "solid NAME", where NAME is optional. +// Note: The "solid NAME" check is necessary, but not sufficient, to determine +// if the buffer is ASCII; a binary header could also begin with "solid NAME". +static bool IsAsciiSTL(const char *buffer, unsigned int fileSize) { + if (IsBinarySTL(buffer, fileSize)) + return false; + + const char *bufferEnd = buffer + fileSize; + + if (!SkipSpaces(&buffer)) { + return false; + } + + if (buffer + 5 >= bufferEnd) { + return false; + } + + bool isASCII(strncmp(buffer, "solid", 5) == 0); + if (isASCII) { + // A lot of importers are write solid even if the file is binary. So we have to check for ASCII-characters. + if (fileSize >= BufferSize) { + isASCII = true; + for (unsigned int i = 0; i < BufferSize; i++) { + if (buffer[i] > UnicodeBoundary) { + isASCII = false; + break; + } + } + } + } + return isASCII; +} +} // namespace + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +STLImporter::STLImporter() : + mBuffer(), + mFileSize(0), + mScene() { + // empty +} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +STLImporter::~STLImporter() { + // empty +} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the class can handle the format of the given file. +bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { + static const char *tokens[] = { "STL", "solid" }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); +} + +// ------------------------------------------------------------------------------------------------ +const aiImporterDesc *STLImporter::GetInfo() const { + return &desc; +} + +void addFacesToMesh(aiMesh *pMesh) { + pMesh->mFaces = new aiFace[pMesh->mNumFaces]; + for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces; ++i) { + + aiFace &face = pMesh->mFaces[i]; + face.mIndices = new unsigned int[face.mNumIndices = 3]; + for (unsigned int o = 0; o < 3; ++o, ++p) { + face.mIndices[o] = p; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Imports the given file into the given scene structure. +void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + std::unique_ptr file(pIOHandler->Open(pFile, "rb")); + + // Check whether we can read from the file + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open STL file ", pFile, "."); + } + + mFileSize = (unsigned int)file->FileSize(); + + // allocate storage and copy the contents of the file to a memory buffer + // (terminate it with zero) + std::vector buffer2; + TextFileToBuffer(file.get(), buffer2); + + mScene = pScene; + mBuffer = &buffer2[0]; + + // the default vertex color is light gray. + mClrColorDefault.r = mClrColorDefault.g = mClrColorDefault.b = mClrColorDefault.a = (ai_real)0.6; + + // allocate a single node + mScene->mRootNode = new aiNode(); + + bool bMatClr = false; + + if (IsBinarySTL(mBuffer, mFileSize)) { + bMatClr = LoadBinaryFile(); + } else if (IsAsciiSTL(mBuffer, mFileSize)) { + LoadASCIIFile(mScene->mRootNode); + } else { + throw DeadlyImportError("Failed to determine STL storage representation for ", pFile, "."); + } + + // create a single default material, using a white diffuse color for consistency with + // other geometric types (e.g., PLY). + aiMaterial *pcMat = new aiMaterial(); + aiString s; + s.Set(AI_DEFAULT_MATERIAL_NAME); + pcMat->AddProperty(&s, AI_MATKEY_NAME); + + aiColor4D clrDiffuse(ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0)); + if (bMatClr) { + clrDiffuse = mClrColorDefault; + } + pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_SPECULAR); + clrDiffuse = aiColor4D(ai_real(0.05), ai_real(0.05), ai_real(0.05), ai_real(1.0)); + pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_AMBIENT); + + mScene->mNumMaterials = 1; + mScene->mMaterials = new aiMaterial *[1]; + mScene->mMaterials[0] = pcMat; + + mBuffer = nullptr; +} + +// ------------------------------------------------------------------------------------------------ +// Read an ASCII STL file +void STLImporter::LoadASCIIFile(aiNode *root) { + std::vector meshes; + std::vector nodes; + const char *sz = mBuffer; + const char *bufferEnd = mBuffer + mFileSize; + std::vector positionBuffer; + std::vector normalBuffer; + + // try to guess how many vertices we could have + // assume we'll need 160 bytes for each face + size_t sizeEstimate = std::max(1u, mFileSize / 160u) * 3; + positionBuffer.reserve(sizeEstimate); + normalBuffer.reserve(sizeEstimate); + + while (IsAsciiSTL(sz, static_cast(bufferEnd - sz))) { + std::vector meshIndices; + aiMesh *pMesh = new aiMesh(); + pMesh->mMaterialIndex = 0; + meshIndices.push_back((unsigned int)meshes.size()); + meshes.push_back(pMesh); + aiNode *node = new aiNode; + node->mParent = root; + nodes.push_back(node); + SkipSpaces(&sz); + ai_assert(!IsLineEnd(sz)); + + sz += 5; // skip the "solid" + SkipSpaces(&sz); + const char *szMe = sz; + while (!::IsSpaceOrNewLine(*sz)) { + sz++; + } + + size_t temp = (size_t)(sz - szMe); + // setup the name of the node + if ( temp ) { + if (temp >= MAXLEN) { + throw DeadlyImportError("STL: Node name too long"); + } + std::string name(szMe, temp); + node->mName.Set(name.c_str()); + pMesh->mName.Set(name.c_str()); + } else { + mScene->mRootNode->mName.Set(""); + } + + unsigned int faceVertexCounter = 3; + for (;;) { + // go to the next token + if (!SkipSpacesAndLineEnd(&sz)) { + // seems we're finished although there was no end marker + ASSIMP_LOG_WARN("STL: unexpected EOF. \'endsolid\' keyword was expected"); + break; + } + // facet normal -0.13 -0.13 -0.98 + if (!strncmp(sz, "facet", 5) && IsSpaceOrNewLine(*(sz + 5)) && *(sz + 5) != '\0') { + + if (faceVertexCounter != 3) { + ASSIMP_LOG_WARN("STL: A new facet begins but the old is not yet complete"); + } + faceVertexCounter = 0; + normalBuffer.push_back(aiVector3D()); + aiVector3D *vn = &normalBuffer.back(); + + sz += 6; + SkipSpaces(&sz); + if (strncmp(sz, "normal", 6)) { + ASSIMP_LOG_WARN("STL: a facet normal vector was expected but not found"); + } else { + if (sz[6] == '\0') { + throw DeadlyImportError("STL: unexpected EOF while parsing facet"); + } + sz += 7; + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (ai_real &)vn->x); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (ai_real &)vn->y); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (ai_real &)vn->z); + normalBuffer.push_back(*vn); + normalBuffer.push_back(*vn); + } + } else if (!strncmp(sz, "vertex", 6) && ::IsSpaceOrNewLine(*(sz + 6))) { // vertex 1.50000 1.50000 0.00000 + if (faceVertexCounter >= 3) { + ASSIMP_LOG_ERROR("STL: a facet with more than 3 vertices has been found"); + ++sz; + } else { + if (sz[6] == '\0') { + throw DeadlyImportError("STL: unexpected EOF while parsing facet"); + } + sz += 7; + SkipSpaces(&sz); + positionBuffer.push_back(aiVector3D()); + aiVector3D *vn = &positionBuffer.back(); + sz = fast_atoreal_move(sz, (ai_real &)vn->x); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (ai_real &)vn->y); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (ai_real &)vn->z); + faceVertexCounter++; + } + } else if (!::strncmp(sz, "endsolid", 8)) { + do { + ++sz; + } while (!::IsLineEnd(*sz)); + SkipSpacesAndLineEnd(&sz); + // finished! + break; + } else { // else skip the whole identifier + do { + ++sz; + } while (!::IsSpaceOrNewLine(*sz)); + } + } + + if (positionBuffer.empty()) { + pMesh->mNumFaces = 0; + ASSIMP_LOG_WARN("STL: mesh is empty or invalid; no data loaded"); + } + if (positionBuffer.size() % 3 != 0) { + pMesh->mNumFaces = 0; + throw DeadlyImportError("STL: Invalid number of vertices"); + } + if (normalBuffer.size() != positionBuffer.size()) { + pMesh->mNumFaces = 0; + throw DeadlyImportError("Normal buffer size does not match position buffer size"); + } + + // only process positionbuffer when filled, else exception when accessing with index operator + // see line 353: only warning is triggered + // see line 373(now): access to empty positionbuffer with index operator forced exception + if (!positionBuffer.empty()) { + pMesh->mNumFaces = static_cast(positionBuffer.size() / 3); + pMesh->mNumVertices = static_cast(positionBuffer.size()); + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + for (size_t i=0; imNumVertices; ++i ) { + pMesh->mVertices[i].x = positionBuffer[i].x; + pMesh->mVertices[i].y = positionBuffer[i].y; + pMesh->mVertices[i].z = positionBuffer[i].z; + } + positionBuffer.clear(); + } + // also only process normalBuffer when filled, else exception when accessing with index operator + if (!normalBuffer.empty()) { + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + for (size_t i=0; imNumVertices; ++i ) { + pMesh->mNormals[i].x = normalBuffer[i].x; + pMesh->mNormals[i].y = normalBuffer[i].y; + pMesh->mNormals[i].z = normalBuffer[i].z; + } + normalBuffer.clear(); + } + + // now copy faces + addFacesToMesh(pMesh); + + // assign the meshes to the current node + pushMeshesToNode(meshIndices, node); + } + + // now add the loaded meshes + mScene->mNumMeshes = (unsigned int)meshes.size(); + mScene->mMeshes = new aiMesh *[mScene->mNumMeshes]; + for (size_t i = 0; i < meshes.size(); i++) { + mScene->mMeshes[i] = meshes[i]; + } + + root->mNumChildren = (unsigned int)nodes.size(); + root->mChildren = new aiNode *[root->mNumChildren]; + for (size_t i = 0; i < nodes.size(); ++i) { + root->mChildren[i] = nodes[i]; + } +} + +// ------------------------------------------------------------------------------------------------ +// Read a binary STL file +bool STLImporter::LoadBinaryFile() { + // allocate one mesh + mScene->mNumMeshes = 1; + mScene->mMeshes = new aiMesh *[1]; + aiMesh *pMesh = mScene->mMeshes[0] = new aiMesh(); + pMesh->mMaterialIndex = 0; + + // skip the first 80 bytes + if (mFileSize < 84) { + throw DeadlyImportError("STL: file is too small for the header"); + } + bool bIsMaterialise = false; + + // search for an occurrence of "COLOR=" in the header + const unsigned char *sz2 = (const unsigned char *)mBuffer; + const unsigned char *const szEnd = sz2 + 80; + while (sz2 < szEnd) { + + if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ && + 'O' == *sz2++ && 'R' == *sz2++ && '=' == *sz2++) { + + // read the default vertex color for facets + bIsMaterialise = true; + ASSIMP_LOG_INFO("STL: Taking code path for Materialise files"); + const ai_real invByte = (ai_real)1.0 / (ai_real)255.0; + mClrColorDefault.r = (*sz2++) * invByte; + mClrColorDefault.g = (*sz2++) * invByte; + mClrColorDefault.b = (*sz2++) * invByte; + mClrColorDefault.a = (*sz2++) * invByte; + break; + } + } + const unsigned char *sz = (const unsigned char *)mBuffer + 80; + + // now read the number of facets + mScene->mRootNode->mName.Set(""); + + pMesh->mNumFaces = *((uint32_t *)sz); + sz += 4; + + if (mFileSize < 84 + pMesh->mNumFaces * 50) { + throw DeadlyImportError("STL: file is too small to hold all facets"); + } + + if (!pMesh->mNumFaces) { + throw DeadlyImportError("STL: file is empty. There are no facets defined"); + } + + pMesh->mNumVertices = pMesh->mNumFaces * 3; + + aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + + typedef aiVector3t aiVector3F; + aiVector3F *theVec; + aiVector3F theVec3F; + + for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) { + // NOTE: Blender sometimes writes empty normals ... this is not + // our fault ... the RemoveInvalidData helper step should fix that + + // There's one normal for the face in the STL; use it three times + // for vertex normals + theVec = (aiVector3F *)sz; + ::memcpy(&theVec3F, theVec, sizeof(aiVector3F)); + vn->x = theVec3F.x; + vn->y = theVec3F.y; + vn->z = theVec3F.z; + *(vn + 1) = *vn; + *(vn + 2) = *vn; + ++theVec; + vn += 3; + + // vertex 1 + ::memcpy(&theVec3F, theVec, sizeof(aiVector3F)); + vp->x = theVec3F.x; + vp->y = theVec3F.y; + vp->z = theVec3F.z; + ++theVec; + ++vp; + + // vertex 2 + ::memcpy(&theVec3F, theVec, sizeof(aiVector3F)); + vp->x = theVec3F.x; + vp->y = theVec3F.y; + vp->z = theVec3F.z; + ++theVec; + ++vp; + + // vertex 3 + ::memcpy(&theVec3F, theVec, sizeof(aiVector3F)); + vp->x = theVec3F.x; + vp->y = theVec3F.y; + vp->z = theVec3F.z; + ++theVec; + ++vp; + + sz = (const unsigned char *)theVec; + + uint16_t color = *((uint16_t *)sz); + sz += 2; + + if (color & (1 << 15)) { + // seems we need to take the color + if (!pMesh->mColors[0]) { + pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; + for (unsigned int j = 0; j < pMesh->mNumVertices; ++j) { + *pMesh->mColors[0]++ = mClrColorDefault; + } + pMesh->mColors[0] -= pMesh->mNumVertices; + + ASSIMP_LOG_INFO("STL: Mesh has vertex colors"); + } + aiColor4D *clr = &pMesh->mColors[0][i * 3]; + clr->a = 1.0; + const ai_real invVal((ai_real)1.0 / (ai_real)31.0); + if (bIsMaterialise) // this is reversed + { + clr->r = (color & 0x31u) * invVal; + clr->g = ((color & (0x31u << 5)) >> 5u) * invVal; + clr->b = ((color & (0x31u << 10)) >> 10u) * invVal; + } else { + clr->b = (color & 0x31u) * invVal; + clr->g = ((color & (0x31u << 5)) >> 5u) * invVal; + clr->r = ((color & (0x31u << 10)) >> 10u) * invVal; + } + // assign the color to all vertices of the face + *(clr + 1) = *clr; + *(clr + 2) = *clr; + } + } + + // now copy faces + addFacesToMesh(pMesh); + + aiNode *root = mScene->mRootNode; + + // allocate one node + aiNode *node = new aiNode(); + node->mParent = root; + + root->mNumChildren = 1u; + root->mChildren = new aiNode *[root->mNumChildren]; + root->mChildren[0] = node; + + // add all created meshes to the single node + node->mNumMeshes = mScene->mNumMeshes; + node->mMeshes = new unsigned int[mScene->mNumMeshes]; + for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { + node->mMeshes[i] = i; + } + + if (bIsMaterialise && !pMesh->mColors[0]) { + // use the color as diffuse material color + return true; + } + return false; +} + +void STLImporter::pushMeshesToNode(std::vector &meshIndices, aiNode *node) { + ai_assert(nullptr != node); + if (meshIndices.empty()) { + return; + } + + node->mNumMeshes = static_cast(meshIndices.size()); + node->mMeshes = new unsigned int[meshIndices.size()]; + for (size_t i = 0; i < meshIndices.size(); ++i) { + node->mMeshes[i] = meshIndices[i]; + } + meshIndices.clear(); +} + +#endif // !! ASSIMP_BUILD_NO_STL_IMPORTER diff --git a/libs/assimp/code/AssetLib/STL/STLLoader.h b/libs/assimp/code/AssetLib/STL/STLLoader.h new file mode 100644 index 0000000..a340abe --- /dev/null +++ b/libs/assimp/code/AssetLib/STL/STLLoader.h @@ -0,0 +1,123 @@ +/* +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. + +---------------------------------------------------------------------- +*/ + +/** @file STLLoader.h + * Declaration of the STL importer class. + */ +#ifndef AI_STLLOADER_H_INCLUDED +#define AI_STLLOADER_H_INCLUDED + +#include +#include + +// Forward declarations +struct aiNode; + +namespace Assimp { + +// --------------------------------------------------------------------------- +/** + * @brief Importer class for the sterolithography STL file format. + */ +class STLImporter : public BaseImporter { +public: + /** + * @brief STLImporter, the class default constructor. + */ + STLImporter(); + + /** + * @brief The class destructor. + */ + ~STLImporter() override; + + /** + * @brief Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override; + +protected: + + /** + * @brief Return importer meta information. + * See #BaseImporter::GetInfo for the details + */ + const aiImporterDesc* GetInfo () const override; + + /** + * @brief Imports the given file into the given scene structure. + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler) override; + + /** + * @brief Loads a binary .stl file + * @return true if the default vertex color must be used as material color + */ + bool LoadBinaryFile(); + + /** + * @brief Loads a ASCII text .stl file + */ + void LoadASCIIFile( aiNode *root ); + + void pushMeshesToNode( std::vector &meshIndices, aiNode *node ); + +protected: + + /** Buffer to hold the loaded file */ + const char* mBuffer; + + /** Size of the file, in bytes */ + unsigned int mFileSize; + + /** Output scene */ + aiScene* mScene; + + /** Default vertex color */ + aiColor4D mClrColorDefault; +}; + +} // end of namespace Assimp + +#endif // AI_3DSIMPORTER_H_IN -- cgit v1.2.1