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 // allocate a single node
pScene->mNumMeshes = 1; pScene->mRootNode = new aiNode();
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;
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,140 +213,165 @@ 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* bufferEnd = mBuffer + fileSize;
std::vector<aiVector3D> positionBuffer;
std::vector<aiVector3D> normalBuffer;
const char* sz = mBuffer; // try to guess how many vertices we could have
SkipSpaces(&sz); // assume we'll need 160 bytes for each face
ai_assert(!IsLineEnd(sz)); size_t sizeEstimate = std::max(1u, fileSize / 160u ) * 3;
positionBuffer.reserve(sizeEstimate);
normalBuffer.reserve(sizeEstimate);
sz += 5; // skip the "solid" while (IsAsciiSTL(sz, bufferEnd - sz))
SkipSpaces(&sz); {
const char* szMe = sz; aiMesh* pMesh = new aiMesh();
while (!::IsSpaceOrNewLine(*sz)) { pMesh->mMaterialIndex = 0;
sz++; meshes.push_back(pMesh);
}
size_t temp; SkipSpaces(&sz);
// setup the name of the node ai_assert(!IsLineEnd(sz));
if ((temp = (size_t)(sz-szMe))) {
if (temp >= MAXLEN) {
throw DeadlyImportError( "STL: Node name too long" );
}
pScene->mRootNode->mName.length = temp; sz += 5; // skip the "solid"
memcpy(pScene->mRootNode->mName.data,szMe,temp); SkipSpaces(&sz);
pScene->mRootNode->mName.data[temp] = '\0'; const char* szMe = sz;
} while (!::IsSpaceOrNewLine(*sz)) {
else pScene->mRootNode->mName.Set("<STL_ASCII>"); sz++;
}
// try to guess how many vertices we could have size_t temp;
// assume we'll need 160 bytes for each face // setup the name of the node
pMesh->mNumVertices = ( pMesh->mNumFaces = std::max(1u,fileSize / 160u )) * 3; if ((temp = (size_t)(sz-szMe))) {
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; if (temp >= MAXLEN) {
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; throw DeadlyImportError( "STL: Node name too long" );
}
unsigned int curFace = 0, curVertex = 3; pScene->mRootNode->mName.length = temp;
for ( ;; ) memcpy(pScene->mRootNode->mName.data,szMe,temp);
{ pScene->mRootNode->mName.data[temp] = '\0';
// go to the next token }
if(!SkipSpacesAndLineEnd(&sz)) else pScene->mRootNode->mName.Set("<STL_ASCII>");
{
// 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))) {
if (3 != curVertex) { uint faceVertexCounter = 0;
DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete"); for ( ;; )
} {
if (pMesh->mNumFaces == curFace) { // go to the next token
ai_assert(pMesh->mNumFaces != 0); 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))) {
// need to resize the arrays, our size estimate was wrong if (faceVertexCounter != 3) {
unsigned int iNeededSize = (unsigned int)(sz-mBuffer) / pMesh->mNumFaces; DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete");
if (iNeededSize <= 160)iNeededSize >>= 1; // prevent endless looping }
unsigned int add = (unsigned int)((mBuffer+fileSize)-sz) / iNeededSize; faceVertexCounter = 0;
add += add >> 3; // add 12.5% as buffer normalBuffer.push_back(aiVector3D());
iNeededSize = (pMesh->mNumFaces + add)*3; aiVector3D* vn = &normalBuffer.back();
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; sz += 6;
pMesh->mNumFaces += add; SkipSpaces(&sz);
} if (strncmp(sz,"normal",6)) {
aiVector3D* vn = &pMesh->mNormals[curFace++*3]; DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
}
else
{
sz += 7;
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->x );
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->y );
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(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<float>(sz, (float&)vn->x );
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->y );
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(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));
}
}
sz += 6; if (positionBuffer.empty()) {
curVertex = 0; pMesh->mNumFaces = 0;
SkipSpaces(&sz); throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded");
if (strncmp(sz,"normal",6)) { }
DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found"); if (positionBuffer.size() % 3 != 0) {
} pMesh->mNumFaces = 0;
else throw DeadlyImportError("STL: Invalid number of vertices");
{ }
sz += 7; if (normalBuffer.size() != positionBuffer.size()) {
SkipSpaces(&sz); pMesh->mNumFaces = 0;
sz = fast_atoreal_move<float>(sz, (float&)vn->x ); throw DeadlyImportError("Normal buffer size does not match position buffer size");
SkipSpaces(&sz); }
sz = fast_atoreal_move<float>(sz, (float&)vn->y ); pMesh->mNumFaces = positionBuffer.size() / 3;
SkipSpaces(&sz); pMesh->mNumVertices = positionBuffer.size();
sz = fast_atoreal_move<float>(sz, (float&)vn->z ); pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
*(vn+1) = *vn; memcpy(pMesh->mVertices, &positionBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
*(vn+2) = *vn; positionBuffer.clear();
} pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
} memcpy(pMesh->mNormals, &normalBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
// vertex 1.50000 1.50000 0.00000 normalBuffer.clear();
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<float>(sz, (float&)vn->x );
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->y );
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float&)vn->z );
}
}
else if (!::strncmp(sz,"endsolid",8)) {
// finished!
break;
}
// else skip the whole identifier
else {
do {
++sz;
} while (!::IsSpaceOrNewLine(*sz));
}
}
if (!curFace) { // now copy faces
pMesh->mNumFaces = 0; addFacesToMesh(pMesh);
throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded"); }
} // now add the loaded meshes
pMesh->mNumFaces = curFace; pScene->mNumMeshes = (unsigned int)meshes.size();
pMesh->mNumVertices = curFace*3; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
// we are finished! 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