STL loader can now handle more than one mesh in a single ascii file.

pull/633/head
Andreas Henne 2015-03-19 17:27:06 +01:00
parent ee98c80654
commit 59b0819866
1 changed files with 168 additions and 140 deletions

View File

@ -131,6 +131,19 @@ const aiImporterDesc* STLImporter::GetInfo () const
return &desc; 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. // Imports the given file into the given scene structure.
void STLImporter::InternReadFile( const std::string& pFile, 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. // the default vertex color is light gray.
clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = 0.6f; 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 // allocate a single node
pScene->mRootNode = new aiNode(); pScene->mRootNode = new aiNode();
pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0;
bool bMatClr = false; bool bMatClr = false;
@ -178,16 +182,12 @@ void STLImporter::InternReadFile( const std::string& pFile,
throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + "."); throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + ".");
} }
// now copy faces // add all created meshes to the single node
pMesh->mFaces = new aiFace[pMesh->mNumFaces]; pScene->mRootNode = new aiNode();
for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces;++i) { pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
aiFace& face = pMesh->mFaces[i]; for (uint i = 0; i < pScene->mNumMeshes; i++)
face.mIndices = new unsigned int[face.mNumIndices = 3]; pScene->mRootNode->mMeshes[i] = i;
for (unsigned int o = 0; o < 3;++o,++p) {
face.mIndices[o] = p;
}
}
// create a single default material, using a light gray diffuse color for consistency with // create a single default material, using a light gray diffuse color for consistency with
// other geometric types (e.g., PLY). // other geometric types (e.g., PLY).
@ -213,9 +213,24 @@ void STLImporter::InternReadFile( const std::string& pFile,
// Read an ASCII STL file // Read an ASCII STL file
void STLImporter::LoadASCIIFile() void STLImporter::LoadASCIIFile()
{ {
aiMesh* pMesh = pScene->mMeshes[0]; std::vector<aiMesh*> meshes;
const char* sz = mBuffer; 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, bufferEnd - sz))
{
aiMesh* pMesh = new aiMesh();
pMesh->mMaterialIndex = 0;
meshes.push_back(pMesh);
SkipSpaces(&sz); SkipSpaces(&sz);
ai_assert(!IsLineEnd(sz)); ai_assert(!IsLineEnd(sz));
@ -239,13 +254,7 @@ void STLImporter::LoadASCIIFile()
} }
else pScene->mRootNode->mName.Set("<STL_ASCII>"); else pScene->mRootNode->mName.Set("<STL_ASCII>");
// try to guess how many vertices we could have uint faceVertexCounter = 0;
// 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 ( ;; ) for ( ;; )
{ {
// go to the next token // go to the next token
@ -258,34 +267,14 @@ void STLImporter::LoadASCIIFile()
// facet normal -0.13 -0.13 -0.98 // facet normal -0.13 -0.13 -0.98
if (!strncmp(sz,"facet",5) && IsSpaceOrNewLine(*(sz+5))) { if (!strncmp(sz,"facet",5) && IsSpaceOrNewLine(*(sz+5))) {
if (3 != curVertex) { if (faceVertexCounter != 3) {
DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete"); DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete");
} }
if (pMesh->mNumFaces == curFace) { faceVertexCounter = 0;
ai_assert(pMesh->mNumFaces != 0); normalBuffer.push_back(aiVector3D());
aiVector3D* vn = &normalBuffer.back();
// 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;
pMesh->mNumVertices = iNeededSize;
pMesh->mNumFaces += add;
}
aiVector3D* vn = &pMesh->mNormals[curFace++*3];
sz += 6; sz += 6;
curVertex = 0;
SkipSpaces(&sz); SkipSpaces(&sz);
if (strncmp(sz,"normal",6)) { if (strncmp(sz,"normal",6)) {
DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found"); DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
@ -299,14 +288,14 @@ void STLImporter::LoadASCIIFile()
sz = fast_atoreal_move<float>(sz, (float&)vn->y ); sz = fast_atoreal_move<float>(sz, (float&)vn->y );
SkipSpaces(&sz); SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->z ); sz = fast_atoreal_move<float>(sz, (float&)vn->z );
*(vn+1) = *vn; normalBuffer.push_back(*vn);
*(vn+2) = *vn; normalBuffer.push_back(*vn);
} }
} }
// vertex 1.50000 1.50000 0.00000 // vertex 1.50000 1.50000 0.00000
else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6))) else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6)))
{ {
if (3 == curVertex) { if (faceVertexCounter >= 3) {
DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found"); DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found");
++sz; ++sz;
} }
@ -314,15 +303,21 @@ void STLImporter::LoadASCIIFile()
{ {
sz += 7; sz += 7;
SkipSpaces(&sz); SkipSpaces(&sz);
aiVector3D* vn = &pMesh->mVertices[(curFace-1)*3 + curVertex++]; positionBuffer.push_back(aiVector3D());
aiVector3D* vn = &positionBuffer.back();
sz = fast_atoreal_move<float>(sz, (float&)vn->x ); sz = fast_atoreal_move<float>(sz, (float&)vn->x );
SkipSpaces(&sz); SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->y ); sz = fast_atoreal_move<float>(sz, (float&)vn->y );
SkipSpaces(&sz); SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->z ); sz = fast_atoreal_move<float>(sz, (float&)vn->z );
faceVertexCounter++;
} }
} }
else if (!::strncmp(sz,"endsolid",8)) { else if (!::strncmp(sz,"endsolid",8)) {
do {
++sz;
} while (!::IsLineEnd(*sz));
SkipSpacesAndLineEnd(&sz);
// finished! // finished!
break; break;
} }
@ -334,19 +329,49 @@ void STLImporter::LoadASCIIFile()
} }
} }
if (!curFace) { if (positionBuffer.empty()) {
pMesh->mNumFaces = 0; pMesh->mNumFaces = 0;
throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded"); throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded");
} }
pMesh->mNumFaces = curFace; if (positionBuffer.size() % 3 != 0) {
pMesh->mNumVertices = curFace*3; pMesh->mNumFaces = 0;
// we are finished! 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 // Read a binary STL file
bool STLImporter::LoadBinaryFile() 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 // skip the first 80 bytes
if (fileSize < 84) { if (fileSize < 84) {
throw DeadlyImportError("STL: file is too small for the header"); 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; const unsigned char* sz = (const unsigned char*)mBuffer + 80;
// now read the number of facets // now read the number of facets
aiMesh* pMesh = pScene->mMeshes[0];
pScene->mRootNode->mName.Set("<STL_BINARY>"); pScene->mRootNode->mName.Set("<STL_BINARY>");
pMesh->mNumFaces = *((uint32_t*)sz); pMesh->mNumFaces = *((uint32_t*)sz);
@ -447,6 +471,10 @@ bool STLImporter::LoadBinaryFile()
*(clr+2) = *clr; *(clr+2) = *clr;
} }
} }
// now copy faces
addFacesToMesh(pMesh);
if (bIsMaterialise && !pMesh->mColors[0]) if (bIsMaterialise && !pMesh->mColors[0])
{ {
// use the color as diffuse material color // use the color as diffuse material color