aboutsummaryrefslogtreecommitdiff
path: root/NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp
diff options
context:
space:
mode:
authorMarijn Tamis <[email protected]>2018-05-03 18:22:48 +0200
committerMarijn Tamis <[email protected]>2018-05-03 18:22:48 +0200
commitca32c59a58d37c1822e185a2d5f3d0d3e8943593 (patch)
treeb06b9eec03f34344ef8fc31aa147b2714d3962ee /NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp
parentForced rename of platform folders in cmake dir. Git didn't pick this up before. (diff)
downloadnvcloth-ca32c59a58d37c1822e185a2d5f3d0d3e8943593.tar.xz
nvcloth-ca32c59a58d37c1822e185a2d5f3d0d3e8943593.zip
NvCloth 1.1.4 Release. (24070740)
Diffstat (limited to 'NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp')
-rw-r--r--NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp b/NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp
new file mode 100644
index 0000000..be4c758
--- /dev/null
+++ b/NvCloth/samples/external/assimp-4.1.0/code/STLLoader.cpp
@@ -0,0 +1,537 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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
+
+// internal headers
+#include "STLLoader.h"
+#include "ParsingUtils.h"
+#include "fast_atof.h"
+#include <memory>
+#include <assimp/IOSystem.hpp>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/importerdesc.h>
+
+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;
+}
+
+// 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 >= 500 ) {
+ isASCII = true;
+ for( unsigned int i = 0; i < 500; i++ ) {
+ if( buffer[ i ] > 127 ) {
+ isASCII = false;
+ break;
+ }
+ }
+ }
+ }
+ return isASCII;
+}
+} // namespace
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+STLImporter::STLImporter()
+ : mBuffer(),
+ fileSize(),
+ pScene()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+STLImporter::~STLImporter()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Returns whether the class can handle the format of the given file.
+bool STLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+{
+ const std::string extension = GetExtension(pFile);
+
+ if( extension == "stl" ) {
+ return true;
+ } else if (!extension.length() || checkSig) {
+ if( !pIOHandler ) {
+ return true;
+ }
+ const char* tokens[] = {"STL","solid"};
+ return SearchFileHeaderForToken(pIOHandler,pFile,tokens,2);
+ }
+
+ return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+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() == NULL) {
+ throw DeadlyImportError( "Failed to open STL file " + pFile + ".");
+ }
+
+ fileSize = (unsigned int)file->FileSize();
+
+ // allocate storage and copy the contents of the file to a memory buffer
+ // (terminate it with zero)
+ std::vector<char> mBuffer2;
+ TextFileToBuffer(file.get(),mBuffer2);
+
+ this->pScene = pScene;
+ this->mBuffer = &mBuffer2[0];
+
+ // the default vertex color is light gray.
+ clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = (ai_real) 0.6;
+
+ // allocate a single node
+ pScene->mRootNode = new aiNode();
+
+ bool bMatClr = false;
+
+ if (IsBinarySTL(mBuffer, fileSize)) {
+ bMatClr = LoadBinaryFile();
+ } else if (IsAsciiSTL(mBuffer, fileSize)) {
+ LoadASCIIFile( pScene->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 = clrColorDefault;
+ }
+ pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
+ pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
+ clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0));
+ pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
+
+ pScene->mNumMaterials = 1;
+ pScene->mMaterials = new aiMaterial*[1];
+ pScene->mMaterials[0] = pcMat;
+}
+
+// ------------------------------------------------------------------------------------------------
+// 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 + fileSize;
+ 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, fileSize / 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;
+ // setup the name of the node
+ if ((temp = (size_t)(sz-szMe))) {
+ if (temp >= MAXLEN) {
+ throw DeadlyImportError( "STL: Node name too long" );
+ }
+ std::string name( szMe, temp );
+ node->mName.Set( name.c_str() );
+ //pScene->mRootNode->mName.length = temp;
+ //memcpy(pScene->mRootNode->mName.data,szMe,temp);
+ //pScene->mRootNode->mName.data[temp] = '\0';
+ } else {
+ pScene->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
+ DefaultLogger::get()->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) {
+ DefaultLogger::get()->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)) {
+ DefaultLogger::get()->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) {
+ DefaultLogger::get()->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;
+ throw DeadlyImportError("STL: ASCII file 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");
+ }
+ pMesh->mNumFaces = static_cast<unsigned int>(positionBuffer.size() / 3);
+ pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
+ pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
+ memcpy(pMesh->mVertices, &positionBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+ positionBuffer.clear();
+ pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
+ memcpy(pMesh->mNormals, &normalBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+ normalBuffer.clear();
+
+ // now copy faces
+ addFacesToMesh(pMesh);
+
+ // assign the meshes to the current node
+ pushMeshesToNode( meshIndices, node );
+ }
+
+ // now add the loaded meshes
+ pScene->mNumMeshes = (unsigned int)meshes.size();
+ pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+ for (size_t i = 0; i < meshes.size(); i++) {
+ pScene->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
+ pScene->mNumMeshes = 1;
+ pScene->mMeshes = new aiMesh*[1];
+ aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh();
+ pMesh->mMaterialIndex = 0;
+
+ // skip the first 80 bytes
+ if (fileSize < 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;
+ DefaultLogger::get()->info("STL: Taking code path for Materialise files");
+ const ai_real invByte = (ai_real)1.0 / ( ai_real )255.0;
+ clrColorDefault.r = (*sz2++) * invByte;
+ clrColorDefault.g = (*sz2++) * invByte;
+ clrColorDefault.b = (*sz2++) * invByte;
+ clrColorDefault.a = (*sz2++) * invByte;
+ break;
+ }
+ }
+ const unsigned char* sz = (const unsigned char*)mBuffer + 80;
+
+ // now read the number of facets
+ pScene->mRootNode->mName.Set("<STL_BINARY>");
+
+ pMesh->mNumFaces = *((uint32_t*)sz);
+ sz += 4;
+
+ if (fileSize < 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,*vn;
+ vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
+ vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
+
+ 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
+ *vn = *((aiVector3D*)sz);
+ sz += sizeof(aiVector3D);
+ *(vn+1) = *vn;
+ *(vn+2) = *vn;
+ vn += 3;
+
+ *vp++ = *((aiVector3D*)sz);
+ sz += sizeof(aiVector3D);
+
+ *vp++ = *((aiVector3D*)sz);
+ sz += sizeof(aiVector3D);
+
+ *vp++ = *((aiVector3D*)sz);
+ sz += sizeof(aiVector3D);
+
+ 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 i = 0; i <pMesh->mNumVertices;++i)
+ *pMesh->mColors[0]++ = this->clrColorDefault;
+ pMesh->mColors[0] -= pMesh->mNumVertices;
+
+ DefaultLogger::get()->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);
+
+ // add all created meshes to the single node
+ pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
+ pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+ for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
+ pScene->mRootNode->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