mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-25 07:32:25 +01:00
Speed up stl format loading, especially with text format.
Loading whole file now in memory (unless it's already a memory file). And avoiding lots of memory allocations otherwise by buffering token string in class object. Was a bit unusable before for large files (several minute loading times now down to a second)- git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6349 dfc29bdd-3216-0410-991c-e03cc46cb475
This commit is contained in:
parent
9504b3da21
commit
439667b369
@ -1,5 +1,7 @@
|
|||||||
--------------------------
|
--------------------------
|
||||||
Changes in 1.9 (not yet released)
|
Changes in 1.9 (not yet released)
|
||||||
|
- stl meshloader now faster, especially with text format
|
||||||
|
- CMemoryReadFile::seek no longer allowed to go _before_ start.
|
||||||
- stl meshloader can now load 32 bit buffers.
|
- stl meshloader can now load 32 bit buffers.
|
||||||
Thanks @Foaly for the patch (https://irrlicht.sourceforge.io/forum/viewtopic.php?f=9&t=51441)
|
Thanks @Foaly for the patch (https://irrlicht.sourceforge.io/forum/viewtopic.php?f=9&t=51441)
|
||||||
- Add IMeshBufffer::clone function to create buffer copies. CMeshManipulator::createMeshCopy uses that now and works now with all types of meshbuffers.
|
- Add IMeshBufffer::clone function to create buffer copies. CMeshManipulator::createMeshCopy uses that now and works now with all types of meshbuffers.
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "CSTLMeshFileLoader.h"
|
#include "CSTLMeshFileLoader.h"
|
||||||
#include "SMesh.h"
|
#include "SMesh.h"
|
||||||
#include "CDynamicMeshBuffer.h"
|
#include "CDynamicMeshBuffer.h"
|
||||||
|
#include "CMemoryFile.h"
|
||||||
#include "SAnimatedMesh.h"
|
#include "SAnimatedMesh.h"
|
||||||
#include "IReadFile.h"
|
#include "IReadFile.h"
|
||||||
#include "fast_atof.h"
|
#include "fast_atof.h"
|
||||||
@ -34,12 +35,26 @@ bool CSTLMeshFileLoader::isALoadableFileExtension(const io::path& filename) cons
|
|||||||
//! \return Pointer to the created mesh. Returns 0 if loading failed.
|
//! \return Pointer to the created mesh. Returns 0 if loading failed.
|
||||||
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
|
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
|
||||||
//! See IReferenceCounted::drop() for more information.
|
//! See IReferenceCounted::drop() for more information.
|
||||||
IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file)
|
IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* fileIn)
|
||||||
{
|
{
|
||||||
const long filesize = file->getSize();
|
const long filesize = fileIn->getSize();
|
||||||
if (filesize < 6) // we need a header
|
if (filesize < 6) // we need a header
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// We copy the whole file into a memory-read file if it isn't already one.
|
||||||
|
io::CMemoryReadFile * memoryFile = 0;
|
||||||
|
if ( fileIn->getType() != io::ERFT_MEMORY_READ_FILE )
|
||||||
|
{
|
||||||
|
u8* fileBuffer = new u8[filesize];
|
||||||
|
if ( fileIn->read(fileBuffer, filesize) != filesize )
|
||||||
|
{
|
||||||
|
delete[] fileBuffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memoryFile = new io::CMemoryReadFile(fileBuffer, filesize, io::path(""), true); // takes over fileBuffer
|
||||||
|
}
|
||||||
|
io::IReadFile* file = memoryFile ? memoryFile : fileIn;
|
||||||
|
|
||||||
SMesh* mesh = new SMesh();
|
SMesh* mesh = new SMesh();
|
||||||
CDynamicMeshBuffer* meshBuffer = new CDynamicMeshBuffer(video::EVT_STANDARD, video::EIT_16BIT);
|
CDynamicMeshBuffer* meshBuffer = new CDynamicMeshBuffer(video::EVT_STANDARD, video::EIT_16BIT);
|
||||||
IVertexBuffer& vertBuffer = meshBuffer->getVertexBuffer();
|
IVertexBuffer& vertBuffer = meshBuffer->getVertexBuffer();
|
||||||
@ -50,8 +65,7 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file)
|
|||||||
core::vector3df normal;
|
core::vector3df normal;
|
||||||
|
|
||||||
bool binary = false;
|
bool binary = false;
|
||||||
core::stringc token;
|
if (getNextToken(file) != "solid")
|
||||||
if (getNextToken(file, token) != "solid")
|
|
||||||
binary = true;
|
binary = true;
|
||||||
// read/skip header
|
// read/skip header
|
||||||
u32 binFaceCount = 0;
|
u32 binFaceCount = 0;
|
||||||
@ -67,62 +81,64 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file)
|
|||||||
goNextLine(file);
|
goNextLine(file);
|
||||||
|
|
||||||
u16 attrib=0;
|
u16 attrib=0;
|
||||||
token.reserve(32);
|
Token.reserve(32);
|
||||||
|
bool failure = false;
|
||||||
|
|
||||||
while (file->getPos() < filesize)
|
while (file->getPos() < filesize)
|
||||||
{
|
{
|
||||||
if (!binary)
|
if (!binary)
|
||||||
{
|
{
|
||||||
if (getNextToken(file, token) != "facet")
|
if (getNextToken(file) != "facet")
|
||||||
{
|
{
|
||||||
if (token=="endsolid")
|
if (Token!="endsolid")
|
||||||
break;
|
failure = true;
|
||||||
mesh->drop();
|
break;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (getNextToken(file, token) != "normal")
|
if (getNextToken(file) != "normal")
|
||||||
{
|
{
|
||||||
mesh->drop();
|
failure = true;
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getNextVector(file, normal, binary);
|
getNextVector(file, normal, binary);
|
||||||
if (!binary)
|
if (!binary)
|
||||||
{
|
{
|
||||||
if (getNextToken(file, token) != "outer")
|
if (getNextToken(file) != "outer")
|
||||||
{
|
{
|
||||||
mesh->drop();
|
failure = true;
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
if (getNextToken(file, token) != "loop")
|
if (getNextToken(file) != "loop")
|
||||||
{
|
{
|
||||||
mesh->drop();
|
failure = true;
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (u32 i=0; i<3; ++i)
|
for (u32 i=0; i<3; ++i)
|
||||||
{
|
{
|
||||||
if (!binary)
|
if (!binary)
|
||||||
{
|
{
|
||||||
if (getNextToken(file, token) != "vertex")
|
if (getNextToken(file) != "vertex")
|
||||||
{
|
{
|
||||||
mesh->drop();
|
failure = true;
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getNextVector(file, vertex[i], binary);
|
getNextVector(file, vertex[i], binary);
|
||||||
}
|
}
|
||||||
|
if ( failure )
|
||||||
|
break;
|
||||||
if (!binary)
|
if (!binary)
|
||||||
{
|
{
|
||||||
if (getNextToken(file, token) != "endloop")
|
if (getNextToken(file) != "endloop")
|
||||||
{
|
{
|
||||||
mesh->drop();
|
failure = true;
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
if (getNextToken(file, token) != "endfacet")
|
if (getNextToken(file) != "endfacet")
|
||||||
{
|
{
|
||||||
mesh->drop();
|
failure = true;
|
||||||
return 0;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -145,7 +161,7 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file)
|
|||||||
|
|
||||||
// Create the Animated mesh if there's anything in the mesh
|
// Create the Animated mesh if there's anything in the mesh
|
||||||
SAnimatedMesh* pAM = 0;
|
SAnimatedMesh* pAM = 0;
|
||||||
if ( 0 != mesh->getMeshBufferCount() )
|
if ( !failure && mesh->getMeshBufferCount() > 0 )
|
||||||
{
|
{
|
||||||
IIndexBuffer& indexBuffer = meshBuffer->getIndexBuffer();
|
IIndexBuffer& indexBuffer = meshBuffer->getIndexBuffer();
|
||||||
u32 vertCount = vertBuffer.size();
|
u32 vertCount = vertBuffer.size();
|
||||||
@ -173,13 +189,16 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mesh->drop();
|
mesh->drop();
|
||||||
|
Token.clear();
|
||||||
|
if ( memoryFile )
|
||||||
|
memoryFile->drop();
|
||||||
|
|
||||||
return pAM;
|
return pAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Read 3d vector of floats
|
//! Read 3d vector of floats
|
||||||
void CSTLMeshFileLoader::getNextVector(io::IReadFile* file, core::vector3df& vec, bool binary) const
|
void CSTLMeshFileLoader::getNextVector(io::IReadFile* file, core::vector3df& vec, bool binary)
|
||||||
{
|
{
|
||||||
if (binary)
|
if (binary)
|
||||||
{
|
{
|
||||||
@ -195,34 +214,33 @@ void CSTLMeshFileLoader::getNextVector(io::IReadFile* file, core::vector3df& vec
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
goNextWord(file);
|
goNextWord(file);
|
||||||
core::stringc tmp;
|
|
||||||
|
|
||||||
getNextToken(file, tmp);
|
getNextToken(file);
|
||||||
core::fast_atof_move(tmp.c_str(), vec.X);
|
core::fast_atof_move(Token.c_str(), vec.X);
|
||||||
getNextToken(file, tmp);
|
getNextToken(file);
|
||||||
core::fast_atof_move(tmp.c_str(), vec.Y);
|
core::fast_atof_move(Token.c_str(), vec.Y);
|
||||||
getNextToken(file, tmp);
|
getNextToken(file);
|
||||||
core::fast_atof_move(tmp.c_str(), vec.Z);
|
core::fast_atof_move(Token.c_str(), vec.Z);
|
||||||
}
|
}
|
||||||
vec.X=-vec.X;
|
vec.X=-vec.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Read next word
|
//! Read next word
|
||||||
const core::stringc& CSTLMeshFileLoader::getNextToken(io::IReadFile* file, core::stringc& token) const
|
const core::stringc& CSTLMeshFileLoader::getNextToken(io::IReadFile* file)
|
||||||
{
|
{
|
||||||
goNextWord(file);
|
goNextWord(file);
|
||||||
u8 c;
|
u8 c;
|
||||||
token = "";
|
Token = "";
|
||||||
while(file->getPos() != file->getSize())
|
while(file->getPos() != file->getSize())
|
||||||
{
|
{
|
||||||
file->read(&c, 1);
|
file->read(&c, 1);
|
||||||
// found it, so leave
|
// found it, so leave
|
||||||
if (core::isspace(c))
|
if (core::isspace(c))
|
||||||
break;
|
break;
|
||||||
token.append(c);
|
Token.append(c);
|
||||||
}
|
}
|
||||||
return token;
|
return Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,12 +34,15 @@ private:
|
|||||||
// skips to the first non-space character available
|
// skips to the first non-space character available
|
||||||
void goNextWord(io::IReadFile* file) const;
|
void goNextWord(io::IReadFile* file) const;
|
||||||
// returns the next word
|
// returns the next word
|
||||||
const core::stringc& getNextToken(io::IReadFile* file, core::stringc& token) const;
|
const core::stringc& getNextToken(io::IReadFile* file);
|
||||||
// skip to next printable character after the first line break
|
// skip to next printable character after the first line break
|
||||||
void goNextLine(io::IReadFile* file) const;
|
void goNextLine(io::IReadFile* file) const;
|
||||||
|
|
||||||
//! Read 3d vector of floats
|
//! Read 3d vector of floats
|
||||||
void getNextVector(io::IReadFile* file, core::vector3df& vec, bool binary) const;
|
void getNextVector(io::IReadFile* file, core::vector3df& vec, bool binary);
|
||||||
|
|
||||||
|
//! Buffering last read token to avoid reallocating string all the time
|
||||||
|
core::stringc Token;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace scene
|
} // end namespace scene
|
||||||
|
Loading…
Reference in New Issue
Block a user