diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 987de89d0..8f2a4e18e 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -131,6 +131,19 @@ 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, @@ -156,17 +169,8 @@ void STLImporter::InternReadFile( const std::string& pFile, // the default vertex color is light gray. clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = 0.6f; - // allocate one mesh - pScene->mNumMeshes = 1; - pScene->mMeshes = new aiMesh*[1]; - aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh(); - pMesh->mMaterialIndex = 0; - - // allocate a single node - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; + // allocate a single node + pScene->mRootNode = new aiNode(); bool bMatClr = false; @@ -178,16 +182,12 @@ void STLImporter::InternReadFile( const std::string& pFile, throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + "."); } - // now copy faces - 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; - } - } + // add all created meshes to the single node + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; + pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + for (uint i = 0; i < pScene->mNumMeshes; i++) + pScene->mRootNode->mMeshes[i] = i; // create a single default material, using a light gray diffuse color for consistency with // other geometric types (e.g., PLY). @@ -213,140 +213,165 @@ void STLImporter::InternReadFile( const std::string& pFile, // Read an ASCII STL file void STLImporter::LoadASCIIFile() { - aiMesh* pMesh = pScene->mMeshes[0]; + std::vector meshes; + const char* sz = mBuffer; + const char* bufferEnd = mBuffer + fileSize; + std::vector positionBuffer; + std::vector normalBuffer; - const char* sz = mBuffer; - SkipSpaces(&sz); - ai_assert(!IsLineEnd(sz)); + // 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); - sz += 5; // skip the "solid" - SkipSpaces(&sz); - const char* szMe = sz; - while (!::IsSpaceOrNewLine(*sz)) { - sz++; - } + while (IsAsciiSTL(sz, bufferEnd - sz)) + { + aiMesh* pMesh = new aiMesh(); + pMesh->mMaterialIndex = 0; + meshes.push_back(pMesh); - 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" ); - } + SkipSpaces(&sz); + ai_assert(!IsLineEnd(sz)); - pScene->mRootNode->mName.length = temp; - memcpy(pScene->mRootNode->mName.data,szMe,temp); - pScene->mRootNode->mName.data[temp] = '\0'; - } - else pScene->mRootNode->mName.Set(""); + sz += 5; // skip the "solid" + SkipSpaces(&sz); + const char* szMe = sz; + while (!::IsSpaceOrNewLine(*sz)) { + sz++; + } - // try to guess how many vertices we could have - // assume we'll need 160 bytes for each face - pMesh->mNumVertices = ( pMesh->mNumFaces = std::max(1u,fileSize / 160u )) * 3; - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - - unsigned int curFace = 0, curVertex = 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))) { + 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" ); + } - if (3 != curVertex) { - DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete"); - } - if (pMesh->mNumFaces == curFace) { - ai_assert(pMesh->mNumFaces != 0); + pScene->mRootNode->mName.length = temp; + memcpy(pScene->mRootNode->mName.data,szMe,temp); + pScene->mRootNode->mName.data[temp] = '\0'; + } + else pScene->mRootNode->mName.Set(""); - // need to resize the arrays, our size estimate was wrong - unsigned int iNeededSize = (unsigned int)(sz-mBuffer) / pMesh->mNumFaces; - if (iNeededSize <= 160)iNeededSize >>= 1; // prevent endless looping - unsigned int add = (unsigned int)((mBuffer+fileSize)-sz) / iNeededSize; - add += add >> 3; // add 12.5% as buffer - iNeededSize = (pMesh->mNumFaces + add)*3; - aiVector3D* pv = new aiVector3D[iNeededSize]; - memcpy(pv,pMesh->mVertices,pMesh->mNumVertices*sizeof(aiVector3D)); - delete[] pMesh->mVertices; - pMesh->mVertices = pv; - pv = new aiVector3D[iNeededSize]; - memcpy(pv,pMesh->mNormals,pMesh->mNumVertices*sizeof(aiVector3D)); - delete[] pMesh->mNormals; - pMesh->mNormals = pv; + uint faceVertexCounter = 0; + 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))) { - pMesh->mNumVertices = iNeededSize; - pMesh->mNumFaces += add; - } - aiVector3D* vn = &pMesh->mNormals[curFace++*3]; + 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; - curVertex = 0; - SkipSpaces(&sz); - if (strncmp(sz,"normal",6)) { - DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found"); - } - else - { - sz += 7; - SkipSpaces(&sz); - sz = fast_atoreal_move(sz, (float&)vn->x ); - SkipSpaces(&sz); - sz = fast_atoreal_move(sz, (float&)vn->y ); - SkipSpaces(&sz); - sz = fast_atoreal_move(sz, (float&)vn->z ); - *(vn+1) = *vn; - *(vn+2) = *vn; - } - } - // vertex 1.50000 1.50000 0.00000 - else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6))) - { - if (3 == curVertex) { - DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found"); - ++sz; - } - else - { - sz += 7; - SkipSpaces(&sz); - aiVector3D* vn = &pMesh->mVertices[(curFace-1)*3 + curVertex++]; - sz = fast_atoreal_move(sz, (float&)vn->x ); - SkipSpaces(&sz); - sz = fast_atoreal_move(sz, (float&)vn->y ); - SkipSpaces(&sz); - sz = fast_atoreal_move(sz, (float&)vn->z ); - } - } - else if (!::strncmp(sz,"endsolid",8)) { - // finished! - break; - } - // else skip the whole identifier - else { - do { - ++sz; - } while (!::IsSpaceOrNewLine(*sz)); - } - } + sz += 6; + SkipSpaces(&sz); + if (strncmp(sz,"normal",6)) { + DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found"); + } + else + { + sz += 7; + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (float&)vn->x ); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (float&)vn->y ); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (float&)vn->z ); + normalBuffer.push_back(*vn); + normalBuffer.push_back(*vn); + } + } + // vertex 1.50000 1.50000 0.00000 + else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6))) + { + if (faceVertexCounter >= 3) { + DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found"); + ++sz; + } + else + { + sz += 7; + SkipSpaces(&sz); + positionBuffer.push_back(aiVector3D()); + aiVector3D* vn = &positionBuffer.back(); + sz = fast_atoreal_move(sz, (float&)vn->x ); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (float&)vn->y ); + SkipSpaces(&sz); + sz = fast_atoreal_move(sz, (float&)vn->z ); + faceVertexCounter++; + } + } + else if (!::strncmp(sz,"endsolid",8)) { + do { + ++sz; + } while (!::IsLineEnd(*sz)); + SkipSpacesAndLineEnd(&sz); + // finished! + break; + } + // else skip the whole identifier + else { + do { + ++sz; + } while (!::IsSpaceOrNewLine(*sz)); + } + } - if (!curFace) { - pMesh->mNumFaces = 0; - throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded"); - } - pMesh->mNumFaces = curFace; - pMesh->mNumVertices = curFace*3; - // we are finished! + 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 = positionBuffer.size() / 3; + pMesh->mNumVertices = 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); + } + // 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]; + } } // ------------------------------------------------------------------------------------------------ // 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"); @@ -374,7 +399,6 @@ bool STLImporter::LoadBinaryFile() const unsigned char* sz = (const unsigned char*)mBuffer + 80; // now read the number of facets - aiMesh* pMesh = pScene->mMeshes[0]; pScene->mRootNode->mName.Set(""); pMesh->mNumFaces = *((uint32_t*)sz); @@ -447,6 +471,10 @@ bool STLImporter::LoadBinaryFile() *(clr+2) = *clr; } } + + // now copy faces + addFacesToMesh(pMesh); + if (bIsMaterialise && !pMesh->mColors[0]) { // use the color as diffuse material color