From 439667b36901b013e878dd81eb83d16b58d45d67 Mon Sep 17 00:00:00 2001 From: cutealien Date: Wed, 20 Apr 2022 22:09:03 +0000 Subject: [PATCH] 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 --- changes.txt | 2 + source/Irrlicht/CSTLMeshFileLoader.cpp | 100 +++++++++++++++---------- source/Irrlicht/CSTLMeshFileLoader.h | 7 +- 3 files changed, 66 insertions(+), 43 deletions(-) diff --git a/changes.txt b/changes.txt index a14daf2c..a0fa6367 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,7 @@ -------------------------- 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. 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. diff --git a/source/Irrlicht/CSTLMeshFileLoader.cpp b/source/Irrlicht/CSTLMeshFileLoader.cpp index bd65703b..315cf15d 100644 --- a/source/Irrlicht/CSTLMeshFileLoader.cpp +++ b/source/Irrlicht/CSTLMeshFileLoader.cpp @@ -9,6 +9,7 @@ #include "CSTLMeshFileLoader.h" #include "SMesh.h" #include "CDynamicMeshBuffer.h" +#include "CMemoryFile.h" #include "SAnimatedMesh.h" #include "IReadFile.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. //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! 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 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(); CDynamicMeshBuffer* meshBuffer = new CDynamicMeshBuffer(video::EVT_STANDARD, video::EIT_16BIT); IVertexBuffer& vertBuffer = meshBuffer->getVertexBuffer(); @@ -50,8 +65,7 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) core::vector3df normal; bool binary = false; - core::stringc token; - if (getNextToken(file, token) != "solid") + if (getNextToken(file) != "solid") binary = true; // read/skip header u32 binFaceCount = 0; @@ -67,62 +81,64 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) goNextLine(file); u16 attrib=0; - token.reserve(32); + Token.reserve(32); + bool failure = false; while (file->getPos() < filesize) { if (!binary) { - if (getNextToken(file, token) != "facet") + if (getNextToken(file) != "facet") { - if (token=="endsolid") - break; - mesh->drop(); - return 0; + if (Token!="endsolid") + failure = true; + break; } - if (getNextToken(file, token) != "normal") + if (getNextToken(file) != "normal") { - mesh->drop(); - return 0; + failure = true; + break; } } getNextVector(file, normal, binary); if (!binary) { - if (getNextToken(file, token) != "outer") + if (getNextToken(file) != "outer") { - mesh->drop(); - return 0; + failure = true; + break; } - if (getNextToken(file, token) != "loop") + if (getNextToken(file) != "loop") { - mesh->drop(); - return 0; + failure = true; + break; } } for (u32 i=0; i<3; ++i) { if (!binary) { - if (getNextToken(file, token) != "vertex") + if (getNextToken(file) != "vertex") { - mesh->drop(); - return 0; + failure = true; + break; } } getNextVector(file, vertex[i], binary); } + if ( failure ) + break; if (!binary) { - if (getNextToken(file, token) != "endloop") + if (getNextToken(file) != "endloop") { - mesh->drop(); - return 0; + failure = true; + break; } - if (getNextToken(file, token) != "endfacet") + if (getNextToken(file) != "endfacet") { - mesh->drop(); - return 0; + failure = true; + break; } } else @@ -145,7 +161,7 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) // Create the Animated mesh if there's anything in the mesh SAnimatedMesh* pAM = 0; - if ( 0 != mesh->getMeshBufferCount() ) + if ( !failure && mesh->getMeshBufferCount() > 0 ) { IIndexBuffer& indexBuffer = meshBuffer->getIndexBuffer(); u32 vertCount = vertBuffer.size(); @@ -173,13 +189,16 @@ IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) } mesh->drop(); + Token.clear(); + if ( memoryFile ) + memoryFile->drop(); return pAM; } //! 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) { @@ -195,34 +214,33 @@ void CSTLMeshFileLoader::getNextVector(io::IReadFile* file, core::vector3df& vec else { goNextWord(file); - core::stringc tmp; - getNextToken(file, tmp); - core::fast_atof_move(tmp.c_str(), vec.X); - getNextToken(file, tmp); - core::fast_atof_move(tmp.c_str(), vec.Y); - getNextToken(file, tmp); - core::fast_atof_move(tmp.c_str(), vec.Z); + getNextToken(file); + core::fast_atof_move(Token.c_str(), vec.X); + getNextToken(file); + core::fast_atof_move(Token.c_str(), vec.Y); + getNextToken(file); + core::fast_atof_move(Token.c_str(), vec.Z); } vec.X=-vec.X; } //! 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); u8 c; - token = ""; + Token = ""; while(file->getPos() != file->getSize()) { file->read(&c, 1); // found it, so leave if (core::isspace(c)) break; - token.append(c); + Token.append(c); } - return token; + return Token; } diff --git a/source/Irrlicht/CSTLMeshFileLoader.h b/source/Irrlicht/CSTLMeshFileLoader.h index d5cbdecd..68415186 100644 --- a/source/Irrlicht/CSTLMeshFileLoader.h +++ b/source/Irrlicht/CSTLMeshFileLoader.h @@ -34,12 +34,15 @@ private: // skips to the first non-space character available void goNextWord(io::IReadFile* file) const; // 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 void goNextLine(io::IReadFile* file) const; //! 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