summaryrefslogtreecommitdiff
path: root/libs/assimp/code/AssetLib/STL
diff options
context:
space:
mode:
Diffstat (limited to 'libs/assimp/code/AssetLib/STL')
-rw-r--r--libs/assimp/code/AssetLib/STL/STLExporter.cpp233
-rw-r--r--libs/assimp/code/AssetLib/STL/STLExporter.h81
-rw-r--r--libs/assimp/code/AssetLib/STL/STLLoader.cpp575
-rw-r--r--libs/assimp/code/AssetLib/STL/STLLoader.h123
4 files changed, 1012 insertions, 0 deletions
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 <assimp/version.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/scene.h>
+#include <assimp/Exporter.hpp>
+#include <memory>
+#include <assimp/Exceptional.h>
+#include <assimp/ByteSwapper.h>
+
+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<IOStream> 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<size_t>(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<IOStream> 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<size_t>(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 <sstream>
+
+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 <assimp/ParsingUtils.h>
+#include <assimp/fast_atof.h>
+#include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/IOSystem.hpp>
+#include <memory>
+
+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<IOStream> 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<char> 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<aiMesh *> meshes;
+ std::vector<aiNode *> nodes;
+ const char *sz = mBuffer;
+ const char *bufferEnd = mBuffer + mFileSize;
+ std::vector<aiVector3D> positionBuffer;
+ std::vector<aiVector3D> 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<unsigned int>(bufferEnd - sz))) {
+ std::vector<unsigned int> 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("<STL_ASCII>");
+ }
+
+ 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<ai_real>(sz, (ai_real &)vn->x);
+ SkipSpaces(&sz);
+ sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
+ SkipSpaces(&sz);
+ sz = fast_atoreal_move<ai_real>(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<ai_real>(sz, (ai_real &)vn->x);
+ SkipSpaces(&sz);
+ sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
+ SkipSpaces(&sz);
+ sz = fast_atoreal_move<ai_real>(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<unsigned int>(positionBuffer.size() / 3);
+ pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
+ pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
+ for (size_t i=0; i<pMesh->mNumVertices; ++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; i<pMesh->mNumVertices; ++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("<STL_BINARY>");
+
+ 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<float> 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<unsigned int> &meshIndices, aiNode *node) {
+ ai_assert(nullptr != node);
+ if (meshIndices.empty()) {
+ return;
+ }
+
+ node->mNumMeshes = static_cast<unsigned int>(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 <assimp/BaseImporter.h>
+#include <assimp/types.h>
+
+// 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<unsigned int> &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