STL loader can now handle more than one mesh in a single ascii file.
parent
ee98c80654
commit
59b0819866
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue