diff --git a/include/eepp/graphics/texturefactory.hpp b/include/eepp/graphics/texturefactory.hpp index fd9be205f..f3386fbc6 100644 --- a/include/eepp/graphics/texturefactory.hpp +++ b/include/eepp/graphics/texturefactory.hpp @@ -1,6 +1,7 @@ #ifndef EECTEXTUREFACTORY_H #define EECTEXTUREFACTORY_H +#include #include #include #include @@ -182,7 +183,7 @@ class EE_API TextureFactory : protected Mutex { void setCurrentTexture( const int& TexId, const Uint32& TextureUnit ); /** Returns the number of textures loaded */ - Uint32 getTextureCount() const { return (Uint32)mTextures.size(); } + Uint32 getTextureCount(); /** @return All the active textures */ std::vector getTextures(); @@ -211,11 +212,8 @@ class EE_API TextureFactory : protected Mutex { /** Reload all the grabbed textures */ void ungrabTextures(); - /** Allocate space for Textures (only works if EE_ALLOC_TEXTURES_ON_VECTOR is defined) */ - void allocate( const unsigned int& size ); - /** @return The memory used by the textures (in bytes) */ - unsigned int getTextureMemorySize() { return mMemSize; } + unsigned int getTextureMemorySize(); /** It's possible to create textures outside the texture factory loader, but the library will * need to know of this texture, so it's necessary to push the texture to the factory. @@ -263,23 +261,23 @@ class EE_API TextureFactory : protected Mutex { std::vector mCurrentTexture; - std::vector mTextures; + UnorderedMap mTextures; unsigned int mMemSize; - std::vector mVectorFreeSlots; + Uint32 mTextureIdSeq; Texture::CoordinateType mLastCoordinateType; void unloadTextures(); - Uint32 findFreeSlot(); - bool mErasing; - const bool& isErasing() const; + bool isErasing(); void removeReference( Texture* Tex ); + + void updateMemorySize( Uint32 oldSize, Uint32 newSize ); }; }} // namespace EE::Graphics diff --git a/src/eepp/graphics/texture.cpp b/src/eepp/graphics/texture.cpp index 74a4025b3..dc85df87b 100644 --- a/src/eepp/graphics/texture.cpp +++ b/src/eepp/graphics/texture.cpp @@ -481,8 +481,7 @@ void Texture::reload() { mTexture = SOIL_create_OGL_texture( reinterpret_cast( &mPixels[0] ), &width, &height, mChannels, mTexture, flags ); - TextureFactory::instance()->mMemSize -= mSize; - + Uint32 oldSize = mSize; mSize = mWidth * mHeight * mChannels; if ( getMipmap() ) { @@ -496,7 +495,7 @@ void Texture::reload() { } } - TextureFactory::instance()->mMemSize += mSize; + TextureFactory::instance()->updateMemorySize( oldSize, mSize ); } iTextureFilter( mFilter ); @@ -593,9 +592,9 @@ void Texture::replace( Image* image ) { mHeight = mImgHeight = height; mChannels = image->getChannels(); - TextureFactory::instance()->mMemSize -= mSize; + Uint32 oldSize = mSize; mSize = mWidth * mHeight * mChannels; - TextureFactory::instance()->mMemSize += mSize; + TextureFactory::instance()->updateMemorySize( oldSize, mSize ); if ( hasLocalCopy() ) { // Renew the local copy diff --git a/src/eepp/graphics/texturefactory.cpp b/src/eepp/graphics/texturefactory.cpp index 112994318..d566a25ca 100644 --- a/src/eepp/graphics/texturefactory.cpp +++ b/src/eepp/graphics/texturefactory.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -17,11 +18,9 @@ SINGLETON_DECLARE_IMPLEMENTATION( TextureFactory ) TextureFactory::TextureFactory() : mCurrentTexture( EE_MAX_TEXTURE_UNITS ), mMemSize( 0 ), + mTextureIdSeq( 0 ), mLastCoordinateType( Texture::CoordinateType::Normalized ), - mErasing( false ) { - mTextures.clear(); - mTextures.push_back( NULL ); -} + mErasing( false ) {} const Texture::CoordinateType& TextureFactory::getLastCoordinateType() const { return mLastCoordinateType; @@ -104,7 +103,7 @@ Texture* TextureFactory::pushTexture( const std::string& Filepath, const Uint32& const Texture::ClampMode& ClampMode, const bool& CompressTexture, const bool& LocalCopy, const Uint32& MemSize ) { - lock(); + Lock l( *this ); Texture* Tex = NULL; Uint32 Pos; @@ -113,7 +112,7 @@ Texture* TextureFactory::pushTexture( const std::string& Filepath, const Uint32& FileSystem::filePathRemoveProcessPath( FPath ); - Pos = findFreeSlot(); + Pos = ++mTextureIdSeq; Tex = mTextures[Pos] = eeNew( Texture, () ); Tex->create( TexId, Width, Height, ImgWidth, ImgHeight, Mipmap, Channels, FPath, ClampMode, @@ -127,25 +126,9 @@ Texture* TextureFactory::pushTexture( const std::string& Filepath, const Uint32& mMemSize += MemSize; - unlock(); - return Tex; } -Uint32 TextureFactory::findFreeSlot() { - if ( !mVectorFreeSlots.empty() ) { - Uint32 Pos = mVectorFreeSlots.front(); - - mVectorFreeSlots.erase( mVectorFreeSlots.begin() ); - - return Pos; - } - - mTextures.push_back( NULL ); - - return (Uint32)mTextures.size() - 1; -} - void TextureFactory::bind( const Texture* texture, Texture::CoordinateType coordinateType, const Uint32& TextureUnit, const bool& forceRebind ) { if ( NULL != texture ) { @@ -195,23 +178,29 @@ void TextureFactory::bind( const Uint32& TexId, Texture::CoordinateType coordina } void TextureFactory::unloadTextures() { + Lock l( *this ); + mErasing = true; - for ( Uint32 i = 1; i < mTextures.size(); i++ ) - eeSAFE_DELETE( mTextures[i] ); + for ( auto& texture : mTextures ) + eeSAFE_DELETE( texture.second ); mErasing = false; mTextures.clear(); + mTextureIdSeq = 0; Log::debug( "Textures Unloaded." ); } bool TextureFactory::remove( Uint32 TexId ) { - Texture* Tex; + Lock l( *this ); - if ( TexId < mTextures.size() && NULL != ( Tex = mTextures[TexId] ) ) { - removeReference( mTextures[TexId] ); + Texture* Tex; + auto it = mTextures.find( TexId ); + + if ( it != mTextures.end() && NULL != ( Tex = it->second ) ) { + removeReference( Tex ); mErasing = true; eeDelete( Tex ); @@ -224,29 +213,51 @@ bool TextureFactory::remove( Uint32 TexId ) { } bool TextureFactory::remove( Texture* texture ) { - if ( std::find( mTextures.begin(), mTextures.end(), texture ) != mTextures.end() ) { + Lock l( *this ); + + auto it = std::find_if( mTextures.begin(), mTextures.end(), + [texture]( const auto& pair ) { return pair.second == texture; } ); + if ( it != mTextures.end() ) { removeReference( texture ); + + mErasing = true; + eeDelete( texture ); + mErasing = false; + return true; } return false; } void TextureFactory::removeReference( Texture* Tex ) { + Lock l( *this ); + + auto it = mTextures.find( Tex->getTextureId() ); + if ( it == mTextures.end() || it->second != Tex ) + return; + mMemSize -= Tex->getMemSize(); int glTexId = Tex->getHandle(); - mTextures[Tex->getTextureId()] = NULL; + mTextures.erase( it ); for ( Uint32 i = 0; i < EE_MAX_TEXTURE_UNITS; i++ ) { if ( mCurrentTexture[i] == (Int32)glTexId ) mCurrentTexture[i] = 0; } - - mVectorFreeSlots.push_back( Tex->getTextureId() ); } -const bool& TextureFactory::isErasing() const { +void TextureFactory::updateMemorySize( Uint32 oldSize, Uint32 newSize ) { + Lock l( *this ); + + mMemSize -= oldSize; + mMemSize += newSize; +} + +bool TextureFactory::isErasing() { + Lock l( *this ); + return mErasing; } @@ -261,11 +272,13 @@ void TextureFactory::setCurrentTexture( const int& TexId, const Uint32& TextureU } std::vector TextureFactory::getTextures() { + Lock l( *this ); + std::vector textures; textures.reserve( mTextures.size() ); - for ( Uint32 i = 1; i < mTextures.size(); i++ ) { - Texture* Tex = getTexture( i ); + for ( const auto& texture : mTextures ) { + Texture* Tex = texture.second; if ( Tex ) textures.push_back( Tex ); @@ -275,8 +288,10 @@ std::vector TextureFactory::getTextures() { } void TextureFactory::reloadAllTextures() { - for ( Uint32 i = 1; i < mTextures.size(); i++ ) { - Texture* Tex = getTexture( i ); + Lock l( *this ); + + for ( const auto& texture : mTextures ) { + Texture* Tex = texture.second; if ( Tex ) Tex->reload(); @@ -286,8 +301,10 @@ void TextureFactory::reloadAllTextures() { } void TextureFactory::grabTextures() { - for ( Uint32 i = 1; i < mTextures.size(); i++ ) { - Texture* Tex = getTexture( i ); + Lock l( *this ); + + for ( const auto& texture : mTextures ) { + Texture* Tex = texture.second; if ( Tex && !Tex->hasLocalCopy() ) { Tex->lock(); @@ -297,8 +314,10 @@ void TextureFactory::grabTextures() { } void TextureFactory::ungrabTextures() { - for ( Uint32 i = 1; i < mTextures.size(); i++ ) { - Texture* Tex = getTexture( i ); + Lock l( *this ); + + for ( const auto& texture : mTextures ) { + Texture* Tex = texture.second; if ( NULL != Tex && Tex->isGrabbed() ) { Tex->reload(); @@ -320,41 +339,57 @@ unsigned int TextureFactory::getValidTextureSize( const unsigned int& Size ) { } bool TextureFactory::existsId( const Uint32& TexId ) { - return ( TexId < mTextures.size() && TexId > 0 && NULL != mTextures[TexId] ); + Lock l( *this ); + + return mTextures.find( TexId ) != mTextures.end(); } bool TextureFactory::exists( const Texture* tex ) { - return std::find( mTextures.begin(), mTextures.end(), tex ) != mTextures.end(); + Lock l( *this ); + + return std::find_if( mTextures.begin(), mTextures.end(), [tex]( const auto& pair ) { + return pair.second == tex; + } ) != mTextures.end(); } Texture* TextureFactory::getTexture( const Uint32& TexId ) { - return mTextures[TexId]; -} + Lock l( *this ); -void TextureFactory::allocate( const unsigned int& size ) { - if ( size > mTextures.size() ) { - mTextures.resize( size + 1, NULL ); - - for ( unsigned int i = 1; i < mTextures.size(); i++ ) - mVectorFreeSlots.push_back( i ); - } + auto it = mTextures.find( TexId ); + return it != mTextures.end() ? it->second : NULL; } Texture* TextureFactory::getByName( const std::string& Name ) { return getByHash( String::hash( Name ) ); } +Uint32 TextureFactory::getTextureCount() { + Lock l( *this ); + + return (Uint32)mTextures.size(); +} + +unsigned int TextureFactory::getTextureMemorySize() { + Lock l( *this ); + + return mMemSize; +} + Texture* TextureFactory::getByHash( const String::HashType& hash ) { - Texture* tTex = NULL; + Lock l( *this ); - for ( Uint32 i = (Uint32)mTextures.size() - 1; i > 0; i-- ) { - tTex = mTextures[i]; + Uint32 latestId = 0; + Texture* latestTexture = NULL; + for ( const auto& texture : mTextures ) { + Texture* tTex = texture.second; - if ( NULL != tTex && tTex->getHashName() == hash ) - return mTextures[i]; + if ( NULL != tTex && texture.first > latestId && tTex->getHashName() == hash ) { + latestId = texture.first; + latestTexture = tTex; + } } - return NULL; + return latestTexture; } }} // namespace EE::Graphics diff --git a/src/eepp/ui/uiimage.cpp b/src/eepp/ui/uiimage.cpp index 5acfbcfd5..fb25d9510 100644 --- a/src/eepp/ui/uiimage.cpp +++ b/src/eepp/ui/uiimage.cpp @@ -21,7 +21,19 @@ namespace EE { namespace UI { namespace { std::string getTextureCacheName( const Network::URI& uri ) { - std::string filePath( uri.getFSPath() ); + std::string filePath( uri.toString() ); + if ( String::startsWith( filePath, "file://" ) ) + filePath = filePath.substr( 7 ); + else + filePath = uri.getFSPath(); + +#if EE_PLATFORM == EE_PLATFORM_WIN + if ( filePath.size() >= 3 && filePath[0] == '/' && String::isLetter( filePath[1] ) && + filePath[2] == ':' ) { + filePath = filePath.substr( 1 ); + } +#endif + FileSystem::filePathRemoveProcessPath( filePath ); return filePath; } diff --git a/src/tests/test_all/test.cpp b/src/tests/test_all/test.cpp index 3455fbc9a..79380eebf 100644 --- a/src/tests/test_all/test.cpp +++ b/src/tests/test_all/test.cpp @@ -141,7 +141,6 @@ void EETest::init() { mWindow->pushResizeCallback( [this]( auto event ) { onWindowResize( event ); } ); TF = TextureFactory::instance(); - TF->allocate( 40 ); Log = Log::instance(); KM = mWindow->getInput(); diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 7b07a914d..8d5cce3a2 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -1,6 +1,7 @@ #include "compareimages.hpp" #include "utest.hpp" +#include #include #include #include @@ -4298,11 +4299,11 @@ UTEST( UIHTML, DeferredFileImageReusesCachedTexture ) { const std::string processPath = Sys::getProcessPath(); UISceneNode* sceneNode = init_test_inline_block(); + sceneNode->setThreadPool( ThreadPool::createShared( 1 ) ); sceneNode->setURI( URI( "file://" + processPath ) ); URI imageURI = sceneNode->solveRelativePath( URI( "../assets/icon/ee.png" ) ); ASSERT_TRUE( FileSystem::fileExists( imageURI.getFSPath() ) ); - Texture* cached = TextureFactory::instance()->loadFromFile( - imageURI.getFSPath(), false, Texture::ClampMode::ClampToEdge, false, false ); + Drawable* cached = DrawableSearcher::searchByName( imageURI.toString() ); ASSERT_TRUE( cached != nullptr ); sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( R"html(