diff --git a/.agent/plans/resource_shared_ownership_architecture.md b/.agent/plans/resource_shared_ownership_architecture.md index 789d2fe16..37a745b0b 100644 --- a/.agent/plans/resource_shared_ownership_architecture.md +++ b/.agent/plans/resource_shared_ownership_architecture.md @@ -790,10 +790,12 @@ Exit criteria: ### Stage 7: remaining resource families -Status: in progress. Nine-patches are the first migrated family: `NinePatch::New()` returns a -`NinePatchPtr`, theme-owned `ResourceCatalog` instances retain their named sources, and scene -`ResourceScope` imports make those sources visible intentionally. `NinePatchManager` was removed. -Removing a catalog entry releases only catalog ownership and leaves retained consumers valid. +Status: in progress. Nine-patches and texture atlases are migrated. `NinePatch::New()`, +`TextureRegion::New()`, and `TextureAtlas::New()` return handles. Atlases retain region and texture +handles; loaders retain and publish atlas handles; theme-owned catalogs retain their named atlas +sources; and scene `ResourceScope` imports make those sources visible intentionally. +`NinePatchManager`, `TextureAtlasManager`, and `GlobalTextureAtlas` were removed. Removing a catalog +entry releases only catalog ownership and leaves separately retained consumers valid. This is the required pattern for the remaining process-wide singleton resource managers. A singleton must not be modernized into another process-global semantic namespace. Each family moves @@ -801,10 +803,10 @@ to ordinary catalogs owned by its application, scene, theme, document, or other boundary. `globalResourceCatalog()` is reserved for resources deliberately published process-wide; scene scopes see non-global resources only through their local catalog or explicit imports. -Migrate fonts, font faces/fallback caches, themes, shader programs/shaders, nine-patch catalogs, -atlas managers, and every remaining raw-owning ResourceManager subclass one family at a time. Their -self-contained GPU objects retain the established graphics-thread destruction contract unless a -concrete migration requires otherwise. +Migrate fonts, font faces/fallback caches, themes/icons, shader programs/shaders, and every remaining +raw-owning ResourceManager subclass one family at a time. Their self-contained GPU objects retain +the established graphics-thread destruction contract unless a concrete migration requires +otherwise. Remove raw-owning `ResourceManager` only when no subclass or consumer depends on it. @@ -872,7 +874,7 @@ Remove raw-owning `ResourceManager` only when no subclass or consumer depends ## 12. Next implementation deliverable Stage 7 continues with the remaining ResourceManager families one at a time: fonts and font caches, -themes/icons, shaders/programs, atlases, and any remaining raw-owning manager. Each singleton -semantic namespace is replaced by naturally owned catalogs plus explicit scope imports, following -the completed nine-patch migration. The raw-owning ResourceManager template is removed only after -its final consumer is migrated. +themes/icons, shaders/programs, and any remaining raw-owning manager. Each singleton semantic +namespace is replaced by naturally owned catalogs plus explicit scope imports, following the +completed nine-patch and texture-atlas migrations. The raw-owning ResourceManager template is +removed only after its final consumer is migrated. diff --git a/.ecode/project_build.json b/.ecode/project_build.json index 1a5edc961..1c763fed1 100644 --- a/.ecode/project_build.json +++ b/.ecode/project_build.json @@ -387,6 +387,12 @@ "command": "${project_root}/bin/eepp-ui-font-picker-debug", "name": "eepp-ui-font-picker-debug", "working_dir": "${project_root}/bin" + }, + { + "args": "", + "command": "${project_root}/bin/eepp-TextureAtlasEditor-debug", + "name": "eepp-TextureAtlasEditor-debug", + "working_dir": "${project_root}/bin" } ], "var": { diff --git a/include/eepp/graphics.hpp b/include/eepp/graphics.hpp index 78a08125f..9e57caa56 100644 --- a/include/eepp/graphics.hpp +++ b/include/eepp/graphics.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -66,7 +65,6 @@ #include #include #include -#include #include #include #include diff --git a/include/eepp/graphics/globaltextureatlas.hpp b/include/eepp/graphics/globaltextureatlas.hpp deleted file mode 100644 index c1c76be86..000000000 --- a/include/eepp/graphics/globaltextureatlas.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef EE_GRAPHICSCGLOBALTEXTUREATLAS_HPP -#define EE_GRAPHICSCGLOBALTEXTUREATLAS_HPP - -#include -#include - -#include -using namespace EE::System; - -namespace EE { namespace Graphics { - -/** @brief Any TextureRegion that doesn't belong to an specific TextureAtlas ( a real texture atlas - texture ), goes here. This is useful to auto release the TextureRegions. -*/ -class EE_API GlobalTextureAtlas : public TextureAtlas { - SINGLETON_DECLARE_HEADERS( GlobalTextureAtlas ) - - public: - ~GlobalTextureAtlas(); - - protected: - GlobalTextureAtlas(); -}; - -}} // namespace EE::Graphics - -#endif diff --git a/include/eepp/graphics/resourcecatalog.hpp b/include/eepp/graphics/resourcecatalog.hpp index a1161d7ec..7419dc870 100644 --- a/include/eepp/graphics/resourcecatalog.hpp +++ b/include/eepp/graphics/resourcecatalog.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace EE { namespace Graphics { @@ -21,16 +22,24 @@ class EE_API ResourceCatalog { void publish( std::string key, TexturePtr texture ); void publishDrawable( ResourceKey key, DrawablePtr drawable ); void publishDrawable( std::string key, DrawablePtr drawable ); + void publishAtlas( ResourceKey key, TextureAtlasPtr atlas ); + void publishAtlas( std::string key, TextureAtlasPtr atlas ); TexturePtr findTexture( const ResourceKey& key ) const; TexturePtr findTexture( const std::string& key ) const; DrawablePtr findDrawable( const ResourceKey& key ) const; DrawablePtr findDrawable( const std::string& key ) const; + DrawablePtr findDrawable( const String::HashType& id ) const; + TextureAtlasPtr findAtlas( const ResourceKey& key ) const; + TextureAtlasPtr findAtlas( const std::string& key ) const; + std::vector getAtlases() const; bool erase( const ResourceKey& key ); bool erase( const std::string& key ); bool eraseDrawable( const ResourceKey& key ); bool eraseDrawable( const std::string& key ); + bool eraseAtlas( const ResourceKey& key ); + bool eraseAtlas( const std::string& key ); void clear(); std::size_t size() const; @@ -38,6 +47,8 @@ class EE_API ResourceCatalog { mutable System::Mutex mMutex; UnorderedMap mTextures; UnorderedMap mDrawables; + UnorderedMap mDrawablesById; + UnorderedMap mAtlases; }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/resourcescope.hpp b/include/eepp/graphics/resourcescope.hpp index 65ce3220b..0f60fd457 100644 --- a/include/eepp/graphics/resourcescope.hpp +++ b/include/eepp/graphics/resourcescope.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace EE { namespace Graphics { @@ -22,15 +23,28 @@ class EE_API ResourceScope { DrawablePtr findDrawableSource( const std::string& key ) const; DrawablePtr findDrawable( const std::string& name, bool firstSearchSprite = false ) const; DrawablePtr findDrawable( const Uint32& id ) const; + TextureAtlasPtr findAtlas( const ResourceKey& key ) const; + TextureAtlasPtr findAtlas( const std::string& key ) const; + std::vector getAtlases() const; + std::vector + findTextureRegionsByPattern( const std::string& name, const std::string& extension = "", + TextureAtlas* searchInTextureAtlas = nullptr ) const; + std::vector + findTextureRegionsByPatternId( const String::HashType& id, const std::string& extension = "", + TextureAtlas* searchInTextureAtlas = nullptr ) const; void publishLocal( ResourceKey key, TexturePtr texture ); void publishLocal( std::string key, TexturePtr texture ); void publishLocalDrawable( ResourceKey key, DrawablePtr drawable ); void publishLocalDrawable( std::string key, DrawablePtr drawable ); + void publishLocalAtlas( ResourceKey key, TextureAtlasPtr atlas ); + void publishLocalAtlas( std::string key, TextureAtlasPtr atlas ); bool eraseLocal( const ResourceKey& key ); bool eraseLocal( const std::string& key ); bool eraseLocalDrawable( const ResourceKey& key ); bool eraseLocalDrawable( const std::string& key ); + bool eraseLocalAtlas( const ResourceKey& key ); + bool eraseLocalAtlas( const std::string& key ); void clearLocal(); void importCatalog( ResourceCatalogPtr catalog ); diff --git a/include/eepp/graphics/sprite.hpp b/include/eepp/graphics/sprite.hpp index 471b7c507..2e0c6fdbb 100644 --- a/include/eepp/graphics/sprite.hpp +++ b/include/eepp/graphics/sprite.hpp @@ -12,6 +12,7 @@ using namespace EE::System; namespace EE { namespace Graphics { class Sprite; +class ResourceScope; using SpritePtr = ResourcePtr; /** @brief A Sprite controller class, can hold and control sprites animations. */ @@ -32,13 +33,17 @@ class EE_API Sprite : public Drawable { static SpritePtr New(); static SpritePtr New( const std::string& name, const std::string& extension = "", - TextureAtlas* SearchInTextureAtlas = NULL ); + TextureAtlas* SearchInTextureAtlas = NULL ); + + static SpritePtr New( ResourceScope& resourceScope, const std::string& name, + const std::string& extension = "", + TextureAtlas* SearchInTextureAtlas = NULL ); static SpritePtr New( TextureRegion* TextureRegion ); static SpritePtr New( ResourceId textureId, const Sizef& DestSize = Sizef( 0, 0 ), - const Vector2i& offset = Vector2i( 0, 0 ), - const Rect& TexSector = Rect( 0, 0, 0, 0 ) ); + const Vector2i& offset = Vector2i( 0, 0 ), + const Rect& TexSector = Rect( 0, 0, 0, 0 ) ); static SpritePtr fromGif( IOStream& gif ); @@ -56,11 +61,14 @@ class EE_API Sprite : public Drawable { * @param SearchInTextureAtlas If you want only to search in a especific atlas ( NULL if you * want to search in all atlases ) * @note Texture atlases saves the TextureRegions names without extension by default. - * @see TextureAtlasManager::GetTextureRegionsByPattern + * @see ResourceScope::findTextureRegionsByPattern */ Sprite( const std::string& name, const std::string& extension = "", TextureAtlas* SearchInTextureAtlas = NULL ); + Sprite( ResourceScope& resourceScope, const std::string& name, + const std::string& extension = "", TextureAtlas* SearchInTextureAtlas = NULL ); + /** Creates a Sprite from a TextureRegion ** @param TextureRegion The TextureRegion to use */ Sprite( TextureRegion* TextureRegion ); @@ -258,13 +266,21 @@ class EE_API Sprite : public Drawable { */ bool addFrames( const std::vector TextureRegions ); - /** @see TextureAtlasManager::GetTextureRegionsByPattern */ + /** @see ResourceScope::findTextureRegionsByPattern */ bool addFramesByPattern( const std::string& name, const std::string& extension = "", TextureAtlas* SearchInTextureAtlas = NULL ); + bool addFramesByPattern( ResourceScope& resourceScope, const std::string& name, + const std::string& extension = "", + TextureAtlas* SearchInTextureAtlas = NULL ); + bool addFramesByPatternId( const Uint32& TextureRegionId, const std::string& extension, TextureAtlas* SearchInTextureAtlas ); + bool addFramesByPatternId( ResourceScope& resourceScope, const Uint32& TextureRegionId, + const std::string& extension, + TextureAtlas* SearchInTextureAtlas = NULL ); + /** Add a frame on an specific subframe to the sprite * @param tex The texture * @param NumFrame The Frame Number diff --git a/include/eepp/graphics/textureatlas.hpp b/include/eepp/graphics/textureatlas.hpp index 2ca77e2b3..eb1343d84 100644 --- a/include/eepp/graphics/textureatlas.hpp +++ b/include/eepp/graphics/textureatlas.hpp @@ -3,18 +3,21 @@ #include #include -#include -using namespace EE::System; +#include namespace EE { namespace Graphics { +class TextureAtlas; +using TextureAtlasPtr = ResourcePtr; +using TextureAtlasWeakPtr = ResourceWeakPtr; + /** @brief The texture atlas class represents a large image containing a collection of sub-images, * or "atlas" which contains many smaller sub-images. The texture atlas in eepp can represent more * than one texture or image, but the common use should be a image with sub-images. * More information about Texture Atlases: http://en.wikipedia.org/wiki/Texture_atlas */ -class EE_API TextureAtlas : public ResourceManager { +class EE_API TextureAtlas { public: - static TextureAtlas* New( const std::string& name = "" ); + static TextureAtlasPtr New( const std::string& name = "" ); /** Creates a new texture atlas with the given name. */ TextureAtlas( const std::string& name = "" ); @@ -22,21 +25,21 @@ class EE_API TextureAtlas : public ResourceManager { ~TextureAtlas(); /** Adds a TextureRegion to the Texture Atlas */ - TextureRegion* add( TextureRegion* textureRegion ); + TextureRegionPtr add( TextureRegionPtr textureRegion ); /** Creates and add to the texture atlas a TextureRegion from a Texture. It will use the full *Texture as a TextureRegion. * @param textureId The texture identity * @param Name The texture name ( if any ) */ - TextureRegion* add( ResourceId textureId, const std::string& Name = "" ); + TextureRegionPtr add( ResourceId textureId, const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion of the indicated part of the texture. * @param textureId The texture identity * @param SrcRect The texture part that will be used as the TextureRegion. * @param Name The texture name ( if any ) */ - TextureRegion* add( ResourceId textureId, const Rect& SrcRect, const std::string& Name = "" ); + TextureRegionPtr add( ResourceId textureId, const Rect& SrcRect, const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion of the indicated part of the texture. * @param textureId The texture identity @@ -44,8 +47,8 @@ class EE_API TextureAtlas : public ResourceManager { * @param DestSize The destination size that the TextureRegion will have when rendered. * @param Name The texture name ( if any ) */ - TextureRegion* add( ResourceId textureId, const Rect& SrcRect, const Sizef& DestSize, - const std::string& Name = "" ); + TextureRegionPtr add( ResourceId textureId, const Rect& SrcRect, const Sizef& DestSize, + const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion of the indicated part of the texture. * @param textureId The texture identity @@ -55,22 +58,22 @@ class EE_API TextureAtlas : public ResourceManager { *used. * @param Name The texture name ( if any ) */ - TextureRegion* add( ResourceId textureId, const Rect& SrcRect, const Sizef& DestSize, - const Vector2i& Offset, const std::string& Name = "" ); + TextureRegionPtr add( ResourceId textureId, const Rect& SrcRect, const Sizef& DestSize, + const Vector2i& Offset, const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion from a Texture. It will use the full *Texture as a TextureRegion. * @param tex The texture * @param Name The texture name ( if any ) */ - TextureRegion* add( TexturePtr tex, const std::string& Name = "" ); + TextureRegionPtr add( TexturePtr tex, const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion of the indicated part of the texture. * @param tex The texture * @param SrcRect The texture part that will be used as the TextureRegion. * @param Name The texture name ( if any ) */ - TextureRegion* add( TexturePtr tex, const Rect& SrcRect, const std::string& Name = "" ); + TextureRegionPtr add( TexturePtr tex, const Rect& SrcRect, const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion of the indicated part of the texture. * @param tex The texture @@ -78,8 +81,8 @@ class EE_API TextureAtlas : public ResourceManager { * @param DestSize The destination size that the TextureRegion will have when rendered. * @param Name The texture name ( if any ) */ - TextureRegion* add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, - const std::string& Name = "" ); + TextureRegionPtr add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, + const std::string& Name = "" ); /** Creates and add to the texture atlas a TextureRegion of the indicated part of the texture. * @param tex The texture @@ -89,8 +92,19 @@ class EE_API TextureAtlas : public ResourceManager { *used. * @param Name The texture name ( if any ) */ - TextureRegion* add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, - const Vector2i& Offset, const std::string& Name = "" ); + TextureRegionPtr add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, + const Vector2i& Offset, const std::string& Name = "" ); + + TextureRegionPtr getByName( const std::string& name ) const; + TextureRegionPtr getById( const String::HashType& id ) const; + bool remove( const TextureRegionPtr& textureRegion ); + bool removeByName( const std::string& name ); + bool removeById( const String::HashType& id ); + bool exists( const std::string& name ) const; + bool existsId( const String::HashType& id ) const; + void clear(); + void printNames() const; + const UnorderedMap& getResources() const; /** @return The texture atlas name. */ const std::string& getName() const; @@ -108,7 +122,7 @@ class EE_API TextureAtlas : public ResourceManager { const String::HashType& getId() const; /** @return The number of TextureRegions inside the texture atlas. */ - Uint32 getCount(); + Uint32 getCount() const; /** @return The texture that corresponds to the texture atlas. * @param texnum The texture index. A texture atlas can use more than one texture, so it can be @@ -122,7 +136,7 @@ class EE_API TextureAtlas : public ResourceManager { const TexturePtr& getTexture( const Uint32& texnum = 0 ) const; /** @return The number of textures linked to the texture atlas. */ - Uint32 getTexturesCount(); + Uint32 getTexturesCount() const; protected: friend class TextureAtlasLoader; @@ -131,6 +145,8 @@ class EE_API TextureAtlas : public ResourceManager { String::HashType mId; std::string mPath; std::vector mTextures; + mutable System::Mutex mMutex; + UnorderedMap mResources; void setTextures( std::vector textures ); }; diff --git a/include/eepp/graphics/textureatlasloader.hpp b/include/eepp/graphics/textureatlasloader.hpp index de5bd70b7..018432e40 100644 --- a/include/eepp/graphics/textureatlasloader.hpp +++ b/include/eepp/graphics/textureatlasloader.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -13,8 +14,6 @@ namespace EE { namespace Graphics { using namespace Private; -class TextureAtlas; - /** @brief The Texture Atlas Loader loads any previously created Texture Atlas. */ class EE_API TextureAtlasLoader { public: @@ -153,7 +152,7 @@ class EE_API TextureAtlasLoader { Uint32 getTexturesLoadedCount(); /** @return The texture atlas instance pointer ( NULL if the atlas isn't loaded yet ). */ - TextureAtlas* getTextureAtlas() const; + const TextureAtlasPtr& getTextureAtlas() const; /** Sets a load notification callback. */ void setLoadCallback( GLLoadCallback LoadCallback ); @@ -174,7 +173,7 @@ class EE_API TextureAtlasLoader { Pack* mPack; bool mSkipResourceLoad; std::atomic mIsLoading; - TextureAtlas* mTextureAtlas; + TextureAtlasPtr mTextureAtlas; GLLoadCallback mLoadCallback; ResourceScopePtr mResourceScope; std::vector mTexturesLoaded; diff --git a/include/eepp/graphics/textureatlasmanager.hpp b/include/eepp/graphics/textureatlasmanager.hpp deleted file mode 100644 index b35151912..000000000 --- a/include/eepp/graphics/textureatlasmanager.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef EE_GRAPHICSCTEXTUREATLASMANAGER_HPP -#define EE_GRAPHICSCTEXTUREATLASMANAGER_HPP - -#include -#include -#include - -#include -#include -using namespace EE::System; - -namespace EE { namespace Graphics { - -/** @brief The Texture Atlas Manager is a singleton class that manages all the instances of Texture - Atlases instantiated. Releases the Texture Atlases instances automatically. So the user doesn't - need to release any Texture Atlas instance. */ -class EE_API TextureAtlasManager : public ResourceManagerMulti { - SINGLETON_DECLARE_HEADERS( TextureAtlasManager ) - - public: - virtual ~TextureAtlasManager(); - - /** Loads a texture atlas from its path ( the texture atlas binary is expected, not the texture, - * the ".eta" file ). */ - TextureAtlas* loadFromFile( const std::string& TextureAtlasPath ); - - /** Loads a texture atlas from a io stream. */ - TextureAtlas* loadFromStream( IOStream& IOS ); - - /** Loads a texture atlas from memory. */ - TextureAtlas* loadFromMemory( const Uint8* Data, const Uint32& DataSize, - const std::string& TextureAtlasName ); - - /** Loads a texture atlas from a pack file. */ - TextureAtlas* loadFromPack( Pack* Pack, const std::string& FilePackPath ); - - /** It will search for a TextureRegion Name in the texture atlases loaded. - * @return The first TextureRegion found with the given name in any atlas. */ - TextureRegion* getTextureRegionByName( const std::string& Name ); - - /** It will search for a TextureRegion Id in the texture atlases loaded. - * @return The first TextureRegion found with the given id in any atlas. */ - TextureRegion* getTextureRegionById( const String::HashType& Id ); - - /** Search for a pattern name - * For example search for name "car" with extensions "png", i will try to find car00.png - * car01.png car02.png, and so on, it will continue if find something, otherwise it will stop ( - * it will always search at least for car00.png and car01.png ) - * @param name First part of the sub texture name - * @param extension Extension of the sub texture name ( if have one, otherwise is empty ) - * @param SearchInTextureAtlas If you want only to search in a especific atlas ( NULL if you - * want to search in all atlases ) - * @note Texture atlases saves the TextureRegions names without extension by default. - */ - std::vector - getTextureRegionsByPattern( const std::string& name, const std::string& extension = "", - TextureAtlas* SearchInTextureAtlas = NULL ); - - /** Search for a pattern id. - * This will look for the TextureRegion with the id passed, and it will try to find any pattern - *by the TextureRegion name. - * @see GetTextureRegionsByPattern - */ - std::vector - getTextureRegionsByPatternId( const Uint32& TextureRegionId, const std::string& extension = "", - TextureAtlas* SearchInTextureAtlas = NULL ); - - /** Prints all the resources name to the screen. */ - void printResources(); - - /** Sets if the warnings for not finding a resource must be printed in screen. */ - void setPrintWarnings( const bool& warn ); - - /** @return If warnings are being printed. */ - const bool& getPrintWarnings() const; - - protected: - bool mWarnings; - - TextureAtlasManager(); -}; - -}} // namespace EE::Graphics - -#endif diff --git a/include/eepp/graphics/textureregion.hpp b/include/eepp/graphics/textureregion.hpp index 4d13158a7..bca539b11 100644 --- a/include/eepp/graphics/textureregion.hpp +++ b/include/eepp/graphics/textureregion.hpp @@ -10,32 +10,34 @@ namespace EE { namespace Graphics { class TextureRegion; using TextureRegionPtr = ResourcePtr; +using TextureRegionWeakPtr = ResourceWeakPtr; /** @brief A TextureRegion is a part of a texture that represent an sprite.*/ class EE_API TextureRegion : public DrawableResource { public: - static TextureRegion* New(); + static TextureRegionPtr New(); - static TextureRegion* New( ResourceId textureId, const std::string& name = "" ); + static TextureRegionPtr New( ResourceId textureId, const std::string& name = "" ); - static TextureRegion* New( ResourceId textureId, const Rect& srcRect, - const std::string& name = "" ); + static TextureRegionPtr New( ResourceId textureId, const Rect& srcRect, + const std::string& name = "" ); - static TextureRegion* New( ResourceId textureId, const Rect& srcRect, const Sizef& destSize, - const std::string& name = "" ); + static TextureRegionPtr New( ResourceId textureId, const Rect& srcRect, const Sizef& destSize, + const std::string& name = "" ); - static TextureRegion* New( ResourceId textureId, const Rect& srcRect, const Sizef& destSize, - const Vector2i& offset, const std::string& name = "" ); + static TextureRegionPtr New( ResourceId textureId, const Rect& srcRect, const Sizef& destSize, + const Vector2i& offset, const std::string& name = "" ); - static TextureRegion* New( TexturePtr tex, const std::string& name = "" ); + static TextureRegionPtr New( TexturePtr tex, const std::string& name = "" ); - static TextureRegion* New( TexturePtr tex, const Rect& srcRect, const std::string& name = "" ); + static TextureRegionPtr New( TexturePtr tex, const Rect& srcRect, + const std::string& name = "" ); - static TextureRegion* New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, - const std::string& name = "" ); + static TextureRegionPtr New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, + const std::string& name = "" ); - static TextureRegion* New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, - const Vector2i& offset, const std::string& name = "" ); + static TextureRegionPtr New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, + const Vector2i& offset, const std::string& name = "" ); /** Creates an empty TextureRegion */ TextureRegion(); diff --git a/include/eepp/ui/tools/textureatlaseditor.hpp b/include/eepp/ui/tools/textureatlaseditor.hpp index 4b151abbc..9e7cb7f41 100644 --- a/include/eepp/ui/tools/textureatlaseditor.hpp +++ b/include/eepp/ui/tools/textureatlaseditor.hpp @@ -2,7 +2,6 @@ #define EE_UITOOLSCTEXTUREATLASEDITOR_HPP #include -#include #include #include #include diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 8910452bf..78de61ebf 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -941,6 +941,7 @@ class EE_API UISceneNode : public SceneNode { UnorderedSet mDirtyStyle; UnorderedSet mDirtyStyleState; UnorderedMap mDirtyStyleStateCSSAnimations; + SmallVector, 64> mDirtyStyleStateSnapshot; UnorderedSet mDirtyLayouts; SmallVector mDirtyLayoutsSnapshot; std::vector> mTimes; diff --git a/include/eepp/ui/uitheme.hpp b/include/eepp/ui/uitheme.hpp index 87df234c6..97680db64 100644 --- a/include/eepp/ui/uitheme.hpp +++ b/include/eepp/ui/uitheme.hpp @@ -40,10 +40,9 @@ class EE_API UITheme : protected ResourceManagerMulti { Graphics::Font* defaultFont, const std::string& styleSheetString ); - static UITheme* loadFromTextureAtlas( UITheme* tTheme, - Graphics::TextureAtlas* getTextureAtlas ); + static UITheme* loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlasPtr textureAtlas ); - static UITheme* loadFromTextureAtlas( Graphics::TextureAtlas* getTextureAtlas, + static UITheme* loadFromTextureAtlas( Graphics::TextureAtlasPtr textureAtlas, const std::string& Name, const std::string& NameAbbr ); static UITheme* loadFromDirectory( UITheme* tTheme, const std::string& Path, @@ -100,7 +99,7 @@ class EE_API UITheme : protected ResourceManagerMulti { std::string mName; String::HashType mNameHash; std::string mAbbr; - Graphics::TextureAtlas* mTextureAtlas; + Graphics::TextureAtlasPtr mTextureAtlas; Font* mDefaultFont; Float mDefaultFontSize; CSS::StyleSheet mStyleSheet; @@ -108,7 +107,7 @@ class EE_API UITheme : protected ResourceManagerMulti { UIIconTheme* mIconTheme; Graphics::ResourceCatalogPtr mResourceCatalog; - void setTextureAtlas( Graphics::TextureAtlas* SG ); + void setTextureAtlas( Graphics::TextureAtlasPtr textureAtlas ); UITheme( const std::string& name, const std::string& abbr, Graphics::Font* defaultFont = NULL ); }; diff --git a/src/eepp/graphics/globaltextureatlas.cpp b/src/eepp/graphics/globaltextureatlas.cpp deleted file mode 100644 index 94f63ee7e..000000000 --- a/src/eepp/graphics/globaltextureatlas.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -namespace EE { namespace Graphics { - -SINGLETON_DECLARE_IMPLEMENTATION( GlobalTextureAtlas ) - -GlobalTextureAtlas::GlobalTextureAtlas() : TextureAtlas( "global" ) {} - -GlobalTextureAtlas::~GlobalTextureAtlas() {} - -}} // namespace EE::Graphics diff --git a/src/eepp/graphics/resourcecatalog.cpp b/src/eepp/graphics/resourcecatalog.cpp index c36d1ab55..1868aa2cf 100644 --- a/src/eepp/graphics/resourcecatalog.cpp +++ b/src/eepp/graphics/resourcecatalog.cpp @@ -53,21 +53,51 @@ void ResourceCatalog::publishDrawable( std::string key, DrawablePtr drawable ) { } DrawablePtr previous; + String::HashType id = String::hash( key ); { Lock lock( mMutex ); auto it = mDrawables.find( key ); if ( it == mDrawables.end() ) { - mDrawables.emplace( std::move( key ), std::move( drawable ) ); + mDrawables.emplace( std::move( key ), drawable ); + mDrawablesById[id] = drawable; return; } previous = std::move( it->second ); - it->second = std::move( drawable ); + it->second = drawable; + mDrawablesById[id] = drawable; } previous.reset(); } +void ResourceCatalog::publishAtlas( ResourceKey key, TextureAtlasPtr atlas ) { + publishAtlas( key.value(), std::move( atlas ) ); +} + +void ResourceCatalog::publishAtlas( std::string key, TextureAtlasPtr atlas ) { + if ( key.empty() ) + return; + + if ( !atlas ) { + eraseAtlas( key ); + return; + } + + TextureAtlasPtr previous; + { + Lock lock( mMutex ); + auto it = mAtlases.find( key ); + if ( it == mAtlases.end() ) { + mAtlases.emplace( std::move( key ), std::move( atlas ) ); + return; + } + previous = std::move( it->second ); + it->second = std::move( atlas ); + } + previous.reset(); +} + TexturePtr ResourceCatalog::findTexture( const ResourceKey& key ) const { return findTexture( key.value() ); } @@ -88,6 +118,31 @@ DrawablePtr ResourceCatalog::findDrawable( const std::string& key ) const { return it != mDrawables.end() ? it->second : DrawablePtr{}; } +DrawablePtr ResourceCatalog::findDrawable( const String::HashType& id ) const { + Lock lock( mMutex ); + auto it = mDrawablesById.find( id ); + return it != mDrawablesById.end() ? it->second.lock() : DrawablePtr{}; +} + +TextureAtlasPtr ResourceCatalog::findAtlas( const ResourceKey& key ) const { + return findAtlas( key.value() ); +} + +TextureAtlasPtr ResourceCatalog::findAtlas( const std::string& key ) const { + Lock lock( mMutex ); + auto it = mAtlases.find( key ); + return it != mAtlases.end() ? it->second : TextureAtlasPtr{}; +} + +std::vector ResourceCatalog::getAtlases() const { + std::vector atlases; + Lock lock( mMutex ); + atlases.reserve( mAtlases.size() ); + for ( const auto& atlas : mAtlases ) + atlases.emplace_back( atlas.second ); + return atlases; +} + bool ResourceCatalog::erase( const ResourceKey& key ) { return erase( key.value() ); } @@ -122,28 +177,55 @@ bool ResourceCatalog::eraseDrawable( const std::string& key ) { drawable = std::move( it->second ); mDrawables.erase( it ); + auto idIt = mDrawablesById.find( String::hash( key ) ); + if ( idIt != mDrawablesById.end() ) + mDrawablesById.erase( idIt ); } drawable.reset(); return true; } +bool ResourceCatalog::eraseAtlas( const ResourceKey& key ) { + return eraseAtlas( key.value() ); +} + +bool ResourceCatalog::eraseAtlas( const std::string& key ) { + TextureAtlasPtr atlas; + { + Lock lock( mMutex ); + auto it = mAtlases.find( key ); + if ( it == mAtlases.end() ) + return false; + atlas = std::move( it->second ); + mAtlases.erase( it ); + } + atlas.reset(); + return true; +} + void ResourceCatalog::clear() { UnorderedMap textures; UnorderedMap drawables; + UnorderedMap drawablesById; + UnorderedMap atlases; { Lock lock( mMutex ); textures = std::move( mTextures ); drawables = std::move( mDrawables ); + drawablesById = std::move( mDrawablesById ); + atlases = std::move( mAtlases ); } textures.clear(); drawables.clear(); + drawablesById.clear(); + atlases.clear(); } std::size_t ResourceCatalog::size() const { Lock lock( mMutex ); - return mTextures.size() + mDrawables.size(); + return mTextures.size() + mDrawables.size() + mAtlases.size(); } }} // namespace EE::Graphics diff --git a/src/eepp/graphics/resourcescope.cpp b/src/eepp/graphics/resourcescope.cpp index 8ef9b05e9..2501b8c8b 100644 --- a/src/eepp/graphics/resourcescope.cpp +++ b/src/eepp/graphics/resourcescope.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include @@ -49,18 +49,110 @@ DrawablePtr ResourceScope::findDrawableSource( const std::string& key ) const { return {}; } +TextureAtlasPtr ResourceScope::findAtlas( const ResourceKey& key ) const { + return findAtlas( key.value() ); +} + +TextureAtlasPtr ResourceScope::findAtlas( const std::string& key ) const { + if ( TextureAtlasPtr atlas = mLocalCatalog->findAtlas( key ) ) + return atlas; + + Lock lock( mMutex ); + for ( const ResourceCatalogPtr& catalog : mImports ) { + if ( TextureAtlasPtr atlas = catalog->findAtlas( key ) ) + return atlas; + } + return {}; +} + +std::vector ResourceScope::getAtlases() const { + std::vector atlases = mLocalCatalog->getAtlases(); + Lock lock( mMutex ); + for ( const ResourceCatalogPtr& catalog : mImports ) { + std::vector imported = catalog->getAtlases(); + atlases.insert( atlases.end(), imported.begin(), imported.end() ); + } + return atlases; +} + +std::vector +ResourceScope::findTextureRegionsByPattern( const std::string& name, const std::string& extension, + TextureAtlas* searchInTextureAtlas ) const { + std::vector regions; + std::string suffix = extension.empty() ? "" : "." + extension; + int padding = 0; + + auto findRegion = [&]( const std::string& key ) -> TextureRegionPtr { + DrawablePtr drawable = searchInTextureAtlas ? searchInTextureAtlas->getByName( key ) + : findDrawableSource( key ); + return drawable && drawable->getDrawableType() == Drawable::TEXTUREREGION + ? std::static_pointer_cast( drawable ) + : TextureRegionPtr{}; + }; + + for ( int len = 1; len < 7 && padding == 0; ++len ) { + for ( int i = 0; i < 2; ++i ) { + std::string format( "%s%0" + String::toString( len ) + "d%s" ); + if ( findRegion( String::format( format.c_str(), name.c_str(), i, suffix.c_str() ) ) ) { + padding = len; + break; + } + } + } + + if ( padding == 0 ) + return regions; + + for ( int i = 0;; ++i ) { + std::string format( "%s%0" + String::toString( padding ) + "d%s" ); + TextureRegionPtr region = + findRegion( String::format( format.c_str(), name.c_str(), i, suffix.c_str() ) ); + if ( region ) { + regions.emplace_back( std::move( region ) ); + } else if ( i != 0 ) { + break; + } + } + return regions; +} + +std::vector +ResourceScope::findTextureRegionsByPatternId( const String::HashType& id, + const std::string& extension, + TextureAtlas* searchInTextureAtlas ) const { + DrawablePtr drawable; + if ( searchInTextureAtlas ) { + drawable = searchInTextureAtlas->getById( id ); + } else { + drawable = mLocalCatalog->findDrawable( id ); + if ( !drawable ) { + Lock lock( mMutex ); + for ( const ResourceCatalogPtr& catalog : mImports ) { + if ( ( drawable = catalog->findDrawable( id ) ) ) + break; + } + } + } + + if ( !drawable || drawable->getDrawableType() != Drawable::TEXTUREREGION ) + return {}; + std::string name = String::removeNumbersAtEnd( FileSystem::fileRemoveExtension( + static_cast( drawable.get() )->getName() ) ); + return findTextureRegionsByPattern( name, extension, searchInTextureAtlas ); +} + DrawablePtr ResourceScope::findDrawable( const std::string& name, bool firstSearchSprite ) const { if ( name.empty() ) return {}; - auto findSprite = []( const std::string& pattern ) -> DrawablePtr { - std::vector textureRegions = - TextureAtlasManager::instance()->getTextureRegionsByPattern( pattern ); + auto findSprite = [this]( const std::string& pattern ) -> DrawablePtr { + std::vector textureRegions = findTextureRegionsByPattern( pattern ); if ( textureRegions.empty() ) return {}; SpritePtr sprite = Sprite::New(); sprite->createAnimation(); - sprite->addFrames( textureRegions ); + for ( const TextureRegionPtr& textureRegion : textureRegions ) + sprite->addFrame( textureRegion.get() ); return sprite; }; @@ -75,8 +167,7 @@ DrawablePtr ResourceScope::findDrawable( const std::string& name, bool firstSear if ( name[0] == '@' ) { if ( String::startsWith( name, "@textureregion/" ) ) { - Drawable* source = - TextureAtlasManager::instance()->getTextureRegionByName( name.substr( 12 ) ); + DrawablePtr source = findDrawableSource( name.substr( 12 ) ); return source ? source->clone() : DrawablePtr{}; } if ( String::startsWith( name, "@image/" ) ) { @@ -101,17 +192,19 @@ DrawablePtr ResourceScope::findDrawable( const std::string& name, bool firstSear if ( DrawablePtr source = findDrawableSource( name ) ) return source->clone(); - String::HashType id = String::hash( name ); - Drawable* source = TextureAtlasManager::instance()->getTextureRegionById( id ); - if ( source ) - return source->clone(); - TexturePtr texture = findTexture( name ); return texture ? texture->clone() : DrawablePtr{}; } DrawablePtr ResourceScope::findDrawable( const Uint32& id ) const { - Drawable* source = TextureAtlasManager::instance()->getTextureRegionById( id ); + DrawablePtr source = mLocalCatalog->findDrawable( id ); + if ( !source ) { + Lock lock( mMutex ); + for ( const ResourceCatalogPtr& catalog : mImports ) { + if ( ( source = catalog->findDrawable( id ) ) ) + break; + } + } return source ? source->clone() : DrawablePtr{}; } @@ -131,6 +224,14 @@ void ResourceScope::publishLocalDrawable( std::string key, DrawablePtr drawable mLocalCatalog->publishDrawable( std::move( key ), std::move( drawable ) ); } +void ResourceScope::publishLocalAtlas( ResourceKey key, TextureAtlasPtr atlas ) { + publishLocalAtlas( key.value(), std::move( atlas ) ); +} + +void ResourceScope::publishLocalAtlas( std::string key, TextureAtlasPtr atlas ) { + mLocalCatalog->publishAtlas( std::move( key ), std::move( atlas ) ); +} + bool ResourceScope::eraseLocal( const ResourceKey& key ) { return mLocalCatalog->erase( key ); } @@ -147,6 +248,14 @@ bool ResourceScope::eraseLocalDrawable( const std::string& key ) { return mLocalCatalog->eraseDrawable( key ); } +bool ResourceScope::eraseLocalAtlas( const ResourceKey& key ) { + return mLocalCatalog->eraseAtlas( key ); +} + +bool ResourceScope::eraseLocalAtlas( const std::string& key ) { + return mLocalCatalog->eraseAtlas( key ); +} + void ResourceScope::clearLocal() { mLocalCatalog->clear(); } diff --git a/src/eepp/graphics/sprite.cpp b/src/eepp/graphics/sprite.cpp index 9f0bebf4b..947adff6f 100644 --- a/src/eepp/graphics/sprite.cpp +++ b/src/eepp/graphics/sprite.cpp @@ -1,6 +1,5 @@ -#include +#include #include -#include #include #include @@ -19,6 +18,11 @@ SpritePtr Sprite::New( const std::string& name, const std::string& extension, return makeResource( name, extension, SearchInTextureAtlas ); } +SpritePtr Sprite::New( ResourceScope& resourceScope, const std::string& name, + const std::string& extension, TextureAtlas* SearchInTextureAtlas ) { + return makeResource( resourceScope, name, extension, SearchInTextureAtlas ); +} + SpritePtr Sprite::New( TextureRegion* TextureRegion ) { return makeResource( TextureRegion ); } @@ -51,6 +55,12 @@ Sprite::Sprite( const std::string& name, const std::string& extension, addFramesByPattern( name, extension, SearchInTextureAtlas ); } +Sprite::Sprite( ResourceScope& resourceScope, const std::string& name, const std::string& extension, + TextureAtlas* SearchInTextureAtlas ) : + Drawable( Drawable::SPRITE ) { + addFramesByPattern( resourceScope, name, extension, SearchInTextureAtlas ); +} + Sprite::Sprite( TextureRegion* TextureRegion ) : Drawable( Drawable::SPRITE ) { createStatic( TextureRegion ); } @@ -77,8 +87,7 @@ Sprite& Sprite::operator=( const Sprite& Other ) { frame.Spr.reserve( otherFrame.Spr.size() ); for ( const TextureRegionPtr& region : otherFrame.Spr ) { frame.Spr.emplace_back( - region ? std::static_pointer_cast( region->clone() ) - : nullptr ); + region ? std::static_pointer_cast( region->clone() ) : nullptr ); } mFrames.emplace_back( std::move( frame ) ); } @@ -345,12 +354,19 @@ bool Sprite::addFrames( const std::vector TextureRegions ) { bool Sprite::addFramesByPatternId( const Uint32& TextureRegionId, const std::string& extension, TextureAtlas* SearchInTextureAtlas ) { - std::vector TextureRegions = - TextureAtlasManager::instance()->getTextureRegionsByPatternId( TextureRegionId, extension, - SearchInTextureAtlas ); + return addFramesByPatternId( defaultResourceScope(), TextureRegionId, extension, + SearchInTextureAtlas ); +} + +bool Sprite::addFramesByPatternId( ResourceScope& resourceScope, const Uint32& TextureRegionId, + const std::string& extension, + TextureAtlas* SearchInTextureAtlas ) { + std::vector TextureRegions = resourceScope.findTextureRegionsByPatternId( + TextureRegionId, extension, SearchInTextureAtlas ); if ( TextureRegions.size() ) { - addFrames( TextureRegions ); + for ( const TextureRegionPtr& textureRegion : TextureRegions ) + addFrame( textureRegion.get() ); return true; } @@ -363,12 +379,18 @@ bool Sprite::addFramesByPatternId( const Uint32& TextureRegionId, const std::str bool Sprite::addFramesByPattern( const std::string& name, const std::string& extension, TextureAtlas* SearchInTextureAtlas ) { - std::vector TextureRegions = - TextureAtlasManager::instance()->getTextureRegionsByPattern( name, extension, - SearchInTextureAtlas ); + return addFramesByPattern( defaultResourceScope(), name, extension, SearchInTextureAtlas ); +} + +bool Sprite::addFramesByPattern( ResourceScope& resourceScope, const std::string& name, + const std::string& extension, + TextureAtlas* SearchInTextureAtlas ) { + std::vector TextureRegions = + resourceScope.findTextureRegionsByPattern( name, extension, SearchInTextureAtlas ); if ( TextureRegions.size() ) { - addFrames( TextureRegions ); + for ( const TextureRegionPtr& textureRegion : TextureRegions ) + addFrame( textureRegion.get() ); return true; } @@ -380,10 +402,10 @@ bool Sprite::addFramesByPattern( const std::string& name, const std::string& ext bool Sprite::addSubFrame( TextureRegion* TextureRegion, const unsigned int& NumFrame, const unsigned int& NumSubFrame ) { - return addSubFrame( TextureRegion ? std::static_pointer_cast( - TextureRegion->clone() ) - : TextureRegionPtr{}, - NumFrame, NumSubFrame ); + return addSubFrame( + TextureRegion ? std::static_pointer_cast( TextureRegion->clone() ) + : TextureRegionPtr{}, + NumFrame, NumSubFrame ); } bool Sprite::addSubFrame( TextureRegionPtr TextureRegion, const unsigned int& NumFrame, diff --git a/src/eepp/graphics/textureatlas.cpp b/src/eepp/graphics/textureatlas.cpp index 7605b3dd4..843b8fa40 100644 --- a/src/eepp/graphics/textureatlas.cpp +++ b/src/eepp/graphics/textureatlas.cpp @@ -1,12 +1,15 @@ #include +#include + +using namespace EE::System; namespace EE { namespace Graphics { -TextureAtlas* TextureAtlas::New( const std::string& name ) { - return eeNew( TextureAtlas, ( name ) ); +TextureAtlasPtr TextureAtlas::New( const std::string& name ) { + return makeResource( name ); } -TextureAtlas::TextureAtlas( const std::string& name ) : ResourceManager() { +TextureAtlas::TextureAtlas( const std::string& name ) { setName( name ); } @@ -33,49 +36,127 @@ const String::HashType& TextureAtlas::getId() const { return mId; } -TextureRegion* TextureAtlas::add( TextureRegion* textureRegion ) { - return ResourceManager::add( textureRegion ); +TextureRegionPtr TextureAtlas::add( TextureRegionPtr textureRegion ) { + if ( !textureRegion ) + return {}; + + std::string realName( textureRegion->getName() ); + Uint32 count = 1; + for ( ;; ) { + { + Lock lock( mMutex ); + if ( mResources.find( textureRegion->getId() ) == mResources.end() ) { + mResources[textureRegion->getId()] = textureRegion; + return textureRegion; + } + } + + // setName() can notify listeners. Never invoke callbacks while holding the atlas mutex. + textureRegion->setName( realName + String::toString( ++count ) ); + } } -TextureRegion* TextureAtlas::add( ResourceId textureId, const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( ResourceId textureId, const std::string& Name ) { return add( TextureRegion::New( textureId, Name ) ); } -TextureRegion* TextureAtlas::add( ResourceId textureId, const Rect& SrcRect, - const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( ResourceId textureId, const Rect& SrcRect, + const std::string& Name ) { return add( TextureRegion::New( textureId, SrcRect, Name ) ); } -TextureRegion* TextureAtlas::add( ResourceId textureId, const Rect& SrcRect, const Sizef& DestSize, - const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( ResourceId textureId, const Rect& SrcRect, + const Sizef& DestSize, const std::string& Name ) { return add( TextureRegion::New( textureId, SrcRect, DestSize, Name ) ); } -TextureRegion* TextureAtlas::add( ResourceId textureId, const Rect& SrcRect, const Sizef& DestSize, - const Vector2i& Offset, const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( ResourceId textureId, const Rect& SrcRect, + const Sizef& DestSize, const Vector2i& Offset, + const std::string& Name ) { return add( TextureRegion::New( textureId, SrcRect, DestSize, Offset, Name ) ); } -TextureRegion* TextureAtlas::add( TexturePtr tex, const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( TexturePtr tex, const std::string& Name ) { return add( TextureRegion::New( std::move( tex ), Name ) ); } -TextureRegion* TextureAtlas::add( TexturePtr tex, const Rect& SrcRect, const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( TexturePtr tex, const Rect& SrcRect, const std::string& Name ) { return add( TextureRegion::New( std::move( tex ), SrcRect, Name ) ); } -TextureRegion* TextureAtlas::add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, - const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, + const std::string& Name ) { return add( TextureRegion::New( std::move( tex ), SrcRect, DestSize, Name ) ); } -TextureRegion* TextureAtlas::add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, - const Vector2i& Offset, const std::string& Name ) { +TextureRegionPtr TextureAtlas::add( TexturePtr tex, const Rect& SrcRect, const Sizef& DestSize, + const Vector2i& Offset, const std::string& Name ) { return add( TextureRegion::New( std::move( tex ), SrcRect, DestSize, Offset, Name ) ); } -Uint32 TextureAtlas::getCount() { - return ResourceManager::getCount(); +TextureRegionPtr TextureAtlas::getByName( const std::string& name ) const { + return getById( String::hash( name ) ); +} + +TextureRegionPtr TextureAtlas::getById( const String::HashType& id ) const { + Lock lock( mMutex ); + auto it = mResources.find( id ); + return it != mResources.end() ? it->second : TextureRegionPtr{}; +} + +bool TextureAtlas::remove( const TextureRegionPtr& textureRegion ) { + return textureRegion && removeById( textureRegion->getId() ); +} + +bool TextureAtlas::removeByName( const std::string& name ) { + return removeById( String::hash( name ) ); +} + +bool TextureAtlas::removeById( const String::HashType& id ) { + TextureRegionPtr textureRegion; + { + Lock lock( mMutex ); + auto it = mResources.find( id ); + if ( it == mResources.end() ) + return false; + textureRegion = std::move( it->second ); + mResources.erase( it ); + } + textureRegion.reset(); + return true; +} + +bool TextureAtlas::exists( const std::string& name ) const { + return existsId( String::hash( name ) ); +} + +bool TextureAtlas::existsId( const String::HashType& id ) const { + Lock lock( mMutex ); + return mResources.find( id ) != mResources.end(); +} + +void TextureAtlas::clear() { + UnorderedMap resources; + { + Lock lock( mMutex ); + resources = std::move( mResources ); + } + resources.clear(); +} + +void TextureAtlas::printNames() const { + Lock lock( mMutex ); + for ( const auto& resource : mResources ) + eePRINTL( "'%s'", resource.second->getName().c_str() ); +} + +const UnorderedMap& TextureAtlas::getResources() const { + return mResources; +} + +Uint32 TextureAtlas::getCount() const { + Lock lock( mMutex ); + return static_cast( mResources.size() ); } void TextureAtlas::setTextures( std::vector textures ) { @@ -87,8 +168,8 @@ const TexturePtr& TextureAtlas::getTexture( const Uint32& texnum ) const { return mTextures[texnum]; } -Uint32 TextureAtlas::getTexturesCount() { - return mTextures.size(); +Uint32 TextureAtlas::getTexturesCount() const { + return static_cast( mTextures.size() ); } }} // namespace EE::Graphics diff --git a/src/eepp/graphics/textureatlasloader.cpp b/src/eepp/graphics/textureatlasloader.cpp index 4c6db9f44..c6d69a5c4 100644 --- a/src/eepp/graphics/textureatlasloader.cpp +++ b/src/eepp/graphics/textureatlasloader.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,7 @@ TextureAtlasLoader::TextureAtlasLoader() : mPack( NULL ), mSkipResourceLoad( false ), mIsLoading( false ), - mTextureAtlas( NULL ) {} + mTextureAtlas() {} TextureAtlasLoader::TextureAtlasLoader( const std::string& TextureAtlasPath, const bool& Threaded, GLLoadCallback LoadCallback ) : @@ -61,7 +60,7 @@ TextureAtlasLoader::TextureAtlasLoader( const std::string& TextureAtlasPath, con mPack( NULL ), mSkipResourceLoad( false ), mIsLoading( false ), - mTextureAtlas( NULL ), + mTextureAtlas(), mLoadCallback( LoadCallback ) { loadFromFile(); } @@ -75,7 +74,7 @@ TextureAtlasLoader::TextureAtlasLoader( const Uint8* Data, const Uint32& DataSiz mPack( NULL ), mSkipResourceLoad( false ), mIsLoading( false ), - mTextureAtlas( NULL ), + mTextureAtlas(), mLoadCallback( LoadCallback ) { loadFromMemory( Data, DataSize, TextureAtlasName ); } @@ -88,7 +87,7 @@ TextureAtlasLoader::TextureAtlasLoader( Pack* Pack, const std::string& FilePackP mPack( NULL ), mSkipResourceLoad( false ), mIsLoading( false ), - mTextureAtlas( NULL ), + mTextureAtlas(), mLoadCallback( LoadCallback ) { loadFromPack( Pack, FilePackPath ); } @@ -100,7 +99,7 @@ TextureAtlasLoader::TextureAtlasLoader( IOStream& IOS, const bool& Threaded, mPack( NULL ), mSkipResourceLoad( false ), mIsLoading( false ), - mTextureAtlas( NULL ), + mTextureAtlas(), mLoadCallback( LoadCallback ) { loadFromStream( IOS ); } @@ -242,7 +241,7 @@ void TextureAtlasLoader::loadFromMemory( const Uint8* Data, const Uint32& DataSi loadFromStream( IOS ); } -TextureAtlas* TextureAtlasLoader::getTextureAtlas() const { +const TextureAtlasPtr& TextureAtlasLoader::getTextureAtlas() const { return mTextureAtlas; } @@ -273,7 +272,7 @@ void TextureAtlasLoader::createTextureRegions() { std::string etapath = FileSystem::fileRemoveExtension( path ) + EE_TEXTURE_ATLAS_EXTENSION; - TextureAtlas* tTextureAtlas = TextureAtlasManager::instance()->getByName( name ); + TextureAtlasPtr tTextureAtlas = mResourceScope->findAtlas( name ); if ( NULL != tTextureAtlas && tTextureAtlas->getPath() == etapath ) { mTextureAtlas = tTextureAtlas; @@ -284,7 +283,7 @@ void TextureAtlasLoader::createTextureRegions() { mTextureAtlas->setPath( etapath ); - TextureAtlasManager::instance()->add( mTextureAtlas ); + mResourceScope->publishLocalAtlas( name, mTextureAtlas ); } } @@ -300,7 +299,7 @@ void TextureAtlasLoader::createTextureRegions() { Rect tRect( tSh->X, tSh->Y, tSh->X + tSh->Width, tSh->Y + tSh->Height ); - TextureRegion* tTextureRegion = TextureRegion::New( + TextureRegionPtr tTextureRegion = TextureRegion::New( tTex->getTextureId(), tRect, Sizef( (Float)tSh->DestWidth, (Float)tSh->DestHeight ), Vector2i( tSh->OffsetX, tSh->OffsetY ), TextureRegionName ); @@ -309,7 +308,8 @@ void TextureAtlasLoader::createTextureRegions() { // if ( tSh->Flags & HDR_TEXTUREREGION_FLAG_FLIPPED ) // Should rotate the sub texture, but.. sub texture rotation is not stored. - mTextureAtlas->add( tTextureRegion ); + tTextureRegion = mTextureAtlas->add( std::move( tTextureRegion ) ); + mResourceScope->publishLocalDrawable( TextureRegionName, tTextureRegion ); } } } else { @@ -373,7 +373,7 @@ bool TextureAtlasLoader::updateTextureAtlas() { for ( Int32 i = 0; i < tTexHdr->TextureRegionCount; i++ ) { sTextureRegionHdr* tSh = &tTexAtlas->TextureRegions[i]; - TextureRegion* tTextureRegion = mTextureAtlas->getById( tSh->ResourceID ); + TextureRegionPtr tTextureRegion = mTextureAtlas->getById( tSh->ResourceID ); if ( NULL != tTextureRegion ) { tSh->OffsetX = tTextureRegion->getOffset().x; diff --git a/src/eepp/graphics/textureatlasmanager.cpp b/src/eepp/graphics/textureatlasmanager.cpp deleted file mode 100644 index 9f35f63e3..000000000 --- a/src/eepp/graphics/textureatlasmanager.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include -#include -#include -#include - -namespace EE { namespace Graphics { - -SINGLETON_DECLARE_IMPLEMENTATION( TextureAtlasManager ) - -TextureAtlasManager::TextureAtlasManager() : - ResourceManagerMulti(), mWarnings( false ) { - add( GlobalTextureAtlas::instance() ); -} - -TextureAtlasManager::~TextureAtlasManager() { - GlobalTextureAtlas::detachSingleton(); -} - -TextureAtlas* TextureAtlasManager::loadFromFile( const std::string& TextureAtlasPath ) { - TextureAtlasLoader loader( TextureAtlasPath ); - - return loader.getTextureAtlas(); -} - -TextureAtlas* TextureAtlasManager::loadFromStream( IOStream& IOS ) { - TextureAtlasLoader loader( IOS ); - - return loader.getTextureAtlas(); -} - -TextureAtlas* TextureAtlasManager::loadFromMemory( const Uint8* Data, const Uint32& DataSize, - const std::string& TextureAtlasName ) { - TextureAtlasLoader loader( Data, DataSize, TextureAtlasName ); - - return loader.getTextureAtlas(); -} - -TextureAtlas* TextureAtlasManager::loadFromPack( Pack* Pack, const std::string& FilePackPath ) { - TextureAtlasLoader loader( Pack, FilePackPath ); - - return loader.getTextureAtlas(); -} - -TextureRegion* TextureAtlasManager::getTextureRegionByName( const std::string& Name ) { - TextureRegion* tTextureRegion = getTextureRegionById( String::hash( Name ) ); - - if ( mWarnings ) { - eePRINTC( NULL == tTextureRegion, - "TextureAtlasManager::getTextureRegionByName TextureRegion '%s' not found\n", - Name.c_str() ); - } - - return tTextureRegion; -} - -TextureRegion* TextureAtlasManager::getTextureRegionById( const String::HashType& Id ) { - TextureAtlas* tSG = NULL; - TextureRegion* tTextureRegion = NULL; - - for ( auto& it : mResources ) { - tSG = it.second; - - tTextureRegion = tSG->getById( Id ); - - if ( NULL != tTextureRegion ) - return tTextureRegion; - } - - return NULL; -} - -void TextureAtlasManager::printResources() { - for ( auto& it : mResources ) - it.second->printNames(); -} - -std::vector -TextureAtlasManager::getTextureRegionsByPatternId( const Uint32& TextureRegionId, - const std::string& extension, - TextureAtlas* SearchInTextureAtlas ) { - TextureRegion* tTextureRegion = NULL; - std::string tName; - - if ( NULL == SearchInTextureAtlas ) - tTextureRegion = getTextureRegionById( TextureRegionId ); - else - tTextureRegion = SearchInTextureAtlas->getById( TextureRegionId ); - - if ( NULL != tTextureRegion ) { - if ( extension.size() ) - tName = String::removeNumbersAtEnd( - FileSystem::fileRemoveExtension( tTextureRegion->getName() ) ) + - extension; - else - tName = tTextureRegion->getName(); - - return getTextureRegionsByPattern( String::removeNumbersAtEnd( tTextureRegion->getName() ), - "", SearchInTextureAtlas ); - } - - return std::vector(); -} - -void TextureAtlasManager::setPrintWarnings( const bool& warn ) { - mWarnings = warn; -} - -const bool& TextureAtlasManager::getPrintWarnings() const { - return mWarnings; -} - -std::vector TextureAtlasManager::getTextureRegionsByPattern( - const std::string& name, const std::string& extension, TextureAtlas* SearchInTextureAtlas ) { - std::vector TextureRegions; - std::string search; - bool found = true; - TextureRegion* tTextureRegion = NULL; - std::string realext = ""; - int c = 0; - int numPadding = 0; - int i; - - if ( extension.size() ) - realext = "." + extension; - - for ( int len = 1; len < 7; len++ ) { - for ( i = 0; i < 2; i++ ) { - std::string formatStr( "%s%0" + String::toString( len ) + "d%s" ); - search = String::format( formatStr.c_str(), name.c_str(), i, realext.c_str() ); - - if ( NULL == SearchInTextureAtlas ) - tTextureRegion = getTextureRegionByName( search ); - else - tTextureRegion = SearchInTextureAtlas->getByName( search ); - - if ( NULL != tTextureRegion ) { - numPadding = len; - - break; - } - } - - if ( 0 != numPadding ) { - break; - } - } - - if ( 0 != numPadding ) { - do { - std::string formatStr( "%s%0" + String::toString( numPadding ) + "d%s" ); - search = String::format( formatStr.c_str(), name.c_str(), c, realext.c_str() ); - - if ( NULL == SearchInTextureAtlas ) - tTextureRegion = getTextureRegionByName( search ); - else - tTextureRegion = SearchInTextureAtlas->getByName( search ); - - if ( NULL != tTextureRegion ) { - TextureRegions.push_back( tTextureRegion ); - - found = true; - } else { - if ( 0 == c ) // if didn't found "00", will search at least for "01" - found = true; - else - found = false; - } - - c++; - } while ( found ); - } - - return TextureRegions; -} - -}} // namespace EE::Graphics diff --git a/src/eepp/graphics/textureregion.cpp b/src/eepp/graphics/textureregion.cpp index cee22e335..9e9634b12 100644 --- a/src/eepp/graphics/textureregion.cpp +++ b/src/eepp/graphics/textureregion.cpp @@ -10,48 +10,50 @@ using namespace EE::Graphics::Private; namespace EE { namespace Graphics { -TextureRegion* TextureRegion::New() { - return eeNew( TextureRegion, () ); +TextureRegionPtr TextureRegion::New() { + return makeResource(); } -TextureRegion* TextureRegion::New( ResourceId textureId, const std::string& name ) { - return eeNew( TextureRegion, ( TextureFactory::instance()->getTexture( textureId ), name ) ); +TextureRegionPtr TextureRegion::New( ResourceId textureId, const std::string& name ) { + return makeResource( TextureFactory::instance()->getTexture( textureId ), name ); } -TextureRegion* TextureRegion::New( ResourceId textureId, const Rect& srcRect, - const std::string& name ) { - return eeNew( TextureRegion, - ( TextureFactory::instance()->getTexture( textureId ), srcRect, name ) ); +TextureRegionPtr TextureRegion::New( ResourceId textureId, const Rect& srcRect, + const std::string& name ) { + return makeResource( TextureFactory::instance()->getTexture( textureId ), + srcRect, name ); } -TextureRegion* TextureRegion::New( ResourceId textureId, const Rect& srcRect, const Sizef& destSize, - const std::string& name ) { - return eeNew( TextureRegion, ( TextureFactory::instance()->getTexture( textureId ), srcRect, - destSize, name ) ); +TextureRegionPtr TextureRegion::New( ResourceId textureId, const Rect& srcRect, + const Sizef& destSize, const std::string& name ) { + return makeResource( TextureFactory::instance()->getTexture( textureId ), + srcRect, destSize, name ); } -TextureRegion* TextureRegion::New( ResourceId textureId, const Rect& srcRect, const Sizef& destSize, - const Vector2i& offset, const std::string& name ) { - return eeNew( TextureRegion, ( TextureFactory::instance()->getTexture( textureId ), srcRect, - destSize, offset, name ) ); +TextureRegionPtr TextureRegion::New( ResourceId textureId, const Rect& srcRect, + const Sizef& destSize, const Vector2i& offset, + const std::string& name ) { + return makeResource( TextureFactory::instance()->getTexture( textureId ), + srcRect, destSize, offset, name ); } -TextureRegion* TextureRegion::New( TexturePtr tex, const std::string& name ) { - return eeNew( TextureRegion, ( std::move( tex ), name ) ); +TextureRegionPtr TextureRegion::New( TexturePtr tex, const std::string& name ) { + return makeResource( std::move( tex ), name ); } -TextureRegion* TextureRegion::New( TexturePtr tex, const Rect& srcRect, const std::string& name ) { - return eeNew( TextureRegion, ( std::move( tex ), srcRect, name ) ); +TextureRegionPtr TextureRegion::New( TexturePtr tex, const Rect& srcRect, + const std::string& name ) { + return makeResource( std::move( tex ), srcRect, name ); } -TextureRegion* TextureRegion::New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, - const std::string& name ) { - return eeNew( TextureRegion, ( std::move( tex ), srcRect, destSize, name ) ); +TextureRegionPtr TextureRegion::New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, + const std::string& name ) { + return makeResource( std::move( tex ), srcRect, destSize, name ); } -TextureRegion* TextureRegion::New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, - const Vector2i& offset, const std::string& name ) { - return eeNew( TextureRegion, ( std::move( tex ), srcRect, destSize, offset, name ) ); +TextureRegionPtr TextureRegion::New( TexturePtr tex, const Rect& srcRect, const Sizef& destSize, + const Vector2i& offset, const std::string& name ) { + return makeResource( std::move( tex ), srcRect, destSize, offset, name ); } TextureRegion::TextureRegion() : diff --git a/src/eepp/ui/tools/textureatlaseditor.cpp b/src/eepp/ui/tools/textureatlaseditor.cpp index cb2a2b85a..2bedcab3c 100644 --- a/src/eepp/ui/tools/textureatlaseditor.cpp +++ b/src/eepp/ui/tools/textureatlaseditor.cpp @@ -384,7 +384,7 @@ void TextureAtlasEditor::fillTextureRegionList() { mTextureRegionGrid->closeAllChildren(); for ( auto& it : res ) { - TextureRegion* tr = it.second; + TextureRegion* tr = it.second.get(); UITextureRegion::New() ->setTextureRegion( tr ) @@ -400,11 +400,13 @@ void TextureAtlasEditor::fillTextureRegionList() { void TextureAtlasEditor::onTextureRegionChange( const Event* Event ) { if ( NULL != mTextureAtlasLoader && NULL != mTextureAtlasLoader->getTextureAtlas() ) { - mCurTextureRegion = Event->getNode()->isType( UI_TYPE_TEXTUREREGION ) - ? mTextureAtlasLoader->getTextureAtlas()->getByName( - static_cast( Event->getNode() )->getTooltipText() ) - : mTextureAtlasLoader->getTextureAtlas()->getByName( - mTextureRegionList->getItemSelectedText() ); + mCurTextureRegion = + ( Event->getNode()->isType( UI_TYPE_TEXTUREREGION ) + ? mTextureAtlasLoader->getTextureAtlas()->getByName( + static_cast( Event->getNode() )->getTooltipText() ) + : mTextureAtlasLoader->getTextureAtlas()->getByName( + mTextureRegionList->getItemSelectedText() ) ) + .get(); if ( Event->getNode()->isType( UI_TYPE_TEXTUREREGION ) ) mTextureRegionList->setSelected( @@ -459,8 +461,6 @@ void TextureAtlasEditor::saveTextureAtlas( const Event* ) { } void TextureAtlasEditor::onTextureAtlasClose( const Event* ) { - if ( NULL != mTextureAtlasLoader && NULL != mTextureAtlasLoader->getTextureAtlas() ) - TextureAtlasManager::instance()->remove( mTextureAtlasLoader->getTextureAtlas() ); eeSAFE_DELETE( mTextureAtlasLoader ); mTextureRegionList->clear(); mTextureRegionGrid->closeAllChildren(); diff --git a/src/eepp/ui/uiprogressbar.cpp b/src/eepp/ui/uiprogressbar.cpp index e4a848fb2..53a304b97 100644 --- a/src/eepp/ui/uiprogressbar.cpp +++ b/src/eepp/ui/uiprogressbar.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 061e8e903..6c17cbf45 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -1418,12 +1418,24 @@ void UISceneNode::updateDirtyStyles() { void UISceneNode::updateDirtyStyleStates() { if ( !mDirtyStyleState.empty() ) { Clock clock; - for ( auto& node : mDirtyStyleState ) { - node->reportStyleStateChangeRecursive( mDirtyStyleStateCSSAnimations[node] ); + + // Applying a style state can create widgets (for example a button icon). Widget + // construction invalidates its style state, so iterating mDirtyStyleState directly would + // mutate and potentially reallocate its vector-backed unordered_dense storage. Snapshot the + // current pass and leave new invalidations queued for the outer invalidation-depth loop. + mDirtyStyleStateSnapshot.clear(); + mDirtyStyleStateSnapshot.reserve( mDirtyStyleState.size() ); + for ( UIWidget* node : mDirtyStyleState ) { + auto animations = mDirtyStyleStateCSSAnimations.find( node ); + mDirtyStyleStateSnapshot.emplace_back( + node, animations != mDirtyStyleStateCSSAnimations.end() && animations->second ); } mDirtyStyleState.clear(); mDirtyStyleStateCSSAnimations.clear(); + for ( const auto& dirtyState : mDirtyStyleStateSnapshot ) + dirtyState.first->reportStyleStateChangeRecursive( dirtyState.second ); + if ( mVerbose ) Log::debug( "CSS Style State Invalidated, reapplied state in %.2f ms", clock.getElapsedTime().asMilliseconds() ); diff --git a/src/eepp/ui/uisprite.cpp b/src/eepp/ui/uisprite.cpp index 3b83c2ad1..0f976406f 100644 --- a/src/eepp/ui/uisprite.cpp +++ b/src/eepp/ui/uisprite.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/src/eepp/ui/uitextureregion.cpp b/src/eepp/ui/uitextureregion.cpp index 0d86876bc..575a46c01 100644 --- a/src/eepp/ui/uitextureregion.cpp +++ b/src/eepp/ui/uitextureregion.cpp @@ -1,7 +1,6 @@ -#include -#include #include #include +#include #include namespace EE { namespace UI { @@ -221,17 +220,15 @@ bool UITextureRegion::applyProperty( const StyleSheetProperty& attribute ) { switch ( attribute.getPropertyDefinition()->getPropertyId() ) { case PropertyId::Src: { - Drawable* res = NULL; std::string name( attribute.asString() ); if ( String::startsWith( name, "@textureregion/" ) ) { name = name.substr( 12 ); } - if ( NULL != - ( res = TextureAtlasManager::instance()->getTextureRegionByName( name ) ) && - res->getDrawableType() == Drawable::TEXTUREREGION ) { - setTextureRegion( static_cast( res ) ); + DrawablePtr resource = getUISceneNode()->getResourceScope()->findDrawableSource( name ); + if ( resource && resource->getDrawableType() == Drawable::TEXTUREREGION ) { + setTextureRegion( static_cast( resource.get() ) ); } break; } diff --git a/src/eepp/ui/uitheme.cpp b/src/eepp/ui/uitheme.cpp index 718de5ee5..9a44e98be 100644 --- a/src/eepp/ui/uitheme.cpp +++ b/src/eepp/ui/uitheme.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -51,14 +50,18 @@ UITheme* UITheme::load( const std::string& name, const std::string& abbr, if ( textureAtlasPath.empty() ) return theme; - TextureAtlasLoader tgl( textureAtlasPath ); + ResourceScopePtr resourceScope = ResourceScope::New(); + theme->mResourceCatalog = resourceScope->getLocalCatalog(); + TextureAtlasLoader tgl; + tgl.setResourceScope( std::move( resourceScope ) ); + tgl.loadFromFile( textureAtlasPath ); return loadFromTextureAtlas( theme, tgl.getTextureAtlas() ); } UITheme* UITheme::loadFromString( const std::string& name, const std::string& abbr, - const std::string& textureAtlasPath, Font* defaultFont, - const std::string& styleSheetString ) { + const std::string& textureAtlasPath, Font* defaultFont, + const std::string& styleSheetString ) { UITheme* theme = UITheme::New( name, abbr, defaultFont ); CSS::StyleSheetParser styleSheetParser; @@ -70,12 +73,16 @@ UITheme* UITheme::loadFromString( const std::string& name, const std::string& ab if ( textureAtlasPath.empty() ) return theme; - TextureAtlasLoader tgl( textureAtlasPath ); + ResourceScopePtr resourceScope = ResourceScope::New(); + theme->mResourceCatalog = resourceScope->getLocalCatalog(); + TextureAtlasLoader tgl; + tgl.setResourceScope( std::move( resourceScope ) ); + tgl.loadFromFile( textureAtlasPath ); return loadFromTextureAtlas( theme, tgl.getTextureAtlas() ); } -UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* textureAtlas ) { +UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, TextureAtlasPtr textureAtlas ) { eeASSERT( NULL != tTheme && NULL != textureAtlas ); /** Themes use nearest filter by default, force the filter to the textures. */ @@ -93,14 +100,13 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* std::map skins; for ( auto& it : resources ) { - TextureRegion* textureRegion = it.second; + TextureRegion* textureRegion = it.second.get(); std::string name( textureRegion->getName() ); if ( String::startsWith( name, sAbbrIcon ) ) { auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); - icon->setSource( textureRegion->getPixelsSize().getWidth(), - textureRegion->clone() ); + icon->setSource( textureRegion->getPixelsSize().getWidth(), textureRegion->clone() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { std::vector dotParts = String::split( name, '.' ); @@ -155,8 +161,7 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* skins[skinName] = tTheme->add( UISkin::New( skinName ) ); if ( -1 != stateNum ) - skins[skinName]->setStateDrawable( stateNum, - textureRegion->clone() ); + skins[skinName]->setStateDrawable( stateNum, textureRegion->clone() ); } } } @@ -180,7 +185,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, if ( !FileSystem::isDirectory( RPath ) ) return NULL; - Graphics::TextureAtlas* tSG = Graphics::TextureAtlas::New( tTheme->getAbbr() ); + TextureAtlasPtr tSG = TextureAtlas::New( tTheme->getAbbr() ); tTheme->setTextureAtlas( tSG ); @@ -196,7 +201,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, if ( !FileSystem::isDirectory( fpath ) ) { if ( String::startsWith( name, sAbbrIcon ) ) { - auto* drawable = + auto drawable = TextureRegion::New( TextureFactory::instance()->loadFromFile( fpath ), name ); tSG->add( drawable ); auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); @@ -250,7 +255,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, int lPart = nameParts.size() - 1; if ( UIState::isStateName( nameParts[lPart] ) ) { - TextureRegion* textureRegion = tSG->add( TextureRegion::New( + TextureRegionPtr textureRegion = tSG->add( TextureRegion::New( TextureFactory::instance()->loadFromFile( fpath ), name ) ); std::string skinName( elemNameFromSkin( nameParts ) ); @@ -260,8 +265,8 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, skins[skinName] = tTheme->add( UISkin::New( skinName ) ); if ( -1 != stateNum ) - skins[skinName]->setStateDrawable( - stateNum, textureRegion->clone() ); + skins[skinName]->setStateDrawable( stateNum, + textureRegion->clone() ); } } } @@ -270,9 +275,9 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, } if ( tSG->getCount() ) - TextureAtlasManager::instance()->add( tSG ); + tTheme->setTextureAtlas( tSG ); else - eeSAFE_DELETE( tSG ); + tTheme->setTextureAtlas( {} ); Log::info( "UI Theme Loaded in: %4.3f ms ( from path )", TE.getElapsedTimeAndReset().asMilliseconds() ); @@ -285,9 +290,9 @@ UITheme* UITheme::loadFromDirectory( const std::string& Path, const std::string& return loadFromDirectory( UITheme::New( Name, NameAbbr ), Path, pixelDensity ); } -UITheme* UITheme::loadFromTextureAtlas( Graphics::TextureAtlas* TextureAtlas, - const std::string& Name, const std::string& NameAbbr ) { - return loadFromTextureAtlas( UITheme::New( Name, NameAbbr ), TextureAtlas ); +UITheme* UITheme::loadFromTextureAtlas( TextureAtlasPtr textureAtlas, const std::string& Name, + const std::string& NameAbbr ) { + return loadFromTextureAtlas( UITheme::New( Name, NameAbbr ), std::move( textureAtlas ) ); } UITheme::UITheme( const std::string& name, const std::string& Abbr, Graphics::Font* defaultFont ) : @@ -295,7 +300,7 @@ UITheme::UITheme( const std::string& name, const std::string& Abbr, Graphics::Fo mName( name ), mNameHash( String::hash( mName ) ), mAbbr( Abbr ), - mTextureAtlas( NULL ), + mTextureAtlas(), mDefaultFont( defaultFont ), mDefaultFontSize( PixelDensity::dpToPx( PixelDensity::getPixelDensity() > 1.4 ? 11 : 12 ) ), mIconTheme( UIIconTheme::New( name ) ), @@ -327,11 +332,16 @@ UISkin* UITheme::add( UISkin* Resource ) { } Graphics::TextureAtlas* UITheme::getTextureAtlas() const { - return mTextureAtlas; + return mTextureAtlas.get(); } -void UITheme::setTextureAtlas( Graphics::TextureAtlas* SG ) { - mTextureAtlas = SG; +void UITheme::setTextureAtlas( TextureAtlasPtr textureAtlas ) { + mTextureAtlas = std::move( textureAtlas ); + if ( !mTextureAtlas ) + return; + mResourceCatalog->publishAtlas( mTextureAtlas->getName(), mTextureAtlas ); + for ( const auto& resource : mTextureAtlas->getResources() ) + mResourceCatalog->publishDrawable( resource.second->getName(), resource.second ); } UIIcon* UITheme::getIconByName( const std::string& name ) { diff --git a/src/eepp/window/engine.cpp b/src/eepp/window/engine.cpp index 28e1c3e21..4a8956ad1 100644 --- a/src/eepp/window/engine.cpp +++ b/src/eepp/window/engine.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -75,7 +74,6 @@ Engine::Engine() : FileSystem::changeWorkingDirectory( getPlatformHelper()->getExternalStoragePath() ); #endif - TextureAtlasManager::createSingleton(); UISceneNode::openAsyncResourceMainThreadQueue(); } @@ -109,8 +107,6 @@ Engine::~Engine() { FontManager::destroySingleton(); - TextureAtlasManager::destroySingleton(); - Graphics::Private::FrameBufferManager::destroySingleton(); Graphics::Private::VertexBufferManager::destroySingleton(); diff --git a/src/examples/sprites/sprites.cpp b/src/examples/sprites/sprites.cpp index baa9b6a09..7bf47fdaa 100644 --- a/src/examples/sprites/sprites.cpp +++ b/src/examples/sprites/sprites.cpp @@ -121,9 +121,9 @@ EE_MAIN_FUNC int main( int, char*[] ) { // Create a static sprite Planet.createStatic( PlanetTex ); - // It will look for a TextureRegion ( in any Texture Atlas loaded, or the GlobalTextureAtlas - // ) animation by its name, it will search for "gn00" to "gnXX" to create a new animation - // see TextureAtlasManager::GetTextureRegionsByPattern for more information. + // It will look for a TextureRegion animation in the default resource scope by its name. It + // will search for "gn00" to "gnXX" to create a new animation. See + // ResourceScope::findTextureRegionsByPattern for more information. // This is the easiest way to load animated sprites. Monster.addFramesByPattern( "gn" ); diff --git a/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp b/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp index 13b4cca08..28e317577 100644 --- a/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp @@ -1,5 +1,5 @@ +#include #include -#include #include #include #include @@ -134,19 +134,23 @@ void GameObjectSprite::setDataId( Uint32 Id ) { Graphics::SpritePtr tSprite; if ( mFlags & GObjFlags::GAMEOBJECT_ANIMATED ) { - std::vector tTextureRegionVec = - TextureAtlasManager::instance()->getTextureRegionsByPatternId( Id ); + std::vector tTextureRegionVec = + defaultResourceScope().findTextureRegionsByPatternId( Id ); if ( tTextureRegionVec.size() ) { tSprite = Graphics::Sprite::New(); tSprite->createAnimation(); - tSprite->addFrames( tTextureRegionVec ); + for ( const TextureRegionPtr& textureRegion : tTextureRegionVec ) + tSprite->addFrame( textureRegion.get() ); setSprite( std::move( tSprite ) ); } } else { + DrawablePtr drawable = defaultResourceScope().findDrawable( Id ); Graphics::TextureRegion* tTextureRegion = - TextureAtlasManager::instance()->getTextureRegionById( Id ); + drawable && drawable->getDrawableType() == Drawable::TEXTUREREGION + ? static_cast( drawable.get() ) + : nullptr; if ( NULL != tTextureRegion ) { setSprite( Graphics::Sprite::New( tTextureRegion ) ); diff --git a/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp b/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp index e419073b9..3ca4400a3 100644 --- a/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -106,9 +106,8 @@ Graphics::TextureRegion* GameObjectTextureRegion::getTextureRegion() const { void GameObjectTextureRegion::setTextureRegion( Graphics::TextureRegion* TextureRegion ) { mTextureRegion = - TextureRegion - ? std::static_pointer_cast( TextureRegion->clone() ) - : TextureRegionPtr{}; + TextureRegion ? std::static_pointer_cast( TextureRegion->clone() ) + : TextureRegionPtr{}; } Uint32 GameObjectTextureRegion::getDataId() { @@ -116,7 +115,10 @@ Uint32 GameObjectTextureRegion::getDataId() { } void GameObjectTextureRegion::setDataId( Uint32 Id ) { - setTextureRegion( TextureAtlasManager::instance()->getTextureRegionById( Id ) ); + DrawablePtr drawable = defaultResourceScope().findDrawable( Id ); + setTextureRegion( drawable && drawable->getDrawableType() == Drawable::TEXTUREREGION + ? static_cast( drawable.get() ) + : nullptr ); } }} // namespace EE::Maps diff --git a/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp b/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp index 9dec79224..8852ec9c3 100644 --- a/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp +++ b/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp @@ -1,8 +1,7 @@ #include -#include +#include #include #include -#include #include #include #include @@ -935,8 +934,7 @@ void MapEditor::onNewGOTypeAdded( std::string name, String::HashType ) { } void MapEditor::fillSGCombo() { - TextureAtlasManager* SGM = TextureAtlasManager::instance(); - auto& res = SGM->getResources(); + std::vector atlases = defaultResourceScope().getAtlases(); mTextureAtlasesList->getListBox()->clear(); @@ -947,9 +945,9 @@ void MapEditor::fillSGCombo() { if ( NULL != mTheme && NULL != mTheme->getTextureAtlas() ) Restricted2 = String::hash( mTheme->getTextureAtlas()->getName() ); - for ( auto& it : res ) { - if ( it.second->getId() != Restricted1 && it.second->getId() != Restricted2 ) - items.push_back( it.second->getName() ); + for ( const TextureAtlasPtr& atlas : atlases ) { + if ( atlas->getId() != Restricted1 && atlas->getId() != Restricted2 ) + items.push_back( atlas->getName() ); } if ( items.size() ) { @@ -963,13 +961,12 @@ void MapEditor::fillSGCombo() { } void MapEditor::fillTextureRegionList() { - TextureAtlasManager* SGM = TextureAtlasManager::instance(); - mCurSG = SGM->getByName( mTextureAtlasesList->getText() ); - auto& res = mCurSG->getResources(); + mCurSG = defaultResourceScope().findAtlas( mTextureAtlasesList->getText() ).get(); mTextureRegionList->clear(); if ( NULL != mCurSG ) { + auto& res = mCurSG->getResources(); std::vector items; for ( auto& it : res ) { @@ -991,7 +988,7 @@ void MapEditor::fillTextureRegionList() { void MapEditor::onTextureRegionChange( const Event* ) { if ( NULL != mCurSG ) { TextureRegion* tTextureRegion = - mCurSG->getByName( mTextureRegionList->getItemSelectedText() ); + mCurSG->getByName( mTextureRegionList->getItemSelectedText() ).get(); if ( NULL != tTextureRegion ) { mGfxPreview->setTextureRegion( tTextureRegion ); @@ -1373,9 +1370,9 @@ void MapEditor::cextureAtlasOpen( const Event* Event ) { std::string sgname = FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( CDL->getFullPath() ) ); - TextureAtlas* SG = TextureAtlasManager::instance()->getByName( sgname ); + TextureAtlasPtr atlas = defaultResourceScope().findAtlas( sgname ); - if ( NULL == SG ) { + if ( !atlas ) { TextureAtlasLoader tgl( CDL->getFullPath() ); if ( tgl.isLoaded() ) { @@ -1443,14 +1440,13 @@ GameObject* MapEditor::createGameObject() { SpritePtr tAnimSprite = Sprite::New( String::removeNumbersAtEnd( mGfxPreview->getTextureRegion()->getName() ) ); tAnimSprite->setAutoAnimate( false ); - tObj = eeNew( GameObjectSprite, - ( mCurGOFlags, mCurLayer, std::move( tAnimSprite ) ) ); + tObj = eeNew( GameObjectSprite, ( mCurGOFlags, mCurLayer, std::move( tAnimSprite ) ) ); } else { SpritePtr tStaticSprite = Sprite::New( mGfxPreview->getTextureRegion() ); - tObj = eeNew( GameObjectSprite, - ( mCurGOFlags, mCurLayer, std::move( tStaticSprite ) ) ); + tObj = + eeNew( GameObjectSprite, ( mCurGOFlags, mCurLayer, std::move( tStaticSprite ) ) ); } } else { //! Creates an empty game object. The client will interpret the GameObject Type, and diff --git a/src/modules/maps/src/eepp/maps/tilemap.cpp b/src/modules/maps/src/eepp/maps/tilemap.cpp index ddfbf3082..785cb7101 100644 --- a/src/modules/maps/src/eepp/maps/tilemap.cpp +++ b/src/modules/maps/src/eepp/maps/tilemap.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include using namespace EE::Graphics; @@ -672,8 +671,11 @@ GameObject* TileMap::createGameObject( const Uint32& Type, const Uint32& Flags, return mCreateGOCb( Type, Flags, Layer, DataId ); } else { GameObjectVirtual* tVirtual; + DrawablePtr drawable = defaultResourceScope().findDrawable( DataId ); TextureRegion* tIsTextureRegion = - TextureAtlasManager::instance()->getTextureRegionById( DataId ); + drawable && drawable->getDrawableType() == Drawable::TEXTUREREGION + ? static_cast( drawable.get() ) + : nullptr; if ( NULL != tIsTextureRegion ) { tVirtual = eeNew( GameObjectVirtual, ( tIsTextureRegion, Layer, Flags, Type ) ); @@ -861,7 +863,7 @@ bool TileMap::loadFromStream( IOStream& IOS ) { std::string sgname = FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( TextureAtlases[i] ) ); - if ( NULL == TextureAtlasManager::instance()->getByName( sgname ) ) { + if ( !defaultResourceScope().findAtlas( sgname ) ) { TextureAtlasLoader* tgl = eeNew( TextureAtlasLoader, () ); if ( !VirtualFileSystem::instance()->fileExists( TextureAtlases[i] ) && @@ -1439,8 +1441,7 @@ void TileMap::saveToFile( const std::string& path ) { } std::vector TileMap::getTextureAtlases() { - TextureAtlasManager* SGM = TextureAtlasManager::instance(); - auto& res = SGM->getResources(); + std::vector atlases = defaultResourceScope().getAtlases(); std::vector items; @@ -1453,9 +1454,9 @@ std::vector TileMap::getTextureAtlases() { ->getTextureAtlas() ->getName() ); - for ( auto& it : res ) { - if ( it.second->getId() != Restricted1 && it.second->getId() != Restricted2 ) - items.push_back( it.second->getPath() ); + for ( const TextureAtlasPtr& atlas : atlases ) { + if ( atlas->getId() != Restricted1 && atlas->getId() != Restricted2 ) + items.push_back( atlas->getPath() ); } return items; diff --git a/src/tests/test_all/test.cpp b/src/tests/test_all/test.cpp index 56e55f81f..eda2b1474 100644 --- a/src/tests/test_all/test.cpp +++ b/src/tests/test_all/test.cpp @@ -1399,14 +1399,14 @@ void EETest::loadTextures() { Tiles.resize( 10 ); TextureAtlasLoader tgl( MyPath + "atlases/tiles.eta" ); - TextureAtlas* SG = TextureAtlasManager::instance()->getByName( "tiles" ); + TextureAtlas* SG = tgl.getTextureAtlas().get(); if ( NULL != SG ) { for ( i = 0; i < 6; i++ ) { - Tiles[i] = SG->getByName( String::toString( i + 1 ) ); + Tiles[i] = SG->getByName( String::toString( i + 1 ) ).get(); } - Tiles[6] = SG->add( TF->loadFromFile( MyPath + "sprites/objects/1.png" ), "7" ); + Tiles[6] = SG->add( TF->loadFromFile( MyPath + "sprites/objects/1.png" ), "7" ).get(); #ifdef EE_GLES Image tImg( MyPath + "sprites/objects/2.png", 4 ); @@ -1415,7 +1415,7 @@ void EETest::loadTextures() { tImg.getHeight(), tImg.getChannels() ), "8" ); #else - Tiles[7] = SG->add( TF->loadFromFile( MyPath + "sprites/objects/2.png" ), "8" ); + Tiles[7] = SG->add( TF->loadFromFile( MyPath + "sprites/objects/2.png" ), "8" ).get(); Tiles[7]->getTexture()->createMaskFromColor( Color( 0, 0, 0, 255 ), 0 ); #endif } @@ -1483,10 +1483,10 @@ void EETest::loadTextures() { mMonster.addFramesByPattern( "rn" ); mMonster.setPosition( Vector2f( 320.f, 0.f ) ); - mBoxSprite = - Sprite::New( GlobalTextureAtlas::instance()->add( TextureRegion::New( TN[3], "ilmare" ) ) ); - mCircleSprite = Sprite::New( - GlobalTextureAtlas::instance()->add( TextureRegion::New( TN[1], "thecircle" ) ) ); + TextureRegionPtr boxRegion = TextureRegion::New( TN[3], "ilmare" ); + mBoxSprite = Sprite::New( boxRegion.get() ); + TextureRegionPtr circleRegion = TextureRegion::New( TN[1], "thecircle" ); + mCircleSprite = Sprite::New( circleRegion.get() ); Log::info( "Textures loading time: %4.3f ms.", TE.getElapsedTimeAndReset().asMilliseconds() ); diff --git a/src/tests/unit_tests/resource_prerequisite_tests.cpp b/src/tests/unit_tests/resource_prerequisite_tests.cpp index 5ef6bad17..30d3e315f 100644 --- a/src/tests/unit_tests/resource_prerequisite_tests.cpp +++ b/src/tests/unit_tests/resource_prerequisite_tests.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -84,7 +83,9 @@ class TestTextureAtlas : public TextureAtlas { class TestTextureAtlasLoader : public TextureAtlasLoader { public: - void setTextureAtlas( TextureAtlas* textureAtlas ) { mTextureAtlas = textureAtlas; } + void setTextureAtlas( TextureAtlasPtr textureAtlas ) { + mTextureAtlas = std::move( textureAtlas ); + } void loadDelayed( const std::shared_ptr& gate, const std::shared_ptr>& callbackCompleted ) { @@ -234,11 +235,11 @@ UTEST( ResourcePrerequisites, textureAtlasLoaderAppliesFilterToEveryTexture ) { ASSERT_TRUE( first != NULL ); ASSERT_TRUE( second != NULL ); - TestTextureAtlas atlas; - atlas.setTextures( { first, second } ); + auto atlas = makeResource(); + atlas->setTextures( { first, second } ); TestTextureAtlasLoader loader; - loader.setTextureAtlas( &atlas ); + loader.setTextureAtlas( atlas ); loader.setTextureFilter( Texture::Filter::Nearest ); EXPECT_EQ( first->getFilter(), Texture::Filter::Nearest ); @@ -255,6 +256,49 @@ UTEST( ResourcePrerequisites, textureAtlasLoaderAcceptsFilterBeforeAtlasExists ) Texture::Filter::Nearest ); } +UTEST( ResourcePrerequisites, textureAtlasAndCatalogRetainRegionsByHandle ) { + TextureAtlasPtr atlas = TextureAtlas::New( "owned-atlas" ); + TextureRegionPtr region = TextureRegion::New( TexturePtr{}, "owned-region" ); + TextureRegionWeakPtr weakRegion = region; + atlas->add( region ); + region.reset(); + ASSERT_FALSE( weakRegion.expired() ); + + ResourceCatalogPtr catalog = ResourceCatalog::New(); + TextureAtlasWeakPtr weakAtlas = atlas; + catalog->publishAtlas( atlas->getName(), atlas ); + atlas.reset(); + ASSERT_FALSE( weakAtlas.expired() ); + EXPECT_TRUE( catalog->findAtlas( "owned-atlas" ) != nullptr ); + + catalog->eraseAtlas( "owned-atlas" ); + EXPECT_TRUE( weakAtlas.expired() ); + EXPECT_TRUE( weakRegion.expired() ); +} + +UTEST( ResourcePrerequisites, resourceScopeResolvesPublishedAtlasRegionPatterns ) { + ResourceScopePtr scope = ResourceScope::New(); + TextureAtlasPtr atlas = TextureAtlas::New( "pattern-atlas" ); + TextureRegionPtr first = atlas->add( TextureRegion::New( TexturePtr{}, "walk00" ) ); + TextureRegionPtr second = atlas->add( TextureRegion::New( TexturePtr{}, "walk01" ) ); + scope->publishLocalAtlas( atlas->getName(), atlas ); + scope->publishLocalDrawable( first->getName(), first ); + scope->publishLocalDrawable( second->getName(), second ); + + std::vector pattern = scope->findTextureRegionsByPattern( "walk" ); + ASSERT_EQ( pattern.size(), 2u ); + EXPECT_EQ( pattern[0].get(), first.get() ); + EXPECT_EQ( pattern[1].get(), second.get() ); + std::vector patternById = + scope->findTextureRegionsByPatternId( first->getId() ); + ASSERT_EQ( patternById.size(), 2u ); + EXPECT_EQ( patternById[0].get(), first.get() ); + + SpritePtr sprite = Sprite::New( *scope, "walk" ); + ASSERT_TRUE( sprite != nullptr ); + EXPECT_EQ( sprite->getNumFrames(), 2u ); +} + UTEST( ResourcePrerequisites, textureRegistryTracksStableIdentityAndMemoryWithoutOwning ) { createLifecycleTestWindow( "Texture registry identity test" ); TextureFactory* factory = TextureFactory::instance(); @@ -1025,7 +1069,6 @@ UTEST( ResourcePrerequisites, engineTeardownReleasesGraphicsBeforeContextsAcross EXPECT_TRUE( SceneManager::existsSingleton() == nullptr ); EXPECT_TRUE( GlobalBatchRenderer::existsSingleton() == nullptr ); EXPECT_TRUE( FontManager::existsSingleton() == nullptr ); - EXPECT_TRUE( TextureAtlasManager::existsSingleton() == nullptr ); EXPECT_TRUE( TextureFactory::existsSingleton() == nullptr ); EXPECT_TRUE( ShaderProgramManager::existsSingleton() == nullptr ); EXPECT_TRUE( Graphics::Private::FrameBufferManager::existsSingleton() == nullptr ); diff --git a/src/tests/unit_tests/uiscenenode_tests.cpp b/src/tests/unit_tests/uiscenenode_tests.cpp index a931edbb1..326e87ee1 100644 --- a/src/tests/unit_tests/uiscenenode_tests.cpp +++ b/src/tests/unit_tests/uiscenenode_tests.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -364,3 +365,22 @@ UTEST( UISceneNode, NestedSceneInvalidationPropagatesToHostScene ) { Engine::destroySingleton(); } + +UTEST( UISceneNode, StyleStateUpdateAllowsWidgetCreation ) { + Engine::instance()->createWindow( WindowSettings( 1024, 768, "Style State Widget Creation Test", + WindowStyle::Default, WindowBackend::Default, + 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_scene_node(); + UIFileDialog* dialog = UIFileDialog::New(); + dialog->setParent( sceneNode->getRoot() ); + + // Applying the select-button state creates its UIImage icon. The new widget invalidates style + // state while the current dirty-state pass is still being processed. + sceneNode->flushDirtyStyleAndLayout(); + + EXPECT_TRUE( dialog->getButtonOpen() != nullptr ); + + Engine::destroySingleton(); +} diff --git a/src/tools/uieditor/uieditor.cpp b/src/tools/uieditor/uieditor.cpp index 7ee2c5e05..5c1431cb2 100644 --- a/src/tools/uieditor/uieditor.cpp +++ b/src/tools/uieditor/uieditor.cpp @@ -135,7 +135,7 @@ void App::saveConfig() { void App::unloadImages() { for ( auto it = mImagesLoaded.begin(); it != mImagesLoaded.end(); ++it ) { - GlobalTextureAtlas::instance()->remove( it->second ); + mUISceneNode->getResourceScope()->eraseLocalDrawable( it->second->getName() ); } mImagesLoaded.clear(); } @@ -151,8 +151,8 @@ void App::loadImage( std::string path ) { TexturePtr tex = TextureFactory::instance()->loadFromFile( path ); if ( tex ) { ResourceId texId = tex->getTextureId(); - TextureRegion* texRegion = - GlobalTextureAtlas::instance()->add( std::move( tex ), filename ); + TextureRegionPtr texRegion = TextureRegion::New( std::move( tex ), filename ); + mUISceneNode->getResourceScope()->publishLocalDrawable( filename, texRegion ); mImagesLoaded[texId] = texRegion; } } @@ -584,13 +584,15 @@ std::string App::pathFix( std::string path ) { } void App::loadUITheme( std::string themePath ) { - TextureAtlasLoader tgl( themePath ); + TextureAtlasLoader tgl; + tgl.setResourceScope( mUISceneNode->getResourceScope() ); + tgl.loadFromFile( themePath ); std::string name( FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( themePath ) ) ); - UITheme* uitheme = UITheme::loadFromTextureAtlas( - UITheme::New( name, name ), TextureAtlasManager::instance()->getByName( name ) ); + UITheme* uitheme = + UITheme::loadFromTextureAtlas( UITheme::New( name, name ), tgl.getTextureAtlas() ); mUISceneNode->getUIThemeManager()->setDefaultTheme( uitheme )->add( uitheme ); } diff --git a/src/tools/uieditor/uieditor.hpp b/src/tools/uieditor/uieditor.hpp index 8efd57710..08514074b 100644 --- a/src/tools/uieditor/uieditor.hpp +++ b/src/tools/uieditor/uieditor.hpp @@ -194,7 +194,7 @@ class App : public UICodeEditorSplitter::Client { IniFile mIni; Uint32 mRecentProjectEventClickId{ 0xFFFFFFFF }; Uint32 mRecentFilesEventClickId{ 0xFFFFFFFF }; - std::map mImagesLoaded; + std::map mImagesLoaded; std::map mFontsLoaded; UpdateListener* mListener{ nullptr }; std::string mConfigPath;