diff options
Diffstat (limited to 'libs/assimp/code/AssetLib/STL/STLLoader.cpp')
-rw-r--r-- | libs/assimp/code/AssetLib/STL/STLLoader.cpp | 575 |
1 files changed, 0 insertions, 575 deletions
diff --git a/libs/assimp/code/AssetLib/STL/STLLoader.cpp b/libs/assimp/code/AssetLib/STL/STLLoader.cpp deleted file mode 100644 index 8de57f1..0000000 --- a/libs/assimp/code/AssetLib/STL/STLLoader.cpp +++ /dev/null @@ -1,575 +0,0 @@ -/* ---------------------------------------------------------------------------- -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 |