diff --git a/.agent/plans/resource_ownership_followup_plan.md b/.agent/plans/resource_ownership_followup_plan.md new file mode 100644 index 000000000..bd6a37abd --- /dev/null +++ b/.agent/plans/resource_ownership_followup_plan.md @@ -0,0 +1,61 @@ +# Resource ownership follow-up plan + +Status: proposed follow-up after Stage 7 completion, 2026-07-24. + +The shared-resource ownership migration is complete. This plan is intentionally limited to +validation, documentation, diagnostics, and compatibility-era naming cleanup. It must not reopen +the established `ResourceScope` / `ResourceCatalog` ownership model without a concrete defect. + +## 1. Scene lifetime coverage + +- Add focused tests proving resources published only into a scene scope are released when its + `UISceneNode` and `ResourceScope` are destroyed. +- Cover textures, drawables, fonts, themes, icons, and shader programs where practical. +- Verify explicitly imported catalogs remain alive only through their actual external owners. +- Assert against registry/catalog contents and retained handles, not only destructor side effects. + +## 2. Public ownership documentation + +- Audit public resource APIs and consistently document whether parameters and return values are: + owning, retaining, borrowing, or observing. +- Document the required lifetime for borrowed raw pointers returned by UI and GPU APIs. +- Keep hot-path raw pointers where ownership is established elsewhere; do not imply ownership by + converting those APIs to shared handles. +- Add short ownership examples to `ResourceScope`, `ResourceCatalog`, and family-specific services. + +## 3. Compatibility-era naming cleanup + +- Rename non-owning `ShaderProgramManager`, `VertexBufferManager`, and `FrameBufferManager` + concepts to `ShaderProgramRegistry`, `VertexBufferRegistry`, and `FrameBufferRegistry` throughout + filenames, includes, build files, and documentation. +- Review other `*Manager` names only when their current role is genuinely a registry or service. +- Keep this as an isolated public API cleanup so downstream include breakage is easy to review. + +## 4. GPU borrowed-lifetime diagnostics + +- Add debug-only validation that borrowed frame buffers, vertex buffers, shaders, and programs are + not used after their owning OpenGL context or renderer has been destroyed. +- Prefer cheap generation/context identity checks at API boundaries over reference counting in hot + rendering paths. +- Do not add OpenGL context-loss recreation support; current supported platforms do not require it. + +## 5. Static initialization audit + +- Build a Clang diagnostic configuration with `-Wglobal-constructors` and + `-Wexit-time-destructors` to identify C++ work performed before `main()` and after its return. +- Produce a linker-level inventory of `.init_array` entries for representative executables to find + constructors hidden in libraries or translation units excluded from Clang diagnostics. +- Prioritize globals that allocate memory, register callbacks/resources, depend on singleton order, + or retain graphics objects. Constant-initialized POD data is not a migration target. +- Move executable state into `main()` scopes and callback lambdas. Replace necessary library + globals with function-local statics only when process lifetime is intentional and documented. +- Track the baseline count and prevent new non-trivial global constructors in CI once existing + cases have been classified. + +## Validation + +- Run the complete unit-test suite and all normal platform CI jobs after each focused change. +- Keep `git diff --check` clean and run examples affected by shutdown-order changes under ASan. +- Confirm GPU/resource handles are destroyed before `Engine::destroySingleton()` in examples and + tools that own them locally. + diff --git a/.agent/plans/resource_shared_ownership_architecture.md b/.agent/plans/resource_shared_ownership_architecture.md index a052197c0..b42218b4c 100644 --- a/.agent/plans/resource_shared_ownership_architecture.md +++ b/.agent/plans/resource_shared_ownership_architecture.md @@ -1,6 +1,6 @@ # eepp shared-resource ownership architecture -Status: active implementation baseline; Stage 0 through Stage 6 complete, 2026-07-21. +Status: implementation complete through Stage 7, 2026-07-24. This document freezes the contracts that must be true before the public texture API is changed. The implementation may refine names and small mechanics, but changing an invariant below requires an @@ -792,7 +792,7 @@ Exit criteria: ### Stage 7: remaining resource families -Status: in progress. Nine-patches and texture atlases are migrated. `NinePatch::New()`, +Status: complete, 2026-07-24. 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. @@ -821,7 +821,15 @@ handle. The former process-wide `FontManager` singleton and compatibility namesp Publishing a font with an existing local key replaces that catalog binding; the legacy manager behavior that silently suffixed duplicate font names is intentionally not preserved. -Remove raw-owning `ResourceManager` only when no subclass or consumer depends on it. +Themes, skins, icon themes, and icons now use shared resource handles. Each scene's +`UIThemeManager` owns its themes and imports their catalogs into that scene's scope; it is not a +process-wide semantic namespace. Shader and shader-program factories return handles, programs own +their constituent shaders, and catalogs/scopes can publish shader programs under semantic keys. +`ShaderProgramRegistry`, `VertexBufferRegistry`, and `FrameBufferRegistry` remain process-wide only +as non-owning inventories of live OpenGL-context objects used for reload and diagnostics. + +The raw-owning `ResourceManager` and `ResourceManagerMulti` templates were removed after their +last consumers migrated. ## 11. Required validation matrix @@ -886,8 +894,8 @@ 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 -now use scope catalogs plus `FontService`; the next families are themes/icons, shaders/programs, and -any remaining raw-owning manager. Each singleton semantic namespace is replaced by naturally owned -catalogs plus explicit scope imports. The raw-owning ResourceManager template is removed only after -its final consumer is migrated. +The ownership migration is complete through Stage 7. Follow-up work is validation and API polish: +expand scene-lifetime and repeated-Engine coverage, audit public ownership documentation, add +debug-only borrowed GPU lifetime checks, audit non-trivial static initialization, and rename +compatibility-era manager filenames when the public include transition is scheduled. OpenGL +context-loss recreation is explicitly outside the supported lifecycle contract. diff --git a/include/eepp/graphics/framebuffer.hpp b/include/eepp/graphics/framebuffer.hpp index 93bf9fa11..7bf2b66ca 100644 --- a/include/eepp/graphics/framebuffer.hpp +++ b/include/eepp/graphics/framebuffer.hpp @@ -2,6 +2,7 @@ #define EE_GRAPHICSCFRAMEBUFFER_HPP #include +#include #include #include @@ -13,6 +14,9 @@ using namespace EE::Window; namespace EE { namespace Graphics { +class FrameBuffer; +using FrameBufferUniquePtr = std::unique_ptr>; + /** @brief A frame buffer allows rendering to a off-screen 2D texture */ class EE_API FrameBuffer { public: @@ -26,9 +30,10 @@ class EE_API FrameBuffer { ** @param window In case that the application is using more than one window, the user can *indicate which one to use ( by default uses the current active window ) */ - static FrameBuffer* New( const Uint32& Width, const Uint32& Height, bool StencilBuffer = true, - bool DepthBuffer = false, bool useColorBuffer = false, - const Uint32& channels = 4, EE::Window::Window* window = NULL ); + static FrameBufferUniquePtr New( const Uint32& Width, const Uint32& Height, + bool StencilBuffer = true, bool DepthBuffer = false, + bool useColorBuffer = false, const Uint32& channels = 4, + EE::Window::Window* window = NULL ); virtual ~FrameBuffer(); diff --git a/include/eepp/graphics/framebuffermanager.hpp b/include/eepp/graphics/framebuffermanager.hpp index d854c2b68..2464fdb07 100644 --- a/include/eepp/graphics/framebuffermanager.hpp +++ b/include/eepp/graphics/framebuffermanager.hpp @@ -10,11 +10,12 @@ using namespace EE::System; namespace EE { namespace Graphics { namespace Private { -class EE_API FrameBufferManager : public Container { - SINGLETON_DECLARE_HEADERS( FrameBufferManager ) +/** Non-owning registry of framebuffers visible to the active graphics context. */ +class EE_API FrameBufferRegistry : public Container { + SINGLETON_DECLARE_HEADERS( FrameBufferRegistry ) public: - virtual ~FrameBufferManager(); + virtual ~FrameBufferRegistry(); FrameBuffer* getCurrentlyBound(); @@ -23,7 +24,7 @@ class EE_API FrameBufferManager : public Container { FrameBuffer* getFromId( const String::HashType& id ); protected: - FrameBufferManager(); + FrameBufferRegistry(); }; }}} // namespace EE::Graphics::Private diff --git a/include/eepp/graphics/primitivedrawable.hpp b/include/eepp/graphics/primitivedrawable.hpp index 33b33d788..3d59e6493 100644 --- a/include/eepp/graphics/primitivedrawable.hpp +++ b/include/eepp/graphics/primitivedrawable.hpp @@ -3,11 +3,10 @@ #include #include +#include namespace EE { namespace Graphics { -class VertexBuffer; - class EE_API PrimitiveDrawable : public Drawable { public: virtual ~PrimitiveDrawable(); @@ -47,7 +46,7 @@ class EE_API PrimitiveDrawable : public Drawable { bool mNeedsUpdate; bool mRecreateVertexBuffer; bool mSmooth{ false }; - VertexBuffer* mVertexBuffer; + VertexBufferUniquePtr mVertexBuffer; virtual void onAlphaChange(); diff --git a/include/eepp/graphics/renderer/renderergl3.hpp b/include/eepp/graphics/renderer/renderergl3.hpp index 13c19d215..ab04da4af 100644 --- a/include/eepp/graphics/renderer/renderergl3.hpp +++ b/include/eepp/graphics/renderer/renderergl3.hpp @@ -68,7 +68,7 @@ class EE_API RendererGL3 : public RendererGLShader { void reloadCurrentShader(); protected: - ShaderProgram* mShaders[EEGL3_SHADERS_COUNT]; + ShaderProgramPtr mShaders[EEGL3_SHADERS_COUNT]; int mAttribsLoc[EEGL_ARRAY_STATES_COUNT]; int mAttribsLocStates[EEGL_ARRAY_STATES_COUNT]; int mPlanes[EE_MAX_PLANES]; diff --git a/include/eepp/graphics/renderer/renderergl3cp.hpp b/include/eepp/graphics/renderer/renderergl3cp.hpp index af86d2cd7..86be0c1ff 100644 --- a/include/eepp/graphics/renderer/renderergl3cp.hpp +++ b/include/eepp/graphics/renderer/renderergl3cp.hpp @@ -70,7 +70,7 @@ class EE_API RendererGL3CP : public RendererGLShader { void reloadCurrentShader(); protected: - ShaderProgram* mShaders[EEGL3CP_SHADERS_COUNT]; + ShaderProgramPtr mShaders[EEGL3CP_SHADERS_COUNT]; unsigned int mVAO; unsigned int mVBO[8]; int mAttribsLoc[EEGL_ARRAY_STATES_COUNT]; diff --git a/include/eepp/graphics/renderer/renderergles2.hpp b/include/eepp/graphics/renderer/renderergles2.hpp index 8d763ef71..3760a27e1 100644 --- a/include/eepp/graphics/renderer/renderergles2.hpp +++ b/include/eepp/graphics/renderer/renderergles2.hpp @@ -74,7 +74,7 @@ class EE_API RendererGLES2 : public RendererGLShader { void reloadCurrentShader(); protected: - ShaderProgram* mShaders[EEGLES2_SHADERS_COUNT]; + ShaderProgramPtr mShaders[EEGLES2_SHADERS_COUNT]; int mAttribsLoc[EEGL_ARRAY_STATES_COUNT]; int mAttribsLocStates[EEGL_ARRAY_STATES_COUNT]; int mPlanes[EE_MAX_PLANES]; diff --git a/include/eepp/graphics/resourcecatalog.hpp b/include/eepp/graphics/resourcecatalog.hpp index ef1543cc5..6d7940b58 100644 --- a/include/eepp/graphics/resourcecatalog.hpp +++ b/include/eepp/graphics/resourcecatalog.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,11 @@ class EE_API ResourceCatalog { /** @copydoc publishFont(ResourceKey,FontPtr) */ void publishFont( std::string key, FontPtr font ); + /** @brief Publishes or replaces a shader-program binding. A null program erases @p key. */ + void publishShaderProgram( ResourceKey key, ShaderProgramPtr program ); + /** @copydoc publishShaderProgram(ResourceKey,ShaderProgramPtr) */ + void publishShaderProgram( std::string key, ShaderProgramPtr program ); + /** @return The texture bound to @p key, or an empty handle when it is not present. */ TexturePtr findTexture( const ResourceKey& key ) const; /** @copydoc findTexture(const ResourceKey&)const */ @@ -101,6 +107,13 @@ class EE_API ResourceCatalog { /** @return An owning snapshot of all fonts currently published in this catalog. */ std::vector getFonts() const; + /** @return The shader program bound to @p key, or an empty handle when absent. */ + ShaderProgramPtr findShaderProgram( const ResourceKey& key ) const; + /** @copydoc findShaderProgram(const ResourceKey&)const */ + ShaderProgramPtr findShaderProgram( const std::string& key ) const; + /** @return An owning snapshot of all shader programs published in this catalog. */ + std::vector getShaderPrograms() const; + /** @brief Removes the texture binding for @p key. @return Whether a binding was removed. */ bool erase( const ResourceKey& key ); /** @copydoc erase(const ResourceKey&) */ @@ -127,10 +140,15 @@ class EE_API ResourceCatalog { */ bool eraseFont( Font* font ); + /** @brief Removes the shader-program binding for @p key. */ + bool eraseShaderProgram( const ResourceKey& key ); + /** @copydoc eraseShaderProgram(const ResourceKey&) */ + bool eraseShaderProgram( const std::string& key ); + /** @brief Removes every binding while allowing previously returned handles to remain valid. */ void clear(); - /** @return The total number of texture, drawable, atlas, and font bindings. */ + /** @return The total number of bindings of every supported resource kind. */ std::size_t size() const; private: @@ -141,6 +159,7 @@ class EE_API ResourceCatalog { UnorderedMap mAtlases; UnorderedMap mFonts; UnorderedMap mFontsById; + UnorderedMap mShaderPrograms; }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/resourcescope.hpp b/include/eepp/graphics/resourcescope.hpp index bb5e5e985..f4ac210a0 100644 --- a/include/eepp/graphics/resourcescope.hpp +++ b/include/eepp/graphics/resourcescope.hpp @@ -49,6 +49,9 @@ class EE_API ResourceScope { FontPtr findFont( const std::string& key ) const; FontPtr findFont( const String::HashType& id ) const; std::vector getFonts() const; + ShaderProgramPtr findShaderProgram( const ResourceKey& key ) const; + ShaderProgramPtr findShaderProgram( const std::string& key ) const; + std::vector getShaderPrograms() const; std::vector findTextureRegionsByPattern( const std::string& name, const std::string& extension = "", TextureAtlas* searchInTextureAtlas = nullptr ) const; @@ -69,6 +72,8 @@ class EE_API ResourceScope { */ void publishLocalFont( ResourceKey key, FontPtr font ); void publishLocalFont( std::string key, FontPtr font ); + void publishLocalShaderProgram( ResourceKey key, ShaderProgramPtr program ); + void publishLocalShaderProgram( std::string key, ShaderProgramPtr program ); bool eraseLocal( const ResourceKey& key ); bool eraseLocal( const std::string& key ); bool eraseLocalDrawable( const ResourceKey& key ); @@ -78,6 +83,8 @@ class EE_API ResourceScope { bool eraseLocalFont( const ResourceKey& key ); bool eraseLocalFont( const std::string& key ); bool eraseLocalFont( Font* font ); + bool eraseLocalShaderProgram( const ResourceKey& key ); + bool eraseLocalShaderProgram( const std::string& key ); void clearLocal(); /** diff --git a/include/eepp/graphics/shader.hpp b/include/eepp/graphics/shader.hpp index fb2fb8d92..bdf93d67a 100644 --- a/include/eepp/graphics/shader.hpp +++ b/include/eepp/graphics/shader.hpp @@ -2,12 +2,17 @@ #define EE_GRAPHICSCSHADER_H #include +#include #include using namespace EE::System; namespace EE { namespace Graphics { +class Shader; +using ShaderPtr = ResourcePtr; +using ShaderWeakPtr = ResourceWeakPtr; + /** @brief The basic shader class. */ class EE_API Shader { public: diff --git a/include/eepp/graphics/shaderprogram.hpp b/include/eepp/graphics/shaderprogram.hpp index 3e0127752..cdd0ee409 100644 --- a/include/eepp/graphics/shaderprogram.hpp +++ b/include/eepp/graphics/shaderprogram.hpp @@ -6,6 +6,10 @@ namespace EE { namespace Graphics { +class ShaderProgram; +using ShaderProgramPtr = ResourcePtr; +using ShaderProgramWeakPtr = ResourceWeakPtr; + /** @brief The Shader Program Class. @short Program is a GPU-executed program that is ready to be used for manipulating geometry and colors. * ShaderProgram can encapsulate vertex and fragment shaders or just one of them. If only @@ -15,40 +19,42 @@ other stage. class EE_API ShaderProgram { public: /** Creates an empty shader program */ - static ShaderProgram* New( const std::string& Name = "" ); + static ShaderProgramPtr New( const std::string& Name = "" ); /** Creates a program shader with a vector of shaders and link them. */ - static ShaderProgram* New( const std::vector& Shaders, const std::string& Name = "" ); + static ShaderProgramPtr New( const std::vector& Shaders, + const std::string& Name = "" ); /** Creates a VertexShader from file and a Fragment Shader from file, and link them. */ - static ShaderProgram* New( const std::string& VertexShaderFile, - const std::string& FragmentShaderFile, - const std::string& Name = "" ); + static ShaderProgramPtr New( const std::string& VertexShaderFile, + const std::string& FragmentShaderFile, + const std::string& Name = "" ); /** Creates a VertexShader from memory and a Fragment Shader from memory, and link them. */ - static ShaderProgram* New( const char* VertexShaderData, const Uint32& VertexShaderDataSize, - const char* FragmentShaderData, const Uint32& FragmentShaderDataSize, - const std::string& Name = "" ); + static ShaderProgramPtr New( const char* VertexShaderData, const Uint32& VertexShaderDataSize, + const char* FragmentShaderData, + const Uint32& FragmentShaderDataSize, + const std::string& Name = "" ); /** Creates the vertex shader and fragment shader from two files inside a pack */ - static ShaderProgram* New( Pack* Pack, const std::string& VertexShaderPath, - const std::string& FragmentShaderPath, - const std::string& Name = "" ); + static ShaderProgramPtr New( Pack* Pack, const std::string& VertexShaderPath, + const std::string& FragmentShaderPath, + const std::string& Name = "" ); /** Creates the vertex and fragment shader from an array of strings */ - static ShaderProgram* New( const char** VertexShaderData, const Uint32& NumLinesVS, - const char** FragmentShaderData, const Uint32& NumLinesFS, - const std::string& Name = "" ); + static ShaderProgramPtr New( const char** VertexShaderData, const Uint32& NumLinesVS, + const char** FragmentShaderData, const Uint32& NumLinesFS, + const std::string& Name = "" ); typedef std::function ShaderProgramReloadCb; virtual ~ShaderProgram(); /** Add a new shader */ - void addShader( Shader* Shader ); + void addShader( ShaderPtr shader ); /** Add a vector of shaders */ - void addShaders( const std::vector& Shaders ); + void addShaders( const std::vector& shaders ); virtual bool link(); @@ -151,7 +157,7 @@ class EE_API ShaderProgram { bool mValid; std::string mLinkLog; - std::vector mShaders; + std::vector mShaders; std::map mUniformLocations; std::map mAttributeLocations; @@ -159,15 +165,15 @@ class EE_API ShaderProgram { void init(); - void addToManager( const std::string& Name ); + void addToRegistry( const std::string& Name ); - void removeFromManager(); + void removeFromRegistry(); /** Creates an empty shader program */ ShaderProgram( const std::string& Name = "" ); /** Construct a program shader with a vector of shaders and link them. */ - ShaderProgram( const std::vector& Shaders, const std::string& Name = "" ); + ShaderProgram( const std::vector& Shaders, const std::string& Name = "" ); /** Constructor that creates a VertexShader from file and a Fragment Shader from file, and link * them. */ diff --git a/include/eepp/graphics/shaderprogrammanager.hpp b/include/eepp/graphics/shaderprogrammanager.hpp index b8c5c031d..4c9e91d62 100644 --- a/include/eepp/graphics/shaderprogrammanager.hpp +++ b/include/eepp/graphics/shaderprogrammanager.hpp @@ -3,26 +3,23 @@ #include #include - -#include +#include #include using namespace EE::System; namespace EE { namespace Graphics { -/** @brief The Shader Program Manager is a singleton class that manages all the instances of Shader - Programs instantiated. Releases the Shader Program instances automatically. So the user doesn't - need to release any Shader Program instance. */ -class EE_API ShaderProgramManager : public ResourceManager { - SINGLETON_DECLARE_HEADERS( ShaderProgramManager ) +/** Non-owning registry of shader programs associated with the active graphics context. */ +class EE_API ShaderProgramRegistry : public Container { + SINGLETON_DECLARE_HEADERS( ShaderProgramRegistry ) public: - virtual ~ShaderProgramManager(); + virtual ~ShaderProgramRegistry(); void reload(); protected: - ShaderProgramManager(); + ShaderProgramRegistry(); }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/vertexbuffer.hpp b/include/eepp/graphics/vertexbuffer.hpp index 4d42be7a4..dd360b6ce 100644 --- a/include/eepp/graphics/vertexbuffer.hpp +++ b/include/eepp/graphics/vertexbuffer.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -10,6 +11,9 @@ using namespace EE::System; namespace EE { namespace Graphics { +class VertexBuffer; +using VertexBufferUniquePtr = std::unique_ptr>; + /** @brief The vertex buffer class holds vertex data. The vertex position, colors, texture *coordinates and indexes. This is useful to accelerate and encapsulate data. */ @@ -27,14 +31,14 @@ class EE_API VertexBuffer { *extensions are supported ( almost for sure that it's supported ). More information here: *http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml */ - static VertexBuffer* New( const Uint32& vertexFlags = VERTEX_FLAGS_DEFAULT, - PrimitiveType drawType = PRIMITIVE_QUADS, - const Int32& reserveVertexSize = 0, const Int32& reserveIndexSize = 0, - VertexBufferUsageType usageType = VertexBufferUsageType::Static ); + static VertexBufferUniquePtr + New( const Uint32& vertexFlags = VERTEX_FLAGS_DEFAULT, PrimitiveType drawType = PRIMITIVE_QUADS, + const Int32& reserveVertexSize = 0, const Int32& reserveIndexSize = 0, + VertexBufferUsageType usageType = VertexBufferUsageType::Static ); /** Creates the simple vertex array implementation ( without VBOs or VAO ), which it's faster * for many cases. */ - static VertexBuffer* + static VertexBufferUniquePtr NewVertexArray( const Uint32& vertexFlags = VERTEX_FLAGS_DEFAULT, PrimitiveType drawType = PRIMITIVE_QUADS, const Int32& reserveVertexSize = 0, const Int32& reserveIndexSize = 0, @@ -215,7 +219,7 @@ class EE_API VertexBuffer { // Creates a rounded rectangle. Polygon2f Poly = Polygon2f::createRoundedRectangle( 0, 0, 256, 50 ); - VertexBuffer * VBO = VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); + auto VBO = VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); if ( NULL != VBO ) { // Upload the rounded rectangle data to the vertex buffer. diff --git a/include/eepp/graphics/vertexbuffermanager.hpp b/include/eepp/graphics/vertexbuffermanager.hpp index 4525ba6dd..3988793d7 100644 --- a/include/eepp/graphics/vertexbuffermanager.hpp +++ b/include/eepp/graphics/vertexbuffermanager.hpp @@ -10,16 +10,17 @@ using namespace EE::System; namespace EE { namespace Graphics { namespace Private { -class EE_API VertexBufferManager : public Container { - SINGLETON_DECLARE_HEADERS( VertexBufferManager ) +/** Non-owning registry of vertex buffers visible to the active graphics context. */ +class EE_API VertexBufferRegistry : public Container { + SINGLETON_DECLARE_HEADERS( VertexBufferRegistry ) public: - virtual ~VertexBufferManager(); + virtual ~VertexBufferRegistry(); void reload(); protected: - VertexBufferManager(); + VertexBufferRegistry(); }; }}} // namespace EE::Graphics::Private diff --git a/include/eepp/scene/scenenode.hpp b/include/eepp/scene/scenenode.hpp index ff1fa121f..2a56e74c1 100644 --- a/include/eepp/scene/scenenode.hpp +++ b/include/eepp/scene/scenenode.hpp @@ -1,14 +1,12 @@ #ifndef EE_SCENENODE_HPP #define EE_SCENENODE_HPP +#include #include #include #include #include -namespace EE { namespace Graphics { -class FrameBuffer; -}} // namespace EE::Graphics using namespace EE::Graphics; namespace EE { namespace Window { @@ -421,7 +419,7 @@ class EE_API SceneNode : public Node { EE::Window::Window* mWindow; ActionManager* mActionManager; - FrameBuffer* mFrameBuffer; + Graphics::FrameBufferUniquePtr mFrameBuffer; EventDispatcher* mEventDispatcher; CloseList mCloseList; Clock mClock; diff --git a/include/eepp/system.hpp b/include/eepp/system.hpp index 39d9982a6..5fb93e7f3 100644 --- a/include/eepp/system.hpp +++ b/include/eepp/system.hpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/include/eepp/system/resourcemanager.hpp b/include/eepp/system/resourcemanager.hpp deleted file mode 100644 index cd72f795d..000000000 --- a/include/eepp/system/resourcemanager.hpp +++ /dev/null @@ -1,411 +0,0 @@ -#ifndef EE_SYSTEMTRESOURCEMANAGER_HPP -#define EE_SYSTEMTRESOURCEMANAGER_HPP - -#include -#include -#include -#include -#include -#include - -namespace EE { namespace System { - -/** @brief A simple resource manager. It keeps a list of the resources, and free the instances of - * the resources when the manager is closed. Resources must implement getId() and getName() - * properties getId() is the string hash of getName(). - */ -template class ResourceManager { - public: - ResourceManager(); - - /** @brief The destructor will call destroy() and destroy all the resources added to the manager - */ - virtual ~ResourceManager(); - - /** @brief Add the resource to the resource manager - ** @param resource The resource to be managed by the manager */ - virtual T* add( T* resource ); - - /** @brief Removes the resource from the manager - ** @param resource The resource to remove - ** @param remove Indicates if the resource must be destroyed after being removed from the - *manager */ - bool remove( T* resource, bool remove = true ); - - /** @brief Removes the resource by its id - ** @see remove */ - bool removeById( const String::HashType& id, bool remove = true ); - - /** @brief Removes the resource by its name - ** @see remove */ - bool removeByName( const std::string& name, bool remove = true ); - - /** @returns A resource by its name. If not found returns NULL. */ - T* getByName( const std::string& name ); - - /** @returns A resource by its id. If not found returns NULL. */ - T* getById( const String::HashType& id ); - - /** @returns The number of resources added */ - Uint32 getCount(); - - /** @returns The number of resources that where added with the indicated name. */ - Uint32 getCount( const std::string& name ); - - /** @returns The number of resources that where added with the indicated id. */ - Uint32 getCount( const String::HashType& id ); - - /** @returns If the resource name exists in the resources list. */ - bool exists( const std::string& name ); - - /** @returns If the resource id exists in the resources list. */ - bool existsId( const String::HashType& id ); - - /** @brief Destroy all the resources added ( delete the instances of the resources ) */ - void destroy(); - - /** @brief Prints all the resources names added to the manager. */ - void printNames(); - - /** @returns A reference to the resources list of the manager. */ - UnorderedMap& getResources(); - - /** @brief Indicates if the resource manager is destroy the resources. */ - const bool& isDestroying() const; - - template void each( Predicate pred ) const { - for ( const auto& res : mResources ) - pred( res ); - } - - template void each( Predicate pred ) { - for ( auto& res : mResources ) - pred( res ); - } - - template T* findIf( Predicate pred ) const { - for ( const auto& res : mResources ) - if ( pred( res ) ) - return res.second; - return nullptr; - } - - template T* findIf( Predicate pred ) { - for ( auto& res : mResources ) - if ( pred( res ) ) - return res.second; - return nullptr; - } - - protected: - Mutex mMutex; - UnorderedMap mResources; - bool mIsDestroying; -}; - -template ResourceManager::ResourceManager() : mIsDestroying( false ) {} - -template const bool& ResourceManager::isDestroying() const { - return mIsDestroying; -} - -template ResourceManager::~ResourceManager() { - destroy(); -} - -template void ResourceManager::destroy() { - mIsDestroying = true; - - { - Lock l( mMutex ); - for ( auto& it : mResources ) { - T* res = it.second; - eeSAFE_DELETE( res ); - } - mResources.clear(); - } - - mIsDestroying = false; -} - -// This is not thread safe -template UnorderedMap& ResourceManager::getResources() { - return mResources; -} - -template T* ResourceManager::add( T* resource ) { - if ( NULL != resource ) { - if ( !existsId( resource->getId() ) ) { - Lock l( mMutex ); - mResources[resource->getId()] = resource; - - return resource; - } else { - std::string realName( resource->getName() ); - Uint32 c = 1; - - while ( existsId( resource->getId() ) ) { - c++; - resource->setName( realName + String::toString( c ) ); - } - - return add( resource ); - } - - Lock l( mMutex ); - mResources[resource->getId()] = resource; - return resource; - } - return NULL; -} - -template bool ResourceManager::remove( T* resource, bool remove ) { - if ( NULL != resource ) { - { - - Lock l( mMutex ); - mResources.erase( resource->getId() ); - } - if ( remove ) - eeSAFE_DELETE( resource ); - - return true; - } - - return false; -} - -template bool ResourceManager::removeById( const String::HashType& id, bool _remove ) { - return remove( getById( id ), _remove ); -} - -template bool ResourceManager::removeByName( const std::string& name, bool _remove ) { - return remove( getByName( name ), _remove ); -} - -template bool ResourceManager::exists( const std::string& name ) { - return existsId( String::hash( name ) ); -} - -template bool ResourceManager::existsId( const String::HashType& id ) { - Lock l( mMutex ); - return mResources.find( id ) != mResources.end(); -} - -template T* ResourceManager::getByName( const std::string& name ) { - return getById( String::hash( name ) ); -} - -template T* ResourceManager::getById( const String::HashType& id ) { - Lock l( mMutex ); - auto it = mResources.find( id ); - return it != mResources.end() ? it->second : nullptr; -} - -template void ResourceManager::printNames() { - Lock l( mMutex ); - for ( auto& it : mResources ) { - eePRINTL( "'%s'", it.second->getName().c_str() ); - } -} - -template Uint32 ResourceManager::getCount() { - Lock l( mMutex ); - return (Uint32)mResources.size(); -} - -template Uint32 ResourceManager::getCount( const String::HashType& id ) { - return existsId( id ) ? 1 : 0; -} - -template Uint32 ResourceManager::getCount( const std::string& name ) { - return getCount( String::hash( name ) ); -} - -/** @brief A simple resource manager. It keeps a list of the resources, and free the instances of - * the resources when the manager is closed. Resources must implement getId() and getName() - * properties getId() is the string hash of getName(). Allows repeated keys. - */ -template class ResourceManagerMulti { - public: - /** @param UniqueId Indicates if the resources id must be unique */ - ResourceManagerMulti(); - - /** @brief The destructor will call destroy() and destroy all the resources added to the manager - */ - virtual ~ResourceManagerMulti(); - - /** @brief Add the resource to the resource manager - ** @param resource The resource to be managed by the manager */ - virtual T* add( T* resource ); - - /** @brief Removes the resource from the manager - ** @param resource The resource to remove - ** @param remove Indicates if the resource must be destroyed after being removed from the - *manager */ - bool remove( T* resource, bool remove = true ); - - /** @brief Removes the resource by its id - ** @see remove */ - bool removeById( const String::HashType& id, bool remove = true ); - - /** @brief Removes the resource by its name - ** @see remove */ - bool removeByName( const std::string& name, bool remove = true ); - - /** @returns A resource by its name. If not found returns NULL. */ - T* getByName( const std::string& name ); - - /** @returns A resource by its id. If not found returns NULL. */ - T* getById( const String::HashType& id ); - - /** @returns The number of resources added */ - Uint32 getCount(); - - /** @returns The number of resources that where added with the indicated name. */ - Uint32 getCount( const std::string& name ); - - /** @returns The number of resources that where added with the indicated id. */ - Uint32 getCount( const String::HashType& id ); - - /** @returns If the resource name exists in the resources list. */ - bool exists( const std::string& name ); - - /** @returns If the resource id exists in the resources list. */ - bool existsId( const String::HashType& id ); - - /** @brief Destroy all the resources added ( delete the instances of the resources ) */ - void destroy(); - - /** @brief Prints all the resources names added to the manager. */ - void printNames(); - - /** @returns A reference to the resources list of the manager. */ - std::unordered_multimap& getResources(); - - /** @brief Indicates if the resource manager is destroy the resources. */ - const bool& isDestroying() const; - - protected: - Mutex mMutex; - std::unordered_multimap mResources; - bool mIsDestroying; -}; - -template ResourceManagerMulti::ResourceManagerMulti() : mIsDestroying( false ) {} - -template const bool& ResourceManagerMulti::isDestroying() const { - return mIsDestroying; -} - -template ResourceManagerMulti::~ResourceManagerMulti() { - destroy(); -} - -template void ResourceManagerMulti::destroy() { - mIsDestroying = true; - - { - Lock l( mMutex ); - for ( auto& it : mResources ) { - T* res = it.second; - eeSAFE_DELETE( res ); - } - - mResources.clear(); - } - - mIsDestroying = false; -} - -template -std::unordered_multimap& ResourceManagerMulti::getResources() { - return mResources; -} - -template T* ResourceManagerMulti::add( T* resource ) { - if ( NULL != resource ) { - Lock l( mMutex ); - mResources.insert( std::pair( resource->getId(), resource ) ); - return resource; - } - return NULL; -} - -template bool ResourceManagerMulti::remove( T* resource, bool remove ) { - if ( NULL != resource ) { - { - Lock l( mMutex ); - auto range = mResources.equal_range( resource->getId() ); - auto it = range.first; - while ( it != range.second ) { - if ( it->second == resource ) { - mResources.erase( it ); - break; - } - it++; - } - } - - if ( remove ) - eeSAFE_DELETE( resource ); - - return true; - } - - return false; -} - -template -bool ResourceManagerMulti::removeById( const String::HashType& id, bool _remove ) { - return remove( getById( id ), _remove ); -} - -template -bool ResourceManagerMulti::removeByName( const std::string& name, bool _remove ) { - return remove( getByName( name ), _remove ); -} - -template bool ResourceManagerMulti::exists( const std::string& name ) { - return existsId( String::hash( name ) ); -} - -template bool ResourceManagerMulti::existsId( const String::HashType& id ) { - Lock l( mMutex ); - return mResources.find( id ) != mResources.end(); -} - -template T* ResourceManagerMulti::getByName( const std::string& name ) { - return getById( String::hash( name ) ); -} - -template T* ResourceManagerMulti::getById( const String::HashType& id ) { - Lock l( mMutex ); - auto it = mResources.find( id ); - return it != mResources.end() ? it->second : nullptr; -} - -template void ResourceManagerMulti::printNames() { - Lock l( mMutex ); - for ( auto& it : mResources ) { - eePRINTL( "'%s'", it.second->getName().c_str() ); - } -} - -template Uint32 ResourceManagerMulti::getCount() { - Lock l( mMutex ); - return (Uint32)mResources.size(); -} - -template Uint32 ResourceManagerMulti::getCount( const String::HashType& id ) { - Lock l( mMutex ); - return mResources.count( id ); -} - -template Uint32 ResourceManagerMulti::getCount( const std::string& name ) { - return getCount( String::hash( name ) ); -} - -}} // namespace EE::System - -#endif diff --git a/include/eepp/ui/iconmanager.hpp b/include/eepp/ui/iconmanager.hpp index 91274f898..b404a6627 100644 --- a/include/eepp/ui/iconmanager.hpp +++ b/include/eepp/ui/iconmanager.hpp @@ -13,8 +13,9 @@ class UIIconTheme; class EE_API IconManager { public: - static UIIconTheme* init( const std::string& iconThemeName, FontTrueType* remixIconFont, - FontTrueType* noniconFont, FontTrueType* codIconFont ); + static ResourcePtr init( const std::string& iconThemeName, + FontTrueType* remixIconFont, FontTrueType* noniconFont, + FontTrueType* codIconFont ); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uibackgrounddrawable.hpp b/include/eepp/ui/uibackgrounddrawable.hpp index b1957e1d1..cf6d0bf85 100644 --- a/include/eepp/ui/uibackgrounddrawable.hpp +++ b/include/eepp/ui/uibackgrounddrawable.hpp @@ -2,6 +2,7 @@ #define EE_UI_UIBACKGROUNDDRAWABLE_HPP #include +#include #include using namespace EE::Graphics; @@ -63,7 +64,7 @@ class EE_API UIBackgroundDrawable : public Drawable { protected: const UINode* mOwner; BorderRadiuseStr mRadiusesStr; - VertexBuffer* mVertexBuffer; + Graphics::VertexBufferUniquePtr mVertexBuffer; Sizef mSize; BorderRadiuses mRadiuses; bool mNeedsUpdate; diff --git a/include/eepp/ui/uiborderdrawable.hpp b/include/eepp/ui/uiborderdrawable.hpp index 9f2b50577..7cda1cabc 100644 --- a/include/eepp/ui/uiborderdrawable.hpp +++ b/include/eepp/ui/uiborderdrawable.hpp @@ -2,6 +2,7 @@ #define EE_UI_UIBORDERDRAWABLE_HPP #include +#include #include #include @@ -87,7 +88,7 @@ class EE_API UIBorderDrawable : public Drawable { protected: const UINode* mOwner; - VertexBuffer* mVertexBuffer; + Graphics::VertexBufferUniquePtr mVertexBuffer; mutable Borders mBorders; BorderStr mBorderStr; BorderType mBorderType; diff --git a/include/eepp/ui/uiicon.hpp b/include/eepp/ui/uiicon.hpp index 8028086aa..2fe78dce3 100644 --- a/include/eepp/ui/uiicon.hpp +++ b/include/eepp/ui/uiicon.hpp @@ -12,9 +12,13 @@ using namespace EE::Graphics; namespace EE { namespace UI { +class UIIcon; +using UIIconPtr = ResourcePtr; +using UIIconWeakPtr = ResourceWeakPtr; + class EE_API UIIcon { public: - static UIIcon* New( const std::string& name ); + static UIIconPtr New( const std::string& name ); virtual ~UIIcon(); @@ -41,7 +45,7 @@ class EE_API UIIcon { class EE_API UIGlyphIcon : public UIIcon { public: - static UIIcon* New( const std::string& name, FontTrueType* font, const Uint32& codePoint ); + static UIIconPtr New( const std::string& name, FontTrueType* font, const Uint32& codePoint ); virtual ~UIGlyphIcon(); @@ -57,7 +61,7 @@ class EE_API UIGlyphIcon : public UIIcon { class EE_API UISVGIcon : public UIIcon { public: - static UIIcon* New( const std::string& name, const std::string& svgXML ); + static UIIconPtr New( const std::string& name, const std::string& svgXML ); virtual ~UISVGIcon(); diff --git a/include/eepp/ui/uiicontheme.hpp b/include/eepp/ui/uiicontheme.hpp index 853cd9778..f6594a208 100644 --- a/include/eepp/ui/uiicontheme.hpp +++ b/include/eepp/ui/uiicontheme.hpp @@ -9,15 +9,19 @@ using namespace EE::Graphics; namespace EE { namespace UI { +class UIIconTheme; +using UIIconThemePtr = ResourcePtr; +using UIIconThemeWeakPtr = ResourceWeakPtr; + class EE_API UIIconTheme { public: - static UIIconTheme* New( const std::string& name ); + static UIIconThemePtr New( const std::string& name ); ~UIIconTheme(); - UIIconTheme* add( UIIcon* icon ); + UIIconTheme* add( UIIconPtr icon ); - UIIconTheme* add( const std::unordered_map& icons ); + UIIconTheme* add( const std::unordered_map& icons ); const std::string& getName() const; @@ -25,7 +29,7 @@ class EE_API UIIconTheme { protected: std::string mName; - std::unordered_map mIcons; + std::unordered_map mIcons; UIIconTheme( const std::string& name ); }; diff --git a/include/eepp/ui/uiiconthememanager.hpp b/include/eepp/ui/uiiconthememanager.hpp index d358d0d68..b9028a8ec 100644 --- a/include/eepp/ui/uiiconthememanager.hpp +++ b/include/eepp/ui/uiiconthememanager.hpp @@ -17,15 +17,15 @@ class EE_API UIIconThemeManager { ~UIIconThemeManager(); - UIIconThemeManager* add( UIIconTheme* iconTheme ); + UIIconThemeManager* add( UIIconThemePtr iconTheme ); UIIconTheme* getCurrentTheme() const; - UIIconThemeManager* setCurrentTheme( UIIconTheme* currentTheme ); + UIIconThemeManager* setCurrentTheme( UIIconThemePtr currentTheme ); UIIconTheme* getFallbackTheme() const; - UIIconThemeManager* setFallbackTheme( UIIconTheme* fallbackTheme ); + UIIconThemeManager* setFallbackTheme( UIIconThemePtr fallbackTheme ); UIIcon* findIcon( const std::string& name ); @@ -36,7 +36,7 @@ class EE_API UIIconThemeManager { void remove( UIIconTheme* iconTheme ); protected: - std::vector mIconThemes; + std::vector mIconThemes; UIIconTheme* mCurrentTheme{ nullptr }; UIIconTheme* mFallbackTheme{ nullptr }; UIThemeManager* mFallbackThemeManager{ nullptr }; diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index d24270fbd..855c1a061 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -850,12 +850,12 @@ class EE_API UINode : public Node { void setThemeByName( const std::string& Theme ); /** - * @brief Sets the theme for this node. + * @brief Sets the borrowed theme used by this node. * - * Applies the specified UITheme to this node, affecting its visual appearance - * through skins and styles. + * The node does not retain @p Theme. Its owner, normally the containing scene's UIThemeManager, + * must keep the theme alive until this node switches themes or is destroyed. * - * @param Theme Pointer to the UITheme to apply. + * @param Theme Borrowed theme to apply, or null to use no explicit theme. */ virtual void setTheme( UITheme* Theme ); diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 637ffbe7f..3252ef752 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -797,11 +797,15 @@ class EE_API UISceneNode : public SceneNode { UISceneNode* setResourceScope( Graphics::ResourceScopePtr resourceScope ); /** - * @brief Sets the theme for the entire UI scene. + * @brief Applies a borrowed theme to the widgets in this UI scene. * - * Applies the theme to the root widget and all children. + * Each affected widget stores a non-owning `UITheme*`; this function does not retain @p theme. + * The theme must therefore outlive every widget using it. Normally callers establish that + * lifetime first by adding the corresponding `UIThemePtr` to this scene's UIThemeManager or by + * setting it as the manager's default theme. * - * @param theme Pointer to the UITheme to set. + * @param theme Borrowed theme to apply recursively. May be null to clear explicit widget + * themes. */ void setTheme( UITheme* theme ); @@ -1199,11 +1203,13 @@ class EE_API UISceneNode : public SceneNode { void resetTooltips( Node* node ); /** - * @brief Applies a theme to a node and its subtree. + * @brief Applies a borrowed theme to the widgets below a node. * - * Recursively applies the specified UITheme to all widgets in the subtree. + * Each affected widget stores a non-owning pointer. This function does not retain @p theme; an + * owner such as this scene's UIThemeManager must keep it alive for the complete period in which + * the subtree uses it. * - * @param theme Pointer to the UITheme to apply. + * @param theme Borrowed theme to apply. May be null to clear explicit widget themes. * @param to The root node of the subtree to theme. */ void setTheme( UITheme* theme, Node* to ); diff --git a/include/eepp/ui/uiskin.hpp b/include/eepp/ui/uiskin.hpp index 3ab26de28..a58c7a7c0 100644 --- a/include/eepp/ui/uiskin.hpp +++ b/include/eepp/ui/uiskin.hpp @@ -8,7 +8,7 @@ namespace EE { namespace UI { class EE_API UISkin : public StateListDrawable { public: - static UISkin* New( const std::string& name = "" ); + static ResourcePtr New( const std::string& name = "" ); virtual ~UISkin(); diff --git a/include/eepp/ui/uitheme.hpp b/include/eepp/ui/uitheme.hpp index 97680db64..87f35325d 100644 --- a/include/eepp/ui/uitheme.hpp +++ b/include/eepp/ui/uitheme.hpp @@ -2,11 +2,11 @@ #define EE_UICUITHEME_HPP #include -#include #include #include #include #include +#include #include namespace EE { namespace Graphics { @@ -21,35 +21,37 @@ namespace EE { namespace UI { class UIIcon; class UIIconTheme; -class EE_API UITheme : protected ResourceManagerMulti { +class UITheme; +using UIThemePtr = ResourcePtr; +using UIThemeWeakPtr = ResourceWeakPtr; +using UISkinPtr = ResourcePtr; + +class EE_API UITheme { public: - using ResourceManagerMulti::getById; - using ResourceManagerMulti::getByName; - using ResourceManagerMulti::exists; - using ResourceManagerMulti::existsId; + static UIThemePtr New( const std::string& name, const std::string& abbr, + Graphics::Font* defaultFont = NULL ); - static UITheme* New( const std::string& name, const std::string& abbr, - Graphics::Font* defaultFont = NULL ); + static UIThemePtr load( const std::string& name, const std::string& abbr, + const std::string& textureAtlasPath, Graphics::Font* defaultFont, + const std::string& styleSheetPath ); - static UITheme* load( const std::string& name, const std::string& abbr, - const std::string& textureAtlasPath, Graphics::Font* defaultFont, - const std::string& styleSheetPath ); + static UIThemePtr loadFromString( const std::string& name, const std::string& abbr, + const std::string& textureAtlasPath, + Graphics::Font* defaultFont, + const std::string& styleSheetString ); - static UITheme* loadFromString( const std::string& name, const std::string& abbr, - const std::string& textureAtlasPath, - Graphics::Font* defaultFont, - const std::string& styleSheetString ); + static UIThemePtr loadFromTextureAtlas( UIThemePtr theme, + Graphics::TextureAtlasPtr textureAtlas ); - static UITheme* loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlasPtr textureAtlas ); + static UIThemePtr loadFromTextureAtlas( Graphics::TextureAtlasPtr textureAtlas, + const std::string& Name, const std::string& NameAbbr ); - static UITheme* loadFromTextureAtlas( Graphics::TextureAtlasPtr textureAtlas, - const std::string& Name, const std::string& NameAbbr ); + static UIThemePtr loadFromDirectory( UIThemePtr theme, const std::string& Path, + const Float& pixelDensity = 1 ); - static UITheme* loadFromDirectory( UITheme* tTheme, const std::string& Path, - const Float& pixelDensity = 1 ); - - static UITheme* loadFromDirectory( const std::string& Path, const std::string& Name, - const std::string& NameAbbr, const Float& pixelDensity = 1 ); + static UIThemePtr loadFromDirectory( const std::string& Path, const std::string& Name, + const std::string& NameAbbr, + const Float& pixelDensity = 1 ); virtual ~UITheme(); @@ -61,7 +63,15 @@ class EE_API UITheme : protected ResourceManagerMulti { const std::string& getAbbr() const; - virtual UISkin* add( UISkin* Resource ); + UISkin* add( UISkinPtr skin ); + + UISkin* getById( const String::HashType& id ) const; + + UISkin* getByName( const std::string& name ) const; + + bool exists( const std::string& name ) const; + + bool existsId( const String::HashType& id ) const; Graphics::TextureAtlas* getTextureAtlas() const; @@ -104,7 +114,8 @@ class EE_API UITheme : protected ResourceManagerMulti { Float mDefaultFontSize; CSS::StyleSheet mStyleSheet; std::string mStyleSheetPath; - UIIconTheme* mIconTheme; + UIIconThemePtr mIconTheme; + UnorderedMap> mSkins; Graphics::ResourceCatalogPtr mResourceCatalog; void setTextureAtlas( Graphics::TextureAtlasPtr textureAtlas ); diff --git a/include/eepp/ui/uithememanager.hpp b/include/eepp/ui/uithememanager.hpp index f37da5033..95c846fe1 100644 --- a/include/eepp/ui/uithememanager.hpp +++ b/include/eepp/ui/uithememanager.hpp @@ -9,19 +9,19 @@ namespace EE { namespace UI { class UINode; -class EE_API UIThemeManager : public ResourceManager { +class EE_API UIThemeManager { public: static UIThemeManager* New(); virtual ~UIThemeManager(); - virtual UITheme* add( UITheme* theme ); + UITheme* add( UIThemePtr theme ); - bool remove( UITheme* theme, bool destroy = true ); + bool remove( UITheme* theme ); - bool removeById( const String::HashType& id, bool destroy = true ); + bool removeById( const String::HashType& id ); - bool removeByName( const std::string& name, bool destroy = true ); + bool removeByName( const std::string& name ); UIThemeManager* setResourceScope( Graphics::ResourceScopePtr resourceScope ); @@ -35,10 +35,19 @@ class EE_API UIThemeManager : public ResourceManager { UIThemeManager* setDefaultTheme( UITheme* Theme ); + UIThemeManager* setDefaultTheme( UIThemePtr theme ); + UIThemeManager* setDefaultTheme( const std::string& Theme ); UITheme* getDefaultTheme() const; + /** @return An owning handle to the default theme, or an empty handle when unset. */ + UIThemePtr getDefaultThemeHandle() const; + + UITheme* getById( const String::HashType& id ) const; + + UITheme* getByName( const std::string& name ) const; + UIThemeManager* applyDefaultTheme( UINode* node ); UIThemeManager* setAutoApplyDefaultTheme( const bool& apply ); @@ -72,7 +81,8 @@ class EE_API UIThemeManager : public ResourceManager { protected: Font* mFont; Float mFontSize; - UITheme* mThemeDefault; + UIThemePtr mThemeDefault; + UnorderedMap mThemes; bool mAutoApplyDefaultTheme; bool mEnableDefaultEffects; diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index fb9db77ff..002d99949 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -130,12 +130,14 @@ class EE_API UIWidget : public UINode { virtual UIWidget* setAnchors( const Uint32& flags ); /** - * @brief Sets the theme for this widget. + * @brief Sets the borrowed theme used by this widget. * - * Applies the specified theme to the widget, affecting its visual appearance. - * The theme controls colors, fonts, borders, and other visual properties. + * The widget stores @p Theme as a non-owning pointer and does not increment its reference + * count. The theme must outlive this use; normally it is retained by the containing scene's + * UIThemeManager. This keeps per-widget theme access inexpensive while centralizing ownership + * at the scene boundary. * - * @param Theme Pointer to the UITheme to apply. + * @param Theme Borrowed theme to apply, or null to use no explicit theme. */ virtual void setTheme( UITheme* Theme ); diff --git a/include/eepp/ui/uiwindow.hpp b/include/eepp/ui/uiwindow.hpp index cf829ae07..bbb3a3473 100644 --- a/include/eepp/ui/uiwindow.hpp +++ b/include/eepp/ui/uiwindow.hpp @@ -220,7 +220,7 @@ class EE_API UIWindow : public UIWidget { RESIZE_TOPRIGHT }; - FrameBuffer* mFrameBuffer; + Graphics::FrameBufferUniquePtr mFrameBuffer; StyleConfig mStyleConfig; UIWidget* mWindowDecoration; UIWidget* mBorderLeft; diff --git a/src/eepp/graphics/framebuffer.cpp b/src/eepp/graphics/framebuffer.cpp index ddd2642c6..b28294c69 100644 --- a/src/eepp/graphics/framebuffer.cpp +++ b/src/eepp/graphics/framebuffer.cpp @@ -14,14 +14,15 @@ namespace EE { namespace Graphics { static std::vector sFBOActiveViews; -FrameBuffer* FrameBuffer::New( const Uint32& Width, const Uint32& Height, bool StencilBuffer, - bool DepthBuffer, bool useColorBuffer, const Uint32& channels, - EE::Window::Window* window ) { +FrameBufferUniquePtr FrameBuffer::New( const Uint32& Width, const Uint32& Height, + bool StencilBuffer, bool DepthBuffer, bool useColorBuffer, + const Uint32& channels, EE::Window::Window* window ) { if ( FrameBufferFBO::isSupported() ) - return eeNew( FrameBufferFBO, ( Width, Height, StencilBuffer, DepthBuffer, useColorBuffer, - channels, window ) ); + return FrameBufferUniquePtr( + eeNew( FrameBufferFBO, ( Width, Height, StencilBuffer, DepthBuffer, useColorBuffer, + channels, window ) ) ); Log::warning( "FBO not supported" ); - return NULL; + return {}; } FrameBuffer::FrameBuffer( EE::Window::Window* window ) : @@ -38,11 +39,12 @@ FrameBuffer::FrameBuffer( EE::Window::Window* window ) : mWindow = Engine::instance()->getCurrentWindow(); } - FrameBufferManager::instance()->add( this ); + FrameBufferRegistry::instance()->add( this ); } FrameBuffer::~FrameBuffer() { - FrameBufferManager::instance()->remove( this ); + if ( FrameBufferRegistry::existsSingleton() ) + FrameBufferRegistry::instance()->remove( this ); } const TexturePtr& FrameBuffer::getTexture() const { diff --git a/src/eepp/graphics/framebuffermanager.cpp b/src/eepp/graphics/framebuffermanager.cpp index b1b7688a6..955a08899 100644 --- a/src/eepp/graphics/framebuffermanager.cpp +++ b/src/eepp/graphics/framebuffermanager.cpp @@ -3,13 +3,13 @@ namespace EE { namespace Graphics { namespace Private { -SINGLETON_DECLARE_IMPLEMENTATION( FrameBufferManager ) +SINGLETON_DECLARE_IMPLEMENTATION( FrameBufferRegistry ) -FrameBufferManager::FrameBufferManager() {} +FrameBufferRegistry::FrameBufferRegistry() {} -FrameBufferManager::~FrameBufferManager() {} +FrameBufferRegistry::~FrameBufferRegistry() {} -FrameBuffer* FrameBufferManager::getCurrentlyBound() { +FrameBuffer* FrameBufferRegistry::getCurrentlyBound() { int curFB; glGetIntegerv( GL_FRAMEBUFFER_BINDING, &curFB ); @@ -25,11 +25,11 @@ FrameBuffer* FrameBufferManager::getCurrentlyBound() { return NULL; } -FrameBuffer* FrameBufferManager::getFromName( const std::string& name ) { +FrameBuffer* FrameBufferRegistry::getFromName( const std::string& name ) { return getFromId( String::hash( name ) ); } -FrameBuffer* FrameBufferManager::getFromId( const String::HashType& id ) { +FrameBuffer* FrameBufferRegistry::getFromId( const String::HashType& id ) { for ( auto& fb : mResources ) { if ( fb->getId() == id ) { return fb; diff --git a/src/eepp/graphics/primitivedrawable.cpp b/src/eepp/graphics/primitivedrawable.cpp index ec51382be..4cb0547ea 100644 --- a/src/eepp/graphics/primitivedrawable.cpp +++ b/src/eepp/graphics/primitivedrawable.cpp @@ -12,11 +12,9 @@ PrimitiveDrawable::PrimitiveDrawable( Type drawableType ) : mLineWidth( 1.f ), mNeedsUpdate( true ), mRecreateVertexBuffer( true ), - mVertexBuffer( NULL ) {} + mVertexBuffer( nullptr ) {} -PrimitiveDrawable::~PrimitiveDrawable() { - eeSAFE_DELETE( mVertexBuffer ); -} +PrimitiveDrawable::~PrimitiveDrawable() = default; void PrimitiveDrawable::draw( const Vector2f& position, const Sizef& ) { if ( mPosition != position ) { @@ -109,7 +107,7 @@ void PrimitiveDrawable::onPositionChange() { void PrimitiveDrawable::prepareVertexBuffer( const PrimitiveType& drawableType ) { if ( mRecreateVertexBuffer ) { - eeSAFE_DELETE( mVertexBuffer ); + mVertexBuffer.reset(); mVertexBuffer = VertexBuffer::NewVertexArray( VERTEX_FLAGS_PRIMITIVE, drawableType ); mRecreateVertexBuffer = false; } diff --git a/src/eepp/graphics/renderer/renderergl3.cpp b/src/eepp/graphics/renderer/renderergl3.cpp index 3a681bb3b..9c082a64d 100644 --- a/src/eepp/graphics/renderer/renderergl3.cpp +++ b/src/eepp/graphics/renderer/renderergl3.cpp @@ -122,12 +122,12 @@ void RendererGL3::reloadShader( ShaderProgram* Shader ) { } void RendererGL3::setShader( const EEGL3_SHADERS& Shader ) { - setShader( mShaders[Shader] ); + setShader( mShaders[Shader].get() ); } void RendererGL3::setShader( ShaderProgram* Shader ) { if ( NULL == Shader ) { - Shader = mShaders[EEGL3_SHADER_BASE]; + Shader = mShaders[EEGL3_SHADER_BASE].get(); } if ( mCurShader == Shader ) { diff --git a/src/eepp/graphics/renderer/renderergl3cp.cpp b/src/eepp/graphics/renderer/renderergl3cp.cpp index 96244aa7e..af5bf5cf1 100644 --- a/src/eepp/graphics/renderer/renderergl3cp.cpp +++ b/src/eepp/graphics/renderer/renderergl3cp.cpp @@ -134,7 +134,7 @@ void RendererGL3CP::init() { clientActiveTexture( GL_TEXTURE0 ); - setShader( mShaders[EEGL3CP_SHADER_BASE] ); + setShader( mShaders[EEGL3CP_SHADER_BASE].get() ); mLoaded = true; } @@ -154,12 +154,12 @@ void RendererGL3CP::reloadShader( ShaderProgram* Shader ) { } void RendererGL3CP::setShader( const EEGL3CP_SHADERS& Shader ) { - setShader( mShaders[Shader] ); + setShader( mShaders[Shader].get() ); } void RendererGL3CP::setShader( ShaderProgram* Shader ) { if ( NULL == Shader ) { - Shader = mShaders[EEGL3CP_SHADER_BASE]; + Shader = mShaders[EEGL3CP_SHADER_BASE].get(); } if ( mCurShader == Shader ) { diff --git a/src/eepp/graphics/renderer/renderergles2.cpp b/src/eepp/graphics/renderer/renderergles2.cpp index aa7911a50..83de668b1 100644 --- a/src/eepp/graphics/renderer/renderergles2.cpp +++ b/src/eepp/graphics/renderer/renderergles2.cpp @@ -155,12 +155,12 @@ void RendererGLES2::reloadShader( ShaderProgram* Shader ) { } void RendererGLES2::setShader( const EEGLES2_SHADERS& Shader ) { - setShader( mShaders[Shader] ); + setShader( mShaders[Shader].get() ); } void RendererGLES2::checkLocalShader() { for ( Uint32 i = 0; i < EEGLES2_SHADERS_COUNT; i++ ) { - if ( mShaders[i] == mCurShader ) { + if ( mShaders[i].get() == mCurShader ) { mCurShaderLocal = true; return; } @@ -171,7 +171,7 @@ void RendererGLES2::checkLocalShader() { void RendererGLES2::setShader( ShaderProgram* Shader ) { if ( NULL == Shader ) { - Shader = mShaders[EEGLES2_SHADER_BASE]; + Shader = mShaders[EEGLES2_SHADER_BASE].get(); } if ( mCurShader == Shader ) { @@ -432,7 +432,7 @@ void RendererGLES2::texCoordPointer( int size, unsigned int type, int stride, co unsigned int /*allocate*/ ) { if ( mCurShaderLocal ) { if ( 1 == mTexActive ) { - if ( mCurShader == mShaders[EEGLES2_SHADER_PRIMITIVE] ) { + if ( mCurShader == mShaders[EEGLES2_SHADER_PRIMITIVE].get() ) { if ( mClippingEnabled ) { setShader( EEGLES2_SHADER_CLIPPED ); } else if ( mPointSpriteEnabled ) { diff --git a/src/eepp/graphics/resourcecatalog.cpp b/src/eepp/graphics/resourcecatalog.cpp index bc4339ef0..71597f1cc 100644 --- a/src/eepp/graphics/resourcecatalog.cpp +++ b/src/eepp/graphics/resourcecatalog.cpp @@ -127,6 +127,31 @@ void ResourceCatalog::publishFont( std::string key, FontPtr font ) { previous.reset(); } +void ResourceCatalog::publishShaderProgram( ResourceKey key, ShaderProgramPtr program ) { + publishShaderProgram( key.value(), std::move( program ) ); +} + +void ResourceCatalog::publishShaderProgram( std::string key, ShaderProgramPtr program ) { + if ( key.empty() ) + return; + if ( !program ) { + eraseShaderProgram( key ); + return; + } + ShaderProgramPtr previous; + { + Lock lock( mMutex ); + auto it = mShaderPrograms.find( key ); + if ( it == mShaderPrograms.end() ) { + mShaderPrograms.emplace( std::move( key ), std::move( program ) ); + return; + } + previous = std::move( it->second ); + it->second = std::move( program ); + } + previous.reset(); +} + TexturePtr ResourceCatalog::findTexture( const ResourceKey& key ) const { return findTexture( key.value() ); } @@ -197,6 +222,25 @@ std::vector ResourceCatalog::getFonts() const { return fonts; } +ShaderProgramPtr ResourceCatalog::findShaderProgram( const ResourceKey& key ) const { + return findShaderProgram( key.value() ); +} + +ShaderProgramPtr ResourceCatalog::findShaderProgram( const std::string& key ) const { + Lock lock( mMutex ); + auto it = mShaderPrograms.find( key ); + return it != mShaderPrograms.end() ? it->second : ShaderProgramPtr{}; +} + +std::vector ResourceCatalog::getShaderPrograms() const { + std::vector programs; + Lock lock( mMutex ); + programs.reserve( mShaderPrograms.size() ); + for ( const auto& program : mShaderPrograms ) + programs.emplace_back( program.second ); + return programs; +} + bool ResourceCatalog::erase( const ResourceKey& key ) { return erase( key.value() ); } @@ -298,6 +342,24 @@ bool ResourceCatalog::eraseFont( Font* font ) { return true; } +bool ResourceCatalog::eraseShaderProgram( const ResourceKey& key ) { + return eraseShaderProgram( key.value() ); +} + +bool ResourceCatalog::eraseShaderProgram( const std::string& key ) { + ShaderProgramPtr program; + { + Lock lock( mMutex ); + auto it = mShaderPrograms.find( key ); + if ( it == mShaderPrograms.end() ) + return false; + program = std::move( it->second ); + mShaderPrograms.erase( it ); + } + program.reset(); + return true; +} + void ResourceCatalog::clear() { UnorderedMap textures; UnorderedMap drawables; @@ -305,6 +367,7 @@ void ResourceCatalog::clear() { UnorderedMap atlases; UnorderedMap fonts; UnorderedMap fontsById; + UnorderedMap shaderPrograms; { Lock lock( mMutex ); textures = std::move( mTextures ); @@ -313,6 +376,7 @@ void ResourceCatalog::clear() { atlases = std::move( mAtlases ); fonts = std::move( mFonts ); fontsById = std::move( mFontsById ); + shaderPrograms = std::move( mShaderPrograms ); } textures.clear(); @@ -321,11 +385,13 @@ void ResourceCatalog::clear() { atlases.clear(); fonts.clear(); fontsById.clear(); + shaderPrograms.clear(); } std::size_t ResourceCatalog::size() const { Lock lock( mMutex ); - return mTextures.size() + mDrawables.size() + mAtlases.size() + mFonts.size(); + return mTextures.size() + mDrawables.size() + mAtlases.size() + mFonts.size() + + mShaderPrograms.size(); } }} // namespace EE::Graphics diff --git a/src/eepp/graphics/resourcescope.cpp b/src/eepp/graphics/resourcescope.cpp index 674473f69..1631ccf14 100644 --- a/src/eepp/graphics/resourcescope.cpp +++ b/src/eepp/graphics/resourcescope.cpp @@ -142,6 +142,31 @@ std::vector ResourceScope::getFonts() const { return fonts; } +ShaderProgramPtr ResourceScope::findShaderProgram( const ResourceKey& key ) const { + return findShaderProgram( key.value() ); +} + +ShaderProgramPtr ResourceScope::findShaderProgram( const std::string& key ) const { + if ( ShaderProgramPtr program = mLocalCatalog->findShaderProgram( key ) ) + return program; + Lock lock( mMutex ); + for ( const ResourceCatalogPtr& catalog : mImports ) { + if ( ShaderProgramPtr program = catalog->findShaderProgram( key ) ) + return program; + } + return {}; +} + +std::vector ResourceScope::getShaderPrograms() const { + std::vector programs = mLocalCatalog->getShaderPrograms(); + Lock lock( mMutex ); + for ( const ResourceCatalogPtr& catalog : mImports ) { + auto imported = catalog->getShaderPrograms(); + programs.insert( programs.end(), imported.begin(), imported.end() ); + } + return programs; +} + std::vector ResourceScope::findTextureRegionsByPattern( const std::string& name, const std::string& extension, TextureAtlas* searchInTextureAtlas ) const { @@ -311,6 +336,14 @@ void ResourceScope::publishLocalFont( std::string key, FontPtr font ) { mLocalCatalog->publishFont( std::move( key ), std::move( font ) ); } +void ResourceScope::publishLocalShaderProgram( ResourceKey key, ShaderProgramPtr program ) { + publishLocalShaderProgram( key.value(), std::move( program ) ); +} + +void ResourceScope::publishLocalShaderProgram( std::string key, ShaderProgramPtr program ) { + mLocalCatalog->publishShaderProgram( std::move( key ), std::move( program ) ); +} + bool ResourceScope::eraseLocal( const ResourceKey& key ) { return mLocalCatalog->erase( key ); } @@ -359,6 +392,14 @@ bool ResourceScope::eraseLocalFont( Font* font ) { return true; } +bool ResourceScope::eraseLocalShaderProgram( const ResourceKey& key ) { + return mLocalCatalog->eraseShaderProgram( key ); +} + +bool ResourceScope::eraseLocalShaderProgram( const std::string& key ) { + return mLocalCatalog->eraseShaderProgram( key ); +} + void ResourceScope::clearLocal() { for ( const FontPtr& font : mLocalCatalog->getFonts() ) detachFontService( font ); diff --git a/src/eepp/graphics/shaderprogram.cpp b/src/eepp/graphics/shaderprogram.cpp index 838d26575..3396ccea3 100644 --- a/src/eepp/graphics/shaderprogram.cpp +++ b/src/eepp/graphics/shaderprogram.cpp @@ -7,48 +7,58 @@ namespace EE { namespace Graphics { -ShaderProgram* ShaderProgram::New( const std::string& name ) { - return eeNew( ShaderProgram, ( name ) ); +ShaderProgramPtr ShaderProgram::New( const std::string& name ) { + return ShaderProgramPtr( eeNew( ShaderProgram, ( name ) ), ResourceDeleter() ); } -ShaderProgram* ShaderProgram::New( const std::vector& Shaders, const std::string& name ) { - return eeNew( ShaderProgram, ( Shaders, name ) ); +ShaderProgramPtr ShaderProgram::New( const std::vector& shaders, + const std::string& name ) { + return ShaderProgramPtr( eeNew( ShaderProgram, ( shaders, name ) ), + ResourceDeleter() ); } -ShaderProgram* ShaderProgram::New( const std::string& VertexShaderFile, - const std::string& FragmentShaderFile, - const std::string& name ) { - return eeNew( ShaderProgram, ( VertexShaderFile, FragmentShaderFile, name ) ); +ShaderProgramPtr ShaderProgram::New( const std::string& VertexShaderFile, + const std::string& FragmentShaderFile, + const std::string& name ) { + return ShaderProgramPtr( eeNew( ShaderProgram, ( VertexShaderFile, FragmentShaderFile, name ) ), + ResourceDeleter() ); } -ShaderProgram* ShaderProgram::New( const char* VertexShaderData, const Uint32& VertexShaderDataSize, - const char* FragmentShaderData, - const Uint32& FragmentShaderDataSize, const std::string& name ) { - return eeNew( ShaderProgram, ( VertexShaderData, VertexShaderDataSize, FragmentShaderData, - FragmentShaderDataSize, name ) ); +ShaderProgramPtr ShaderProgram::New( const char* VertexShaderData, + const Uint32& VertexShaderDataSize, + const char* FragmentShaderData, + const Uint32& FragmentShaderDataSize, + const std::string& name ) { + return ShaderProgramPtr( + eeNew( ShaderProgram, ( VertexShaderData, VertexShaderDataSize, FragmentShaderData, + FragmentShaderDataSize, name ) ), + ResourceDeleter() ); } -ShaderProgram* ShaderProgram::New( Pack* Pack, const std::string& VertexShaderPath, - const std::string& FragmentShaderPath, - const std::string& name ) { - return eeNew( ShaderProgram, ( Pack, VertexShaderPath, FragmentShaderPath, name ) ); +ShaderProgramPtr ShaderProgram::New( Pack* Pack, const std::string& VertexShaderPath, + const std::string& FragmentShaderPath, + const std::string& name ) { + return ShaderProgramPtr( + eeNew( ShaderProgram, ( Pack, VertexShaderPath, FragmentShaderPath, name ) ), + ResourceDeleter() ); } -ShaderProgram* ShaderProgram::New( const char** VertexShaderData, const Uint32& NumLinesVS, - const char** FragmentShaderData, const Uint32& NumLinesFS, - const std::string& name ) { - return eeNew( ShaderProgram, - ( VertexShaderData, NumLinesVS, FragmentShaderData, NumLinesFS, name ) ); +ShaderProgramPtr ShaderProgram::New( const char** VertexShaderData, const Uint32& NumLinesVS, + const char** FragmentShaderData, const Uint32& NumLinesFS, + const std::string& name ) { + return ShaderProgramPtr( eeNew( ShaderProgram, ( VertexShaderData, NumLinesVS, + FragmentShaderData, NumLinesFS, name ) ), + ResourceDeleter() ); } ShaderProgram::ShaderProgram( const std::string& name ) : mHandler( 0 ), mId( 0 ) { - addToManager( name ); + addToRegistry( name ); init(); } -ShaderProgram::ShaderProgram( const std::vector& Shaders, const std::string& name ) : +ShaderProgram::ShaderProgram( const std::vector& Shaders, const std::string& name ) : mHandler( 0 ), mId( 0 ) { - addToManager( name ); + addToRegistry( name ); init(); addShaders( Shaders ); @@ -59,15 +69,13 @@ ShaderProgram::ShaderProgram( const std::vector& Shaders, const std::st ShaderProgram::ShaderProgram( const std::string& VertexShaderFile, const std::string& FragmentShaderFile, const std::string& name ) : mHandler( 0 ), mId( 0 ) { - addToManager( name ); + addToRegistry( name ); init(); - VertexShader* vs = eeNew( VertexShader, ( VertexShaderFile ) ); - FragmentShader* fs = eeNew( FragmentShader, ( FragmentShaderFile ) ); + ShaderPtr vs( eeNew( VertexShader, ( VertexShaderFile ) ), ResourceDeleter() ); + ShaderPtr fs( eeNew( FragmentShader, ( FragmentShaderFile ) ), ResourceDeleter() ); if ( !vs->isValid() || !fs->isValid() ) { - eeSAFE_DELETE( vs ); - eeSAFE_DELETE( fs ); return; } @@ -80,17 +88,17 @@ ShaderProgram::ShaderProgram( const std::string& VertexShaderFile, ShaderProgram::ShaderProgram( Pack* Pack, const std::string& VertexShaderPath, const std::string& FragmentShaderPath, const std::string& name ) : mHandler( 0 ), mId( 0 ) { - addToManager( name ); + addToRegistry( name ); init(); if ( NULL != Pack && Pack->isOpen() && -1 != Pack->exists( VertexShaderPath ) && -1 != Pack->exists( FragmentShaderPath ) ) { - VertexShader* vs = eeNew( VertexShader, ( Pack, VertexShaderPath ) ); - FragmentShader* fs = eeNew( FragmentShader, ( Pack, FragmentShaderPath ) ); + ShaderPtr vs( eeNew( VertexShader, ( Pack, VertexShaderPath ) ), + ResourceDeleter() ); + ShaderPtr fs( eeNew( FragmentShader, ( Pack, FragmentShaderPath ) ), + ResourceDeleter() ); if ( !vs->isValid() || !fs->isValid() ) { - eeSAFE_DELETE( vs ); - eeSAFE_DELETE( fs ); return; } @@ -105,15 +113,15 @@ ShaderProgram::ShaderProgram( const char* VertexShaderData, const Uint32& Vertex const char* FragmentShaderData, const Uint32& FragmentShaderDataSize, const std::string& name ) : mHandler( 0 ), mId( 0 ) { - addToManager( name ); + addToRegistry( name ); init(); - VertexShader* vs = eeNew( VertexShader, ( VertexShaderData, VertexShaderDataSize ) ); - FragmentShader* fs = eeNew( FragmentShader, ( FragmentShaderData, FragmentShaderDataSize ) ); + ShaderPtr vs( eeNew( VertexShader, ( VertexShaderData, VertexShaderDataSize ) ), + ResourceDeleter() ); + ShaderPtr fs( eeNew( FragmentShader, ( FragmentShaderData, FragmentShaderDataSize ) ), + ResourceDeleter() ); if ( !vs->isValid() || !fs->isValid() ) { - eeSAFE_DELETE( vs ); - eeSAFE_DELETE( fs ); return; } @@ -127,15 +135,15 @@ ShaderProgram::ShaderProgram( const char** VertexShaderData, const Uint32& NumLi const char** FragmentShaderData, const Uint32& NumLinesFS, const std::string& name ) : mHandler( 0 ), mId( 0 ) { - addToManager( name ); + addToRegistry( name ); init(); - VertexShader* vs = eeNew( VertexShader, ( VertexShaderData, NumLinesVS ) ); - FragmentShader* fs = eeNew( FragmentShader, ( FragmentShaderData, NumLinesFS ) ); + ShaderPtr vs( eeNew( VertexShader, ( VertexShaderData, NumLinesVS ) ), + ResourceDeleter() ); + ShaderPtr fs( eeNew( FragmentShader, ( FragmentShaderData, NumLinesFS ) ), + ResourceDeleter() ); if ( !vs->isValid() || !fs->isValid() ) { - eeSAFE_DELETE( vs ); - eeSAFE_DELETE( fs ); return; } @@ -155,22 +163,18 @@ ShaderProgram::~ShaderProgram() { mUniformLocations.clear(); mAttributeLocations.clear(); - for ( unsigned int i = 0; i < mShaders.size(); i++ ) - eeSAFE_DELETE( mShaders[i] ); - - if ( !ShaderProgramManager::instance()->isDestroying() ) { - removeFromManager(); - } + removeFromRegistry(); } -void ShaderProgram::addToManager( const std::string& name ) { +void ShaderProgram::addToRegistry( const std::string& name ) { setName( name ); - ShaderProgramManager::instance()->add( this ); + ShaderProgramRegistry::instance()->add( this ); } -void ShaderProgram::removeFromManager() { - ShaderProgramManager::instance()->remove( this, false ); +void ShaderProgram::removeFromRegistry() { + if ( ShaderProgramRegistry::existsSingleton() ) + ShaderProgramRegistry::instance()->remove( this ); } void ShaderProgram::init() { @@ -191,7 +195,7 @@ void ShaderProgram::reload() { init(); - std::vector tmpShader = mShaders; + std::vector tmpShader = mShaders; mShaders.clear(); @@ -207,24 +211,24 @@ void ShaderProgram::reload() { } } -void ShaderProgram::addShader( Shader* Shader ) { - if ( !Shader->isValid() ) { +void ShaderProgram::addShader( ShaderPtr shader ) { + if ( !shader || !shader->isValid() ) { Log::error( "ShaderProgram::addShader() %s: Cannot add invalid shader", mName.c_str() ); return; } if ( 0 != getHandler() ) { #ifdef EE_SHADERS_SUPPORTED - GLi->attachShader( getHandler(), Shader->getId() ); + GLi->attachShader( getHandler(), shader->getId() ); #endif - mShaders.push_back( Shader ); + mShaders.emplace_back( std::move( shader ) ); } } -void ShaderProgram::addShaders( const std::vector& Shaders ) { - for ( Uint32 i = 0; i < Shaders.size(); i++ ) - addShader( Shaders[i] ); +void ShaderProgram::addShaders( const std::vector& shaders ) { + for ( const auto& shader : shaders ) + addShader( shader ); } bool ShaderProgram::link() { @@ -411,12 +415,6 @@ const std::string& ShaderProgram::getName() const { void ShaderProgram::setName( const std::string& name ) { mName = name; mId = String::hash( mName ); - - Uint32 NameCount = ShaderProgramManager::instance()->exists( mName ); - - if ( 0 != NameCount || 0 == name.size() ) { - setName( name + String::toString( NameCount + 1 ) ); - } } void ShaderProgram::setReloadCb( ShaderProgramReloadCb Cb ) { diff --git a/src/eepp/graphics/shaderprogrammanager.cpp b/src/eepp/graphics/shaderprogrammanager.cpp index d27c633f8..f690d779a 100644 --- a/src/eepp/graphics/shaderprogrammanager.cpp +++ b/src/eepp/graphics/shaderprogrammanager.cpp @@ -2,15 +2,15 @@ namespace EE { namespace Graphics { -SINGLETON_DECLARE_IMPLEMENTATION( ShaderProgramManager ) +SINGLETON_DECLARE_IMPLEMENTATION( ShaderProgramRegistry ) -ShaderProgramManager::ShaderProgramManager() {} +ShaderProgramRegistry::ShaderProgramRegistry() {} -ShaderProgramManager::~ShaderProgramManager() {} +ShaderProgramRegistry::~ShaderProgramRegistry() {} -void ShaderProgramManager::reload() { - for ( auto& res : mResources ) - res.second->reload(); +void ShaderProgramRegistry::reload() { + for ( auto* program : mResources ) + program->reload(); } }} // namespace EE::Graphics diff --git a/src/eepp/graphics/vertexbuffer.cpp b/src/eepp/graphics/vertexbuffer.cpp index dd45b401e..96b8bdb08 100644 --- a/src/eepp/graphics/vertexbuffer.cpp +++ b/src/eepp/graphics/vertexbuffer.cpp @@ -7,23 +7,28 @@ using namespace EE::Graphics::Private; namespace EE { namespace Graphics { -VertexBuffer* VertexBuffer::New( const Uint32& vertexFlags, PrimitiveType drawType, - const Int32& reserveVertexSize, const Int32& reserveIndexSize, - VertexBufferUsageType usageType ) { +VertexBufferUniquePtr VertexBuffer::New( const Uint32& vertexFlags, PrimitiveType drawType, + const Int32& reserveVertexSize, + const Int32& reserveIndexSize, + VertexBufferUsageType usageType ) { if ( GLi->isExtension( EEGL_ARB_vertex_buffer_object ) || GLi->version() == GLv_3CP ) - return eeNew( VertexBufferVBO, - ( vertexFlags, drawType, reserveVertexSize, reserveIndexSize, usageType ) ); + return VertexBufferUniquePtr( + eeNew( VertexBufferVBO, + ( vertexFlags, drawType, reserveVertexSize, reserveIndexSize, usageType ) ) ); - return eeNew( VertexBufferOGL, - ( vertexFlags, drawType, reserveVertexSize, reserveIndexSize, usageType ) ); + return VertexBufferUniquePtr( + eeNew( VertexBufferOGL, + ( vertexFlags, drawType, reserveVertexSize, reserveIndexSize, usageType ) ) ); } -VertexBuffer* VertexBuffer::NewVertexArray( const Uint32& vertexFlags, PrimitiveType drawType, - const Int32& reserveVertexSize, - const Int32& reserveIndexSize, - VertexBufferUsageType usageType ) { - return eeNew( VertexBufferOGL, - ( vertexFlags, drawType, reserveVertexSize, reserveIndexSize, usageType ) ); +VertexBufferUniquePtr VertexBuffer::NewVertexArray( const Uint32& vertexFlags, + PrimitiveType drawType, + const Int32& reserveVertexSize, + const Int32& reserveIndexSize, + VertexBufferUsageType usageType ) { + return VertexBufferUniquePtr( + eeNew( VertexBufferOGL, + ( vertexFlags, drawType, reserveVertexSize, reserveIndexSize, usageType ) ) ); } VertexBuffer::VertexBuffer( const Uint32& vertexFlags, PrimitiveType drawType, @@ -48,11 +53,12 @@ VertexBuffer::VertexBuffer( const Uint32& vertexFlags, PrimitiveType drawType, mIndexArray.reserve( reserveIndexSize ); } - VertexBufferManager::instance()->add( this ); + VertexBufferRegistry::instance()->add( this ); } VertexBuffer::~VertexBuffer() { - VertexBufferManager::instance()->remove( this ); + if ( VertexBufferRegistry::existsSingleton() ) + VertexBufferRegistry::instance()->remove( this ); } void VertexBuffer::addVertex( const Uint32& type, const Vector2f& vertex ) { diff --git a/src/eepp/graphics/vertexbuffermanager.cpp b/src/eepp/graphics/vertexbuffermanager.cpp index 937bf277c..4fce728af 100644 --- a/src/eepp/graphics/vertexbuffermanager.cpp +++ b/src/eepp/graphics/vertexbuffermanager.cpp @@ -2,13 +2,13 @@ namespace EE { namespace Graphics { namespace Private { -SINGLETON_DECLARE_IMPLEMENTATION( VertexBufferManager ) +SINGLETON_DECLARE_IMPLEMENTATION( VertexBufferRegistry ) -VertexBufferManager::VertexBufferManager() {} +VertexBufferRegistry::VertexBufferRegistry() {} -VertexBufferManager::~VertexBufferManager() {} +VertexBufferRegistry::~VertexBufferRegistry() {} -void VertexBufferManager::reload() { +void VertexBufferRegistry::reload() { for ( auto& vb : mResources ) vb->reload(); } diff --git a/src/eepp/scene/scenenode.cpp b/src/eepp/scene/scenenode.cpp index 77a158e75..392c40ea3 100644 --- a/src/eepp/scene/scenenode.cpp +++ b/src/eepp/scene/scenenode.cpp @@ -18,7 +18,7 @@ SceneNode::SceneNode( EE::Window::Window* window ) : Node(), mWindow( window ), mActionManager( ActionManager::New() ), - mFrameBuffer( NULL ), + mFrameBuffer( nullptr ), mEventDispatcher( NULL ), mFrameBufferBound( false ), mUseInvalidation( false ), @@ -65,7 +65,7 @@ SceneNode::~SceneNode() { if ( !mParentNode ) eeSAFE_DELETE( mEventDispatcher ); - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); } void SceneNode::enableFrameBuffer() { @@ -74,7 +74,7 @@ void SceneNode::enableFrameBuffer() { } void SceneNode::disableFrameBuffer() { - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); writeNodeFlag( NODE_FLAG_FRAME_BUFFER, 0 ); } @@ -260,7 +260,7 @@ Sizei SceneNode::getFrameBufferSize() { void SceneNode::createFrameBuffer() { writeNodeFlag( NODE_FLAG_FRAME_BUFFER, 1 ); - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); Sizei fboSize( getFrameBufferSize() ); if ( fboSize.getWidth() < 1 ) fboSize.setWidth( 1 ); @@ -271,7 +271,7 @@ void SceneNode::createFrameBuffer() { // Frame buffer failed to create? if ( mFrameBuffer == nullptr || !mFrameBuffer->created() ) { - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); } } @@ -351,7 +351,7 @@ void SceneNode::resizeNode( EE::Window::Window* ) { } FrameBuffer* SceneNode::getFrameBuffer() const { - return mFrameBuffer; + return mFrameBuffer.get(); } void SceneNode::setEventDispatcher( EventDispatcher* eventDispatcher ) { diff --git a/src/eepp/ui/iconmanager.cpp b/src/eepp/ui/iconmanager.cpp index 94e8ce8f7..7368d3e81 100644 --- a/src/eepp/ui/iconmanager.cpp +++ b/src/eepp/ui/iconmanager.cpp @@ -6,10 +6,11 @@ namespace EE { namespace UI { using IconPair = std::pair; -UIIconTheme* IconManager::init( const std::string& iconThemeName, FontTrueType* remixIconFont, - FontTrueType* noniconFont, FontTrueType* codIconFont ) { +ResourcePtr IconManager::init( const std::string& iconThemeName, + FontTrueType* remixIconFont, FontTrueType* noniconFont, + FontTrueType* codIconFont ) { - UIIconTheme* iconTheme = UIIconTheme::New( iconThemeName ); + auto iconTheme = UIIconTheme::New( iconThemeName ); if ( remixIconFont && remixIconFont->loaded() ) { remixIconFont->setIsEmojiFont( true ); diff --git a/src/eepp/ui/uiapplication.cpp b/src/eepp/ui/uiapplication.cpp index bfbda4ff8..b15b34e97 100644 --- a/src/eepp/ui/uiapplication.cpp +++ b/src/eepp/ui/uiapplication.cpp @@ -94,14 +94,14 @@ UIApplication::UIApplication( const WindowSettings& windowSettings, const Settin mUISceneNode->getRoot()->addClass( "appbackground" ); mUISceneNode->getUIThemeManager()->setDefaultEffectsEnabled( true )->setDefaultFont( font ); - UITheme* theme = UITheme::load( "uitheme", "uitheme", "", font, - appSettings.baseStyleSheetPath ? *appSettings.baseStyleSheetPath - : "assets/ui/breeze.css" ); + UIThemePtr theme = UITheme::load( + "uitheme", "uitheme", "", font, + appSettings.baseStyleSheetPath ? *appSettings.baseStyleSheetPath : "assets/ui/breeze.css" ); mStyleSheetMarker = String::hash( "uitheme" ); mUISceneNode->setStyleSheet( theme->getStyleSheet() ); mUISceneNode->getStyleSheet().setMarker( mStyleSheetMarker ); - mUISceneNode->getUIThemeManager()->setDefaultTheme( theme )->add( theme ); + mUISceneNode->getUIThemeManager()->setDefaultTheme( std::move( theme ) ); } UIApplication::~UIApplication() { diff --git a/src/eepp/ui/uibackgrounddrawable.cpp b/src/eepp/ui/uibackgrounddrawable.cpp index d94270397..6a32ae30d 100644 --- a/src/eepp/ui/uibackgrounddrawable.cpp +++ b/src/eepp/ui/uibackgrounddrawable.cpp @@ -18,9 +18,7 @@ UIBackgroundDrawable::UIBackgroundDrawable( const UINode* owner ) : mNeedsRadiusUpdate( false ), mColorNeedsUpdate( false ) {} -UIBackgroundDrawable::~UIBackgroundDrawable() { - eeSAFE_DELETE( mVertexBuffer ); -} +UIBackgroundDrawable::~UIBackgroundDrawable() = default; void UIBackgroundDrawable::draw() { draw( mPosition, mSize ); @@ -178,7 +176,7 @@ void UIBackgroundDrawable::update() { mVertexBuffer = VertexBuffer::NewVertexArray( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); } - Borders::createBackground( mVertexBuffer, mRadiuses, mPosition, mSize, mColor ); + Borders::createBackground( mVertexBuffer.get(), mRadiuses, mPosition, mSize, mColor ); } mColorNeedsUpdate = false; mNeedsRadiusUpdate = false; diff --git a/src/eepp/ui/uiborderdrawable.cpp b/src/eepp/ui/uiborderdrawable.cpp index bf6e26621..f136ec71b 100644 --- a/src/eepp/ui/uiborderdrawable.cpp +++ b/src/eepp/ui/uiborderdrawable.cpp @@ -20,9 +20,7 @@ UIBorderDrawable::UIBorderDrawable( const UINode* owner ) : mColorNeedsUpdate( false ), mHasBorder( false ) {} -UIBorderDrawable::~UIBorderDrawable() { - eeSAFE_DELETE( mVertexBuffer ); -} +UIBorderDrawable::~UIBorderDrawable() = default; void UIBorderDrawable::draw() { draw( mPosition, mSize ); @@ -309,12 +307,12 @@ void UIBorderDrawable::update() { size.y += mBorders.bottom.width * 2; } - Borders::createBorders( mVertexBuffer, mBorders, pos, size ); + Borders::createBorders( mVertexBuffer.get(), mBorders, pos, size ); break; } case BorderType::Inside: { - Borders::createBorders( mVertexBuffer, mBorders, Vector2f::Zero, mSize ); + Borders::createBorders( mVertexBuffer.get(), mBorders, Vector2f::Zero, mSize ); break; } case BorderType::Outline: { @@ -337,7 +335,7 @@ void UIBorderDrawable::update() { size.y += mBorders.bottom.width; } - Borders::createBorders( mVertexBuffer, mBorders, pos, size ); + Borders::createBorders( mVertexBuffer.get(), mBorders, pos, size ); break; } diff --git a/src/eepp/ui/uiicon.cpp b/src/eepp/ui/uiicon.cpp index b3c03d905..f11cd410a 100644 --- a/src/eepp/ui/uiicon.cpp +++ b/src/eepp/ui/uiicon.cpp @@ -5,8 +5,8 @@ namespace EE { namespace UI { -UIIcon* UIIcon::New( const std::string& name ) { - return eeNew( UIIcon, ( name ) ); +UIIconPtr UIIcon::New( const std::string& name ) { + return UIIconPtr( eeNew( UIIcon, ( name ) ), ResourceDeleter() ); } UIIcon::UIIcon( const std::string& name ) : mName( name ) {} @@ -43,8 +43,8 @@ void UIIcon::setSource( const int& size, DrawablePtr drawable ) { mSizes[size] = std::move( drawable ); } -UIIcon* UIGlyphIcon::New( const std::string& name, FontTrueType* font, const Uint32& codePoint ) { - return eeNew( UIGlyphIcon, ( name, font, codePoint ) ); +UIIconPtr UIGlyphIcon::New( const std::string& name, FontTrueType* font, const Uint32& codePoint ) { + return UIIconPtr( eeNew( UIGlyphIcon, ( name, font, codePoint ) ), ResourceDeleter() ); } const DrawablePtr& UIGlyphIcon::getSource( const int& size ) const { @@ -78,8 +78,8 @@ UIGlyphIcon::~UIGlyphIcon() { } } -UIIcon* UISVGIcon::New( const std::string& name, const std::string& svgXML ) { - return eeNew( UISVGIcon, ( name, svgXML ) ); +UIIconPtr UISVGIcon::New( const std::string& name, const std::string& svgXML ) { + return UIIconPtr( eeNew( UISVGIcon, ( name, svgXML ) ), ResourceDeleter() ); } UISVGIcon::~UISVGIcon() {} diff --git a/src/eepp/ui/uiicontheme.cpp b/src/eepp/ui/uiicontheme.cpp index 5096debd9..f42a6f8dd 100644 --- a/src/eepp/ui/uiicontheme.cpp +++ b/src/eepp/ui/uiicontheme.cpp @@ -3,26 +3,21 @@ namespace EE { namespace UI { -UIIconTheme* UIIconTheme::New( const std::string& name ) { - return eeNew( UIIconTheme, ( name ) ); +UIIconThemePtr UIIconTheme::New( const std::string& name ) { + return UIIconThemePtr( eeNew( UIIconTheme, ( name ) ), ResourceDeleter() ); } -UIIconTheme::~UIIconTheme() { - for ( auto icon : mIcons ) - eeDelete( icon.second ); -} +UIIconTheme::~UIIconTheme() = default; UIIconTheme::UIIconTheme( const std::string& name ) : mName( name ) {} -UIIconTheme* UIIconTheme::add( UIIcon* icon ) { - auto iconExists = mIcons.find( icon->getName() ); - if ( iconExists != mIcons.end() ) - eeDelete( iconExists->second ); - mIcons[icon->getName()] = icon; +UIIconTheme* UIIconTheme::add( UIIconPtr icon ) { + if ( icon ) + mIcons[icon->getName()] = std::move( icon ); return this; } -UIIconTheme* UIIconTheme::add( const std::unordered_map& icons ) { +UIIconTheme* UIIconTheme::add( const std::unordered_map& icons ) { mIcons.insert( icons.begin(), icons.end() ); return this; } @@ -33,7 +28,7 @@ const std::string& UIIconTheme::getName() const { UIIcon* UIIconTheme::getIcon( const std::string& name ) const { auto it = mIcons.find( name ); - return it != mIcons.end() ? it->second : nullptr; + return it != mIcons.end() ? it->second.get() : nullptr; } }} // namespace EE::UI diff --git a/src/eepp/ui/uiiconthememanager.cpp b/src/eepp/ui/uiiconthememanager.cpp index 54357498a..cea69dbe4 100644 --- a/src/eepp/ui/uiiconthememanager.cpp +++ b/src/eepp/ui/uiiconthememanager.cpp @@ -20,16 +20,13 @@ UIIconThemeManager* UIIconThemeManager::New() { return eeNew( UIIconThemeManager, () ); } -UIIconThemeManager::~UIIconThemeManager() { - for ( UIIconTheme* theme : mIconThemes ) - eeDelete( theme ); -} +UIIconThemeManager::~UIIconThemeManager() = default; UIIconThemeManager::UIIconThemeManager() {} -UIIconThemeManager* UIIconThemeManager::add( UIIconTheme* iconTheme ) { - if ( !isPresent( iconTheme ) ) { - mIconThemes.push_back( iconTheme ); +UIIconThemeManager* UIIconThemeManager::add( UIIconThemePtr iconTheme ) { + if ( iconTheme && !isPresent( iconTheme.get() ) ) { + mIconThemes.emplace_back( std::move( iconTheme ) ); } return this; } @@ -38,11 +35,10 @@ UIIconTheme* UIIconThemeManager::getCurrentTheme() const { return mCurrentTheme; } -UIIconThemeManager* UIIconThemeManager::setCurrentTheme( UIIconTheme* currentTheme ) { - if ( currentTheme != mCurrentTheme && currentTheme != mFallbackTheme ) { - if ( !isPresent( currentTheme ) ) - add( currentTheme ); - mCurrentTheme = currentTheme; +UIIconThemeManager* UIIconThemeManager::setCurrentTheme( UIIconThemePtr currentTheme ) { + if ( currentTheme.get() != mCurrentTheme && currentTheme.get() != mFallbackTheme ) { + mCurrentTheme = currentTheme.get(); + add( std::move( currentTheme ) ); } return this; } @@ -51,11 +47,10 @@ UIIconTheme* UIIconThemeManager::getFallbackTheme() const { return mFallbackTheme; } -UIIconThemeManager* UIIconThemeManager::setFallbackTheme( UIIconTheme* fallbackTheme ) { - if ( fallbackTheme != mFallbackTheme && fallbackTheme != mCurrentTheme ) { - if ( !isPresent( fallbackTheme ) ) - add( fallbackTheme ); - mFallbackTheme = fallbackTheme; +UIIconThemeManager* UIIconThemeManager::setFallbackTheme( UIIconThemePtr fallbackTheme ) { + if ( fallbackTheme.get() != mFallbackTheme && fallbackTheme.get() != mCurrentTheme ) { + mFallbackTheme = fallbackTheme.get(); + add( std::move( fallbackTheme ) ); } return this; } @@ -89,12 +84,14 @@ UIIconThemeManager::setFallbackThemeManager( UIThemeManager* fallbackThemeManage } void UIIconThemeManager::remove( UIIconTheme* iconTheme ) { - auto pos = std::find( mIconThemes.begin(), mIconThemes.end(), iconTheme ); + auto pos = std::find_if( + mIconThemes.begin(), mIconThemes.end(), + [iconTheme]( const UIIconThemePtr& theme ) { return theme.get() == iconTheme; } ); if ( pos != mIconThemes.end() ) { - if ( *pos == mCurrentTheme ) { + if ( pos->get() == mCurrentTheme ) { mCurrentTheme = mFallbackTheme; mFallbackTheme = nullptr; - } else if ( *pos == mFallbackTheme ) { + } else if ( pos->get() == mFallbackTheme ) { mFallbackTheme = nullptr; } mIconThemes.erase( pos ); @@ -102,7 +99,10 @@ void UIIconThemeManager::remove( UIIconTheme* iconTheme ) { } bool UIIconThemeManager::isPresent( UIIconTheme* iconTheme ) { - return std::find( mIconThemes.begin(), mIconThemes.end(), iconTheme ) != mIconThemes.end(); + return std::find_if( mIconThemes.begin(), mIconThemes.end(), + [iconTheme]( const UIIconThemePtr& theme ) { + return theme.get() == iconTheme; + } ) != mIconThemes.end(); } }} // namespace EE::UI diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 174afbc90..b39dc158d 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -322,7 +322,7 @@ void UISceneNode::initializeEmbeddedFromHost( UISceneNode* hostScene ) { if ( hostThemeManager ) { mUIThemeManager->setDefaultFont( hostThemeManager->getDefaultFont() ); mUIThemeManager->setDefaultFontSize( hostThemeManager->getDefaultFontSize() ); - mUIThemeManager->setDefaultTheme( hostThemeManager->getDefaultTheme() ); + mUIThemeManager->setDefaultTheme( hostThemeManager->getDefaultThemeHandle() ); mUIThemeManager->setAutoApplyDefaultTheme( hostThemeManager->getAutoApplyDefaultTheme() ); mUIThemeManager->setDefaultEffectsEnabled( hostThemeManager->getDefaultEffectsEnabled() ); mUIThemeManager->setWidgetsFadeInTime( hostThemeManager->getWidgetsFadeInTime() ); diff --git a/src/eepp/ui/uiskin.cpp b/src/eepp/ui/uiskin.cpp index 5a611a3bd..7ba33cf7e 100644 --- a/src/eepp/ui/uiskin.cpp +++ b/src/eepp/ui/uiskin.cpp @@ -5,8 +5,8 @@ namespace EE { namespace UI { -UISkin* UISkin::New( const std::string& name ) { - return eeNew( UISkin, ( name ) ); +ResourcePtr UISkin::New( const std::string& name ) { + return ResourcePtr( eeNew( UISkin, ( name ) ), ResourceDeleter() ); } UISkin::UISkin( const std::string& name ) : StateListDrawable( SKIN, name ) { diff --git a/src/eepp/ui/uitheme.cpp b/src/eepp/ui/uitheme.cpp index 9a44e98be..cc78be93a 100644 --- a/src/eepp/ui/uitheme.cpp +++ b/src/eepp/ui/uitheme.cpp @@ -31,14 +31,14 @@ static std::string elemNameFromSkin( const std::vector& nameParts ) return str; } -UITheme* UITheme::New( const std::string& name, const std::string& abbr, Font* defaultFont ) { - return eeNew( UITheme, ( name, abbr, defaultFont ) ); +UIThemePtr UITheme::New( const std::string& name, const std::string& abbr, Font* defaultFont ) { + return UIThemePtr( eeNew( UITheme, ( name, abbr, defaultFont ) ), ResourceDeleter() ); } -UITheme* UITheme::load( const std::string& name, const std::string& abbr, - const std::string& textureAtlasPath, Font* defaultFont, - const std::string& styleSheetPath ) { - UITheme* theme = UITheme::New( name, abbr, defaultFont ); +UIThemePtr UITheme::load( const std::string& name, const std::string& abbr, + const std::string& textureAtlasPath, Font* defaultFont, + const std::string& styleSheetPath ) { + UIThemePtr theme = UITheme::New( name, abbr, defaultFont ); CSS::StyleSheetParser styleSheetParser; @@ -59,10 +59,10 @@ UITheme* UITheme::load( const std::string& name, const std::string& abbr, 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 ) { - UITheme* theme = UITheme::New( name, abbr, defaultFont ); +UIThemePtr UITheme::loadFromString( const std::string& name, const std::string& abbr, + const std::string& textureAtlasPath, Font* defaultFont, + const std::string& styleSheetString ) { + UIThemePtr theme = UITheme::New( name, abbr, defaultFont ); CSS::StyleSheetParser styleSheetParser; @@ -82,7 +82,7 @@ UITheme* UITheme::loadFromString( const std::string& name, const std::string& ab return loadFromTextureAtlas( theme, tgl.getTextureAtlas() ); } -UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, TextureAtlasPtr textureAtlas ) { +UIThemePtr UITheme::loadFromTextureAtlas( UIThemePtr tTheme, TextureAtlasPtr textureAtlas ) { eeASSERT( NULL != tTheme && NULL != textureAtlas ); /** Themes use nearest filter by default, force the filter to the textures. */ @@ -105,7 +105,7 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, TextureAtlasPtr texture std::string name( textureRegion->getName() ); if ( String::startsWith( name, sAbbrIcon ) ) { - auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); + auto icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); icon->setSource( textureRegion->getPixelsSize().getWidth(), textureRegion->clone() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { @@ -174,8 +174,8 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, TextureAtlasPtr texture return tTheme; } -UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, - const Float& pixelDensity ) { +UIThemePtr UITheme::loadFromDirectory( UIThemePtr tTheme, const std::string& Path, + const Float& pixelDensity ) { Clock TE; std::string RPath( Path ); @@ -204,7 +204,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, auto drawable = TextureRegion::New( TextureFactory::instance()->loadFromFile( fpath ), name ); tSG->add( drawable ); - auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); + auto icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); icon->setSource( drawable->getPixelsSize().getWidth(), drawable->clone() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { @@ -285,18 +285,17 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, return tTheme; } -UITheme* UITheme::loadFromDirectory( const std::string& Path, const std::string& Name, - const std::string& NameAbbr, const Float& pixelDensity ) { +UIThemePtr UITheme::loadFromDirectory( const std::string& Path, const std::string& Name, + const std::string& NameAbbr, const Float& pixelDensity ) { return loadFromDirectory( UITheme::New( Name, NameAbbr ), Path, pixelDensity ); } -UITheme* UITheme::loadFromTextureAtlas( TextureAtlasPtr textureAtlas, const std::string& Name, - const std::string& NameAbbr ) { +UIThemePtr 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 ) : - ResourceManagerMulti(), mName( name ), mNameHash( String::hash( mName ) ), mAbbr( Abbr ), @@ -306,9 +305,7 @@ UITheme::UITheme( const std::string& name, const std::string& Abbr, Graphics::Fo mIconTheme( UIIconTheme::New( name ) ), mResourceCatalog( ResourceCatalog::New() ) {} -UITheme::~UITheme() { - eeSAFE_DELETE( mIconTheme ); -} +UITheme::~UITheme() = default; const std::string& UITheme::getName() const { return mName; @@ -327,8 +324,29 @@ const std::string& UITheme::getAbbr() const { return mAbbr; } -UISkin* UITheme::add( UISkin* Resource ) { - return ResourceManagerMulti::add( Resource ); +UISkin* UITheme::add( UISkinPtr skin ) { + if ( !skin ) + return nullptr; + UISkin* result = skin.get(); + mSkins[skin->getId()].emplace_back( std::move( skin ) ); + return result; +} + +UISkin* UITheme::getById( const String::HashType& id ) const { + auto it = mSkins.find( id ); + return it != mSkins.end() && !it->second.empty() ? it->second.front().get() : nullptr; +} + +UISkin* UITheme::getByName( const std::string& name ) const { + return getById( String::hash( name ) ); +} + +bool UITheme::exists( const std::string& name ) const { + return existsId( String::hash( name ) ); +} + +bool UITheme::existsId( const String::HashType& id ) const { + return mSkins.find( id ) != mSkins.end(); } Graphics::TextureAtlas* UITheme::getTextureAtlas() const { @@ -377,7 +395,7 @@ void UITheme::setDefaultFontSize( const Float& defaultFontSize ) { } UIIconTheme* UITheme::getIconTheme() const { - return mIconTheme; + return mIconTheme.get(); } const ResourceCatalogPtr& UITheme::getResourceCatalog() const { diff --git a/src/eepp/ui/uithememanager.cpp b/src/eepp/ui/uithememanager.cpp index 9fbeb184e..318ab3357 100644 --- a/src/eepp/ui/uithememanager.cpp +++ b/src/eepp/ui/uithememanager.cpp @@ -8,7 +8,6 @@ UIThemeManager* UIThemeManager::New() { } UIThemeManager::UIThemeManager() : - ResourceManager(), mFont( NULL ), mFontSize( PixelDensity::dpToPx( 12 ) ), mThemeDefault( NULL ), @@ -22,34 +21,53 @@ UIThemeManager::UIThemeManager() : UIThemeManager::~UIThemeManager() { if ( mResourceScope ) { - each( [this]( const auto& resource ) { - if ( resource.second ) - mResourceScope->removeCatalog( resource.second->getResourceCatalog() ); - } ); + for ( const auto& resource : mThemes ) + mResourceScope->removeCatalog( resource.second->getResourceCatalog() ); + if ( mThemeDefault && mThemes.find( mThemeDefault->getId() ) == mThemes.end() ) + mResourceScope->removeCatalog( mThemeDefault->getResourceCatalog() ); } } -UITheme* UIThemeManager::add( UITheme* theme ) { - UITheme* added = ResourceManager::add( theme ); - if ( added && mResourceScope ) +UITheme* UIThemeManager::add( UIThemePtr theme ) { + if ( !theme ) + return nullptr; + UITheme* added = theme.get(); + auto existing = mThemes.find( theme->getId() ); + const bool replacesDefault = + existing != mThemes.end() && existing->second.get() == mThemeDefault.get(); + if ( existing != mThemes.end() && mResourceScope ) + mResourceScope->removeCatalog( existing->second->getResourceCatalog() ); + mThemes[theme->getId()] = std::move( theme ); + if ( replacesDefault ) + mThemeDefault = mThemes[added->getId()]; + if ( mResourceScope ) mResourceScope->importCatalog( added->getResourceCatalog() ); return added; } -bool UIThemeManager::remove( UITheme* theme, bool destroy ) { - if ( theme && mResourceScope ) +bool UIThemeManager::remove( UITheme* theme ) { + if ( !theme ) + return false; + auto it = mThemes.find( theme->getId() ); + const bool isManaged = it != mThemes.end() && it->second.get() == theme; + const bool isDefault = theme == mThemeDefault.get(); + if ( !isManaged && !isDefault ) + return false; + if ( mResourceScope ) mResourceScope->removeCatalog( theme->getResourceCatalog() ); - if ( theme == mThemeDefault ) - mThemeDefault = nullptr; - return ResourceManager::remove( theme, destroy ); + if ( isDefault ) + mThemeDefault.reset(); + if ( isManaged ) + mThemes.erase( it ); + return true; } -bool UIThemeManager::removeById( const String::HashType& id, bool destroy ) { - return remove( getById( id ), destroy ); +bool UIThemeManager::removeById( const String::HashType& id ) { + return remove( getById( id ) ); } -bool UIThemeManager::removeByName( const std::string& name, bool destroy ) { - return remove( getByName( name ), destroy ); +bool UIThemeManager::removeByName( const std::string& name ) { + return remove( getByName( name ) ); } UIThemeManager* UIThemeManager::setResourceScope( ResourceScopePtr resourceScope ) { @@ -57,17 +75,17 @@ UIThemeManager* UIThemeManager::setResourceScope( ResourceScopePtr resourceScope return this; if ( mResourceScope ) { - each( [this]( const auto& resource ) { - if ( resource.second ) - mResourceScope->removeCatalog( resource.second->getResourceCatalog() ); - } ); + for ( const auto& resource : mThemes ) + mResourceScope->removeCatalog( resource.second->getResourceCatalog() ); + if ( mThemeDefault && mThemes.find( mThemeDefault->getId() ) == mThemes.end() ) + mResourceScope->removeCatalog( mThemeDefault->getResourceCatalog() ); } mResourceScope = std::move( resourceScope ); if ( mResourceScope ) { - each( [this]( const auto& resource ) { - if ( resource.second ) - mResourceScope->importCatalog( resource.second->getResourceCatalog() ); - } ); + for ( const auto& resource : mThemes ) + mResourceScope->importCatalog( resource.second->getResourceCatalog() ); + if ( mThemeDefault && mThemes.find( mThemeDefault->getId() ) == mThemes.end() ) + mResourceScope->importCatalog( mThemeDefault->getResourceCatalog() ); } return this; } @@ -96,13 +114,17 @@ const Float& UIThemeManager::getDefaultFontSize() const { } UIThemeManager* UIThemeManager::setDefaultTheme( UITheme* Theme ) { - UITheme* previousTheme = mThemeDefault; + UITheme* previousTheme = mThemeDefault.get(); if ( previousTheme && previousTheme != Theme && mResourceScope && - !findIf( [previousTheme]( const auto& resource ) { - return resource.second == previousTheme; - } ) ) + mThemes.find( previousTheme->getId() ) == mThemes.end() ) mResourceScope->removeCatalog( previousTheme->getResourceCatalog() ); - mThemeDefault = Theme; + if ( Theme ) { + auto it = mThemes.find( Theme->getId() ); + mThemeDefault = + it != mThemes.end() && it->second.get() == Theme ? it->second : UIThemePtr{}; + } else { + mThemeDefault.reset(); + } if ( mThemeDefault && mResourceScope ) mResourceScope->importCatalog( mThemeDefault->getResourceCatalog() ); @@ -112,18 +134,44 @@ UIThemeManager* UIThemeManager::setDefaultTheme( UITheme* Theme ) { return this; } +UIThemeManager* UIThemeManager::setDefaultTheme( UIThemePtr theme ) { + UITheme* previousTheme = mThemeDefault.get(); + if ( previousTheme && previousTheme != theme.get() && mResourceScope && + mThemes.find( previousTheme->getId() ) == mThemes.end() ) + mResourceScope->removeCatalog( previousTheme->getResourceCatalog() ); + mThemeDefault = std::move( theme ); + if ( mThemeDefault && mResourceScope ) + mResourceScope->importCatalog( mThemeDefault->getResourceCatalog() ); + if ( mThemeDefault && !mThemeDefault->getDefaultFont() ) + mThemeDefault->setDefaultFont( mFont ); + return this; +} + UIThemeManager* UIThemeManager::setDefaultTheme( const std::string& Theme ) { setDefaultTheme( getByName( Theme ) ); return this; } UITheme* UIThemeManager::getDefaultTheme() const { + return mThemeDefault.get(); +} + +UIThemePtr UIThemeManager::getDefaultThemeHandle() const { return mThemeDefault; } +UITheme* UIThemeManager::getById( const String::HashType& id ) const { + auto it = mThemes.find( id ); + return it != mThemes.end() ? it->second.get() : nullptr; +} + +UITheme* UIThemeManager::getByName( const std::string& name ) const { + return getById( String::hash( name ) ); +} + UIThemeManager* UIThemeManager::applyDefaultTheme( UINode* node ) { if ( mAutoApplyDefaultTheme && NULL != mThemeDefault && NULL != node ) - node->setTheme( mThemeDefault ); + node->setTheme( mThemeDefault.get() ); return this; } diff --git a/src/eepp/ui/uiwindow.cpp b/src/eepp/ui/uiwindow.cpp index 3c138c777..451f66391 100644 --- a/src/eepp/ui/uiwindow.cpp +++ b/src/eepp/ui/uiwindow.cpp @@ -50,7 +50,7 @@ UIWindow::UIWindow( UIWindow::WindowBaseContainerType type ) : UIWindow( type, S UIWindow::UIWindow( UIWindow::WindowBaseContainerType type, const StyleConfig& windowStyleConfig ) : UIWidget( "window" ), - mFrameBuffer( NULL ), + mFrameBuffer( nullptr ), mStyleConfig( windowStyleConfig ), mWindowDecoration( NULL ), mBorderLeft( NULL ), @@ -133,7 +133,7 @@ UIWindow::~UIWindow() { sendCommonEvent( Event::OnWindowClose ); - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); } void UIWindow::onContainerPositionChange( const Event* ) { @@ -166,7 +166,7 @@ void UIWindow::updateWinFlags() { if ( NULL == mFrameBuffer ) createFrameBuffer(); } else { - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); } if ( NULL != mContainer && ( mStyleConfig.WinFlags & UI_WIN_DRAGGABLE_CONTAINER ) ) { @@ -330,7 +330,7 @@ void UIWindow::updateWinFlags() { } void UIWindow::createFrameBuffer() { - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); Sizei fboSize( getFrameBufferSize() ); if ( fboSize.getWidth() < 1 ) fboSize.setWidth( 1 ); @@ -341,8 +341,8 @@ void UIWindow::createFrameBuffer() { ( mStyleConfig.WinFlags & UI_WIN_COLOR_BUFFER ) ? true : false ); // Frame buffer failed to create? - if ( !mFrameBuffer->created() ) { - eeSAFE_DELETE( mFrameBuffer ); + if ( !mFrameBuffer || !mFrameBuffer->created() ) { + mFrameBuffer.reset(); } } @@ -1309,7 +1309,7 @@ void UIWindow::invalidate( Node* invalidator ) { } FrameBuffer* UIWindow::getFrameBuffer() const { - return mFrameBuffer; + return mFrameBuffer.get(); } bool UIWindow::isDrawInvalidator() const { diff --git a/src/eepp/window/engine.cpp b/src/eepp/window/engine.cpp index 2701144fb..a53c90572 100644 --- a/src/eepp/window/engine.cpp +++ b/src/eepp/window/engine.cpp @@ -104,9 +104,9 @@ Engine::~Engine() { Doc::SyntaxDefinitionManager::destroySingleton(); - Graphics::Private::FrameBufferManager::destroySingleton(); + Graphics::Private::FrameBufferRegistry::destroySingleton(); - Graphics::Private::VertexBufferManager::destroySingleton(); + Graphics::Private::VertexBufferRegistry::destroySingleton(); // Catalogs are the final intentional texture owners. Clear them while the factory and current // graphics context are still available for deferred release collection. @@ -120,7 +120,7 @@ Engine::~Engine() { // Shader and renderer destructors issue GL commands. Programs must go first while GLi and the // current window context are still valid. - ShaderProgramManager::destroySingleton(); + ShaderProgramRegistry::destroySingleton(); Graphics::Renderer::destroySingleton(); diff --git a/src/examples/external_shader/external_shader.cpp b/src/examples/external_shader/external_shader.cpp index e63d9e2c5..d0b7c73ea 100644 --- a/src/examples/external_shader/external_shader.cpp +++ b/src/examples/external_shader/external_shader.cpp @@ -8,31 +8,35 @@ namespace Demo_ExternalShader { static Float sqrt_approx[20001]; #endif -Uint32 ParticlesNum = 30000; +static constexpr Uint32 ParticlesNum = 30000; -EE::Window::Window* win = NULL; -Input* imp = NULL; -ShaderProgram* shaderProgram = NULL; -bool ShadersSupported = false; -Float tw; -Float th; -Float aspectRatio; -Vector3ff* vertices = eeNewArray( Vector3ff, ParticlesNum ); -Vector3ff* velocities = eeNewArray( Vector3ff, ParticlesNum ); -ColorAf* colors = eeNewArray( ColorAf, ParticlesNum ); +struct ExampleState { + EE::Window::Window* win{ nullptr }; + Input* input{ nullptr }; + ShaderProgramPtr shaderProgram; + bool shadersSupported{ false }; + Float halfWidth{ 0 }; + Float halfHeight{ 0 }; + Float aspectRatio{ 0 }; + std::vector vertices{ ParticlesNum }; + std::vector velocities{ ParticlesNum }; + std::vector colors{ ParticlesNum }; +}; -void videoResize( EE::Window::Window* ) { +void videoResize( ExampleState& state, EE::Window::Window* ) { + auto* win = state.win; + auto& shaderProgram = state.shaderProgram; /// Video Resize event will re-setup the 2D projection and states, so we must rebuild them. - aspectRatio = (Float)win->getWidth() / (Float)win->getHeight(); - tw = (Float)win->getWidth() / 2; - th = (Float)win->getHeight() / 2; + state.aspectRatio = (Float)win->getWidth() / (Float)win->getHeight(); + state.halfWidth = (Float)win->getWidth() / 2; + state.halfHeight = (Float)win->getHeight() / 2; float fieldOfView = 30.0; float nearPlane = 1.0; float farPlane = 10000.0; float top = nearPlane * eetan( fieldOfView * EE_PI_360 ); float bottom = -top; - float right = top * aspectRatio; + float right = top * state.aspectRatio; float left = -right; float a = ( right + left ) / ( right - left ); @@ -63,7 +67,7 @@ void videoResize( EE::Window::Window* ) { /// Set the line width GLi->lineWidth( 2 ); - if ( ShadersSupported ) { + if ( state.shadersSupported ) { /// Rebind the Shader shaderProgram->bind(); @@ -87,7 +91,13 @@ void videoResize( EE::Window::Window* ) { } // namespace Demo_ExternalShader using namespace Demo_ExternalShader; -void mainLoop() { +void mainLoop( ExampleState& state ) { + auto* win = state.win; + auto* imp = state.input; + auto& vertices = state.vertices; + auto& velocities = state.velocities; + auto& colors = state.colors; + const Float aspectRatio = state.aspectRatio; win->clear(); imp->update(); @@ -108,9 +118,9 @@ void mainLoop() { Float p; Vector2f mf = imp->getMousePos().asFloat(); - Float tratio = tw / th; - Float touchX = ( mf.x / tw - 1 ) * tratio; - Float touchY = -( mf.y / th - 1 ); + Float tratio = state.halfWidth / state.halfHeight; + Float touchX = ( mf.x / state.halfWidth - 1 ) * tratio; + Float touchY = -( mf.y / state.halfHeight - 1 ); bool touch = imp->isMouseLeftPressed(); for ( Uint32 i = 0; i < ParticlesNum; i += 2 ) { @@ -197,7 +207,13 @@ void mainLoop() { win->display(); } -EE_MAIN_FUNC int main( int argc, char* argv[] ) { +static int run() { + ExampleState state; + auto& win = state.win; + auto& shaderProgram = state.shaderProgram; + auto& vertices = state.vertices; + auto& velocities = state.velocities; + auto& colors = state.colors; win = Engine::instance()->createWindow( WindowSettings( 960, 640, "eepp - External Shaders" ), ContextSettings( true ) ); @@ -205,13 +221,13 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { return EXIT_FAILURE; /// This will work without shaders too - ShadersSupported = GLi->shadersSupported(); + state.shadersSupported = GLi->shadersSupported(); - imp = win->getInput(); + state.input = win->getInput(); /// We really don't need shaders for this, but the purpose of the example is to show how to /// work with external shaders - if ( ShadersSupported ) { + if ( state.shadersSupported ) { /// Disable the automatic shader conversion from fixed-pipeline to programmable-pipeline Shader::ensure( false ); @@ -246,10 +262,11 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { } /// Set the projection - videoResize( win ); + videoResize( state, win ); /// Push a window resize callback the reset the projection when needed - win->pushResizeCallback( videoResize ); + win->pushResizeCallback( + [&state]( EE::Window::Window* window ) { videoResize( state, window ); } ); Uint32 i; @@ -269,15 +286,17 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { } #endif - win->runMainLoop( &mainLoop ); + win->runMainLoop( [&state] { mainLoop( state ); } ); - eeSAFE_DELETE_ARRAY( vertices ); - eeSAFE_DELETE_ARRAY( velocities ); - eeSAFE_DELETE_ARRAY( colors ); + return EXIT_SUCCESS; +} + +EE_MAIN_FUNC int main( int, char*[] ) { + int result = run(); Engine::destroySingleton(); MemoryManager::showResults(); - return EXIT_SUCCESS; + return result; } diff --git a/src/examples/vbo_fbo_batch/vbo_fbo_batch.cpp b/src/examples/vbo_fbo_batch/vbo_fbo_batch.cpp index a255fcc72..0daf1b463 100644 --- a/src/examples/vbo_fbo_batch/vbo_fbo_batch.cpp +++ b/src/examples/vbo_fbo_batch/vbo_fbo_batch.cpp @@ -1,118 +1,8 @@ #include -EE::Window::Window* win = NULL; -VertexBuffer* VBO = NULL; -VertexBuffer* VBO2 = NULL; -FrameBuffer* FBO = NULL; - -// The batch renderer class is designed to take control of almost all the rendering needed by the -// engine. Controls that the rendering is only done when is needed, preventing redundant OpenGL API -// calls Usually the user will not need to use this class manually, since eepp controls this -// internally. The engine uses the singleton class GlobalBatchRenderer instance to render textures -// and primitives. -BatchRenderer* Batch = BatchRenderer::New(); - -Float ang = 0, scale = 1; -bool side = false; - -void mainLoop() { - // Clear the screen buffer - win->clear(); - - // Update the input - win->getInput()->update(); - - // Check if ESCAPE key is pressed - if ( win->getInput()->isKeyDown( KEY_ESCAPE ) ) { - // Close the window - win->close(); - } - - // Bind the Frame Buffer, everything rendered from here will be rendered in the frame buffer - FBO->bind(); - { - // Bind the buffered data ( activate the buffer ) - VBO->bind(); - - // Draw the buffered data - VBO->draw(); - - // Unbind the buffered data - VBO->unbind(); - - // Same as above - VBO2->bind(); - VBO2->draw(); - VBO2->unbind(); - } - // Unbind the frame buffer. Stops rendering to the frame buffer - FBO->unbind(); - - // Draw the frame buffer many times - for ( int y = 0; y < 5; y++ ) { - for ( int x = 0; x < 5; x++ ) { - FBO->getTexture()->draw( x * 200, y * 200, -ang, Vector2f::One, - Color( 255, 255, 255, 100 ) ); - } - } - - Float HWidth = win->getWidth() * 0.5f; - Float HHeight = win->getHeight() * 0.5f; - - // The batch can be rotated, scale and moved - Batch->setBatchRotation( ang ); - Batch->setBatchScale( scale ); - Batch->setBatchCenter( Vector2f( HWidth, HHeight ) ); - - // Create a quad to render - Float aX = HWidth - 256.f; - Float aY = HHeight - 256.f; - Quad2f TmpQuad( Vector2f( aX, aY ), Vector2f( aX, aY + 32.f ), Vector2f( aX + 32.f, aY + 32.f ), - Vector2f( aX + 32.f, aY ) ); - TmpQuad.rotate( ang, Vector2f( aX + 16.f, aY + 16.f ) ); - - // Begin drawing quads - Batch->quadsBegin(); - - // Add some quads to the batch renderer - for ( Uint32 z = 0; z < 16; z++ ) { - for ( Uint32 y = 0; y < 16; y++ ) { - Float tmpx = (Float)z * 32.f; - Float tmpy = (Float)y * 32.f; - - // Add the quad to the batch - Batch->quadsSetColor( Color( z * 16, 255, 255, 150 ) ); - Batch->batchQuadFree( TmpQuad[0].x + tmpx, TmpQuad[0].y + tmpy, TmpQuad[1].x + tmpx, - TmpQuad[1].y + tmpy, TmpQuad[2].x + tmpx, TmpQuad[2].y + tmpy, - TmpQuad[3].x + tmpx, TmpQuad[3].y + tmpy ); - } - } - - // Draw the batched quads - Batch->draw(); - - // Add the rotation angle - ang += win->getElapsed().asMilliseconds() * 0.1f; - ang = ( ang >= 360 ) ? 0 : ang; - - // Change the scale value - if ( scale >= 1.5f ) { - scale = 1.5f; - side = true; - } else if ( scale <= 0.5f ) { - side = false; - scale = 0.5f; - } - scale = ( !side ) ? scale + win->getElapsed().asMilliseconds() * 0.00025f - : scale - win->getElapsed().asMilliseconds() * 0.00025f; - - // Draw frame - win->display(); -} - EE_MAIN_FUNC int main( int, char*[] ) { // Create a new window - win = Engine::instance()->createWindow( + auto* win = Engine::instance()->createWindow( WindowSettings( 1024, 768, "eepp - VBO - FBO and Batch Rendering" ), ContextSettings( true ) ); @@ -121,14 +11,18 @@ EE_MAIN_FUNC int main( int, char*[] ) { // Check if created if ( win->isOpen() ) { + auto VBO = VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); + auto VBO2 = VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); + auto FBO = FrameBuffer::New( 200, 200 ); + auto* Batch = BatchRenderer::New(); + Float ang = 0; + Float scale = 1; + bool side = false; Polygon2f Poly( Polygon2f::createRoundedRectangle( 0, 0, 200, 50 ) ); // Create the Vertex Buffer, the vertex buffer stores the vertex data in the GPU, making the // rendering much faster In the case that Vertex Buffer Object is not supported by the GPU, // it will fallback to a immediate-mode vertex buffer - VBO = VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); - VBO2 = VertexBuffer::New( VERTEX_FLAGS_PRIMITIVE, PRIMITIVE_TRIANGLE_FAN ); - // Add the vertex and vertex colors to the Vertex Buffer if ( NULL != VBO && NULL != VBO2 ) { for ( Uint32 i = 0; i < Poly.getSize(); i++ ) { @@ -148,17 +42,66 @@ EE_MAIN_FUNC int main( int, char*[] ) { VBO2->compile(); } - // Create a new frame buffer. It will use Framebuffer Objects if available, otherwise it - // will try to fallback to PBuffers. - FBO = FrameBuffer::New( 200, 200 ); - // Application loop - win->runMainLoop( &mainLoop ); + win->runMainLoop( [&] { + win->clear(); + win->getInput()->update(); + if ( win->getInput()->isKeyDown( KEY_ESCAPE ) ) + win->close(); + + FBO->bind(); + VBO->bind(); + VBO->draw(); + VBO->unbind(); + VBO2->bind(); + VBO2->draw(); + VBO2->unbind(); + FBO->unbind(); + + for ( int y = 0; y < 5; y++ ) + for ( int x = 0; x < 5; x++ ) + FBO->getTexture()->draw( x * 200, y * 200, -ang, Vector2f::One, + Color( 255, 255, 255, 100 ) ); + + Float halfWidth = win->getWidth() * 0.5f; + Float halfHeight = win->getHeight() * 0.5f; + Batch->setBatchRotation( ang ); + Batch->setBatchScale( scale ); + Batch->setBatchCenter( Vector2f( halfWidth, halfHeight ) ); + + Float x = halfWidth - 256.f; + Float y = halfHeight - 256.f; + Quad2f quad( Vector2f( x, y ), Vector2f( x, y + 32.f ), Vector2f( x + 32.f, y + 32.f ), + Vector2f( x + 32.f, y ) ); + quad.rotate( ang, Vector2f( x + 16.f, y + 16.f ) ); + + Batch->quadsBegin(); + for ( Uint32 column = 0; column < 16; column++ ) { + for ( Uint32 row = 0; row < 16; row++ ) { + Float offsetX = static_cast( column ) * 32.f; + Float offsetY = static_cast( row ) * 32.f; + Batch->quadsSetColor( Color( column * 16, 255, 255, 150 ) ); + Batch->batchQuadFree( quad[0].x + offsetX, quad[0].y + offsetY, + quad[1].x + offsetX, quad[1].y + offsetY, + quad[2].x + offsetX, quad[2].y + offsetY, + quad[3].x + offsetX, quad[3].y + offsetY ); + } + } + Batch->draw(); + + ang += win->getElapsed().asMilliseconds() * 0.1f; + ang = ang >= 360 ? 0 : ang; + if ( scale >= 1.5f ) { + scale = 1.5f; + side = true; + } else if ( scale <= 0.5f ) { + scale = 0.5f; + side = false; + } + scale += ( side ? -1.f : 1.f ) * win->getElapsed().asMilliseconds() * 0.00025f; + win->display(); + } ); - // Release the allocated objects ( VBOs and FBOs need to be released manually ) - eeSAFE_DELETE( VBO ); - eeSAFE_DELETE( VBO2 ); - eeSAFE_DELETE( FBO ); eeSAFE_DELETE( Batch ); } diff --git a/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp b/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp index 90aaf2852..8a5f66332 100644 --- a/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp +++ b/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -316,10 +317,10 @@ class TerminalDisplay : public ITerminalDisplay { Uint32 mColumns{ 0 }; Uint32 mRows{ 0 }; Uint32 mClickStep{ 5 }; - FrameBuffer* mFrameBuffer{ nullptr }; - VertexBuffer* mVBBackground{ nullptr }; - VertexBuffer* mVBForeground{ nullptr }; - std::vector mVBStyles; + FrameBufferUniquePtr mFrameBuffer; + VertexBufferUniquePtr mVBBackground; + VertexBufferUniquePtr mVBForeground; + std::vector mVBStyles; TerminalColorScheme mColorScheme; Uint32 mQuadVertex{ 6 }; Primitives mPrimitives; @@ -355,9 +356,9 @@ class TerminalDisplay : public ITerminalDisplay { void drawFrameBuffer(); - void createVBO( VertexBuffer** vbo, bool usesTexCoords ); + void createVBO( VertexBufferUniquePtr& vbo, bool usesTexCoords ); - VertexBuffer* createRowVBO( bool usesTexCoords ); + VertexBufferUniquePtr createRowVBO( bool usesTexCoords ); void initVBOs(); diff --git a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp index 88558790d..67831a668 100644 --- a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp @@ -461,13 +461,7 @@ std::shared_ptr TerminalDisplay::create( return terminal; } -TerminalDisplay::~TerminalDisplay() { - eeSAFE_DELETE( mVBBackground ); - eeSAFE_DELETE( mVBForeground ); - for ( VertexBuffer* vb : mVBStyles ) - eeSAFE_DELETE( vb ); - eeSAFE_DELETE( mFrameBuffer ); -} +TerminalDisplay::~TerminalDisplay() = default; TerminalDisplay::TerminalDisplay( EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize, const bool& useFrameBuffer ) : @@ -1406,7 +1400,7 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { : GlyphDrawable::DrawMode::Text ); if ( mVBForeground ) { - gd->drawIntoVertexBuffer( mVBForeground, mCurGridPos, { x, y } ); + gd->drawIntoVertexBuffer( mVBForeground.get(), mCurGridPos, { x, y } ); } else { gd->draw( { x, y } ); } @@ -1532,12 +1526,12 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { if ( !mVBStyles.empty() ) { if ( dirtyFG ) { - for ( auto vbo : mVBStyles ) { + for ( const auto& vbo : mVBStyles ) { if ( vbo->getVertexCount() ) vbo->update( VERTEX_FLAGS_PRIMITIVE, false ); } } - for ( auto vbo : mVBStyles ) { + for ( const auto& vbo : mVBStyles ) { if ( vbo->getVertexCount() == 0 ) continue; vbo->bind(); @@ -1937,7 +1931,7 @@ Sizei TerminalDisplay::getFrameBufferSize() { } void TerminalDisplay::createFrameBuffer() { - eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer.reset(); Sizei fboSize( getFrameBufferSize() ); if ( fboSize.getWidth() < 1 ) fboSize.setWidth( 1 ); @@ -1946,8 +1940,8 @@ void TerminalDisplay::createFrameBuffer() { mFrameBuffer = FrameBuffer::New( fboSize.getWidth(), fboSize.getHeight(), true ); // Frame buffer failed to create? - if ( !mFrameBuffer->created() ) - eeSAFE_DELETE( mFrameBuffer ); + if ( !mFrameBuffer || !mFrameBuffer->created() ) + mFrameBuffer.reset(); } void TerminalDisplay::drawFrameBuffer() { @@ -1958,8 +1952,8 @@ void TerminalDisplay::drawFrameBuffer() { } } -VertexBuffer* TerminalDisplay::createRowVBO( bool usesTexCoords ) { - auto* VBO = VertexBuffer::NewVertexArray( +VertexBufferUniquePtr TerminalDisplay::createRowVBO( bool usesTexCoords ) { + auto VBO = VertexBuffer::NewVertexArray( usesTexCoords ? VERTEX_FLAGS_DEFAULT : VERTEX_FLAGS_PRIMITIVE, mQuadVertex == 6 ? EE::Graphics::PRIMITIVE_TRIANGLES : EE::Graphics::PRIMITIVE_QUADS, mColumns * mQuadVertex, 0, VertexBufferUsageType::Stream ); @@ -1967,24 +1961,21 @@ VertexBuffer* TerminalDisplay::createRowVBO( bool usesTexCoords ) { return VBO; } -void TerminalDisplay::createVBO( VertexBuffer** vbo, bool usesTexCoords ) { - eeSAFE_DELETE( ( *vbo ) ); - ( *vbo ) = VertexBuffer::New( - usesTexCoords ? VERTEX_FLAGS_DEFAULT : VERTEX_FLAGS_PRIMITIVE, - mQuadVertex == 6 ? EE::Graphics::PRIMITIVE_TRIANGLES : EE::Graphics::PRIMITIVE_QUADS, - mRows * mColumns * mQuadVertex, 0, VertexBufferUsageType::Stream ); - ( *vbo )->resizeArray( VERTEX_FLAG_POSITION, mRows * mColumns * mQuadVertex ); - ( *vbo )->resizeArray( VERTEX_FLAG_COLOR, mRows * mColumns * mQuadVertex ); - ( *vbo )->setGridSize( Sizei( mColumns, mRows ) ); +void TerminalDisplay::createVBO( VertexBufferUniquePtr& vbo, bool usesTexCoords ) { + vbo = VertexBuffer::New( usesTexCoords ? VERTEX_FLAGS_DEFAULT : VERTEX_FLAGS_PRIMITIVE, + mQuadVertex == 6 ? EE::Graphics::PRIMITIVE_TRIANGLES + : EE::Graphics::PRIMITIVE_QUADS, + mRows * mColumns * mQuadVertex, 0, VertexBufferUsageType::Stream ); + vbo->resizeArray( VERTEX_FLAG_POSITION, mRows * mColumns * mQuadVertex ); + vbo->resizeArray( VERTEX_FLAG_COLOR, mRows * mColumns * mQuadVertex ); + vbo->setGridSize( Sizei( mColumns, mRows ) ); if ( usesTexCoords ) - ( *vbo )->resizeArray( VERTEX_FLAG_TEXTURE0, mRows * mColumns * mQuadVertex ); + vbo->resizeArray( VERTEX_FLAG_TEXTURE0, mRows * mColumns * mQuadVertex ); } void TerminalDisplay::initVBOs() { - createVBO( &mVBBackground, false ); - createVBO( &mVBForeground, true ); - for ( VertexBuffer* vb : mVBStyles ) - eeSAFE_DELETE( vb ); + createVBO( mVBBackground, false ); + createVBO( mVBForeground, true ); mVBStyles.clear(); for ( Uint32 i = 0; i < mRows; ++i ) mVBStyles.emplace_back( createRowVBO( false ) ); diff --git a/src/tests/test_all/test.cpp b/src/tests/test_all/test.cpp index 2fd731771..42dd3c9cf 100644 --- a/src/tests/test_all/test.cpp +++ b/src/tests/test_all/test.cpp @@ -11,18 +11,18 @@ namespace Demo_Test { class UIBlurredWindow : public UIWindow { public: - static UIBlurredWindow* New( ShaderProgram* blurShader ) { - return eeNew( UIBlurredWindow, ( blurShader ) ); + static UIBlurredWindow* New( ShaderProgramPtr blurShader ) { + return eeNew( UIBlurredWindow, ( std::move( blurShader ) ) ); } - explicit UIBlurredWindow( ShaderProgram* blurShader ) : - UIWindow(), mBlurShader( blurShader ), mFboBlur( NULL ) {} + explicit UIBlurredWindow( ShaderProgramPtr blurShader ) : + UIWindow(), mBlurShader( std::move( blurShader ) ) {} - ~UIBlurredWindow() { eeSAFE_DELETE( mFboBlur ); } + ~UIBlurredWindow() = default; protected: - ShaderProgram* mBlurShader; - FrameBuffer* mFboBlur; + ShaderProgramPtr mBlurShader; + FrameBufferUniquePtr mFboBlur[2]; void preDraw() { if ( !ownsFrameBuffer() ) @@ -30,47 +30,54 @@ class UIBlurredWindow : public UIWindow { FrameBuffer* curFBO = getSceneNode()->getFrameBuffer(); - if ( NULL != curFBO && NULL != curFBO->getTexture() && NULL != mBlurShader ) { + if ( curFBO && curFBO->getTexture() && mBlurShader ) { static int fboDiv = 2; + const Sizei blurSize( std::max( 1, static_cast( mSize.x / fboDiv ) ), + std::max( 1, static_cast( mSize.y / fboDiv ) ) ); - if ( NULL == mFboBlur ) { - mFboBlur = FrameBuffer::New( mSize.x / fboDiv, mSize.y / fboDiv ); - } else if ( mFboBlur->getSize().getWidth() != (int)( mSize.x / fboDiv ) || - mFboBlur->getSize().getHeight() != (int)( mSize.y / fboDiv ) ) { - mFboBlur->resize( mSize.x / fboDiv, mSize.y / fboDiv ); + for ( auto& fbo : mFboBlur ) { + if ( !fbo ) { + fbo = FrameBuffer::New( blurSize.x, blurSize.y ); + } else if ( fbo->getSize() != blurSize ) { + fbo->resize( blurSize.x, blurSize.y ); + } } + if ( !mFboBlur[0] || !mFboBlur[1] ) + return; TextureRegion textureRegion( curFBO->getTexture(), Rect( mScreenPos.x, mScreenPos.y, mScreenPos.x + mSize.x, mScreenPos.y + mSize.y ) ); RGB cc = getSceneNode()->getWindow()->getClearColor(); - mFboBlur->setClearColor( ColorAf( cc.r / 255.f, cc.g / 255.f, cc.b / 255.f, 1.f ) ); - mFboBlur->bind(); - mFboBlur->clear(); - textureRegion.draw( Vector2f( 0, 0 ), mFboBlur->getSizef() ); - mFboBlur->unbind(); + mFboBlur[0]->setClearColor( ColorAf( cc.r / 255.f, cc.g / 255.f, cc.b / 255.f, 1.f ) ); + mFboBlur[0]->bind(); + mFboBlur[0]->clear(); + textureRegion.draw( Vector2f( 0, 0 ), mFboBlur[0]->getSizef() ); + mFboBlur[0]->unbind(); mBlurShader->bind(); + mBlurShader->setUniform( "textureRes", mFboBlur[0]->getSizef() ); + // Never sample a texture while it is attached to the currently bound draw framebuffer: + // that creates an undefined framebuffer feedback loop. Some desktop OpenGL drivers made + // the old in-place blur appear to work, but GLES/WebGL commonly produce no useful + // output. A separable blur therefore ping-pongs its horizontal and vertical passes + // between two FBO textures: read A/write B, then read B/write A. mBlurShader->setUniform( "dir", (Int32)0 ); - mBlurShader->setUniform( "textureRes", mFboBlur->getSizef() ); - - mFboBlur->bind(); - mFboBlur->getTexture()->draw( Vector2f( 0, 0 ), mFboBlur->getSizef() ); - mFboBlur->unbind(); + mFboBlur[1]->bind(); + mFboBlur[0]->getTexture()->draw( Vector2f( 0, 0 ), mFboBlur[1]->getSizef() ); + mFboBlur[1]->unbind(); mBlurShader->setUniform( "dir", (Int32)1 ); - mBlurShader->setUniform( "textureRes", mFboBlur->getSizef() ); - - mFboBlur->bind(); - mFboBlur->getTexture()->draw( Vector2f( 0, 0 ), mFboBlur->getSizef() ); - mFboBlur->unbind(); + mFboBlur[0]->bind(); + mFboBlur[1]->getTexture()->draw( Vector2f( 0, 0 ), mFboBlur[0]->getSizef() ); + mFboBlur[0]->unbind(); mBlurShader->unbind(); - mFboBlur->getTexture()->draw( Vector2f( mScreenPos.x, mScreenPos.y ), - Sizef( mSize.x, mSize.y ) ); + mFboBlur[0]->getTexture()->draw( Vector2f( mScreenPos.x, mScreenPos.y ), + Sizef( mSize.x, mSize.y ) ); } } }; @@ -292,7 +299,7 @@ void EETest::onFontLoaded() { void EETest::createShaders() { mUseShaders = mUseShaders && GLi->shadersSupported(); - mShaderProgram = NULL; + mShaderProgram.reset(); if ( mUseShaders ) { mBlurFactor = 0.01f; @@ -1930,7 +1937,7 @@ void EETest::input() { Mousef = Vector2f( (Float)Mouse.x, (Float)Mouse.y ); if ( KM->isKeyUp( KEY_F1 ) ) - Graphics::ShaderProgramManager::instance()->reload(); + Graphics::ShaderProgramRegistry::instance()->reload(); UISceneNode* uiSceneNode = SceneManager::instance()->getUISceneNode(); @@ -2548,8 +2555,8 @@ void EETest::end() { eeSAFE_DELETE( Mus ); eeSAFE_DELETE( mTGL ); - eeSAFE_DELETE( mFBO ); - eeSAFE_DELETE( mVBO ); + mFBO.reset(); + mVBO.reset(); mBoxSprite.reset(); mCircleSprite.reset(); eeSAFE_DELETE( PakTest ); diff --git a/src/tests/test_all/test.hpp b/src/tests/test_all/test.hpp index 5e992ec20..8fb304a01 100644 --- a/src/tests/test_all/test.hpp +++ b/src/tests/test_all/test.hpp @@ -108,8 +108,8 @@ class EETest : private Thread { View Views[2]; - ShaderProgram* mShaderProgram; - ShaderProgram* mBlur; + ShaderProgramPtr mShaderProgram; + ShaderProgramPtr mBlur; Float mBlurFactor; bool mUseShaders; @@ -140,8 +140,8 @@ class EETest : private Thread { TextureAtlasLoader* mTGL; Sprite mMonster; - FrameBuffer* mFBO; - VertexBuffer* mVBO; + FrameBufferUniquePtr mFBO; + VertexBufferUniquePtr mVBO; Clock mFTE; Translator mTranslator; @@ -228,7 +228,7 @@ class EETest : private Thread { SpritePtr mBoxSprite; SpritePtr mCircleSprite; - UITheme* mTheme; + UIThemePtr mTheme; UISceneNode* mSceneNode; bool mTerrainUp; diff --git a/src/tests/ui_perf_test/ui_perf_test.cpp b/src/tests/ui_perf_test/ui_perf_test.cpp index 870fc0b79..325bebc3a 100644 --- a/src/tests/ui_perf_test/ui_perf_test.cpp +++ b/src/tests/ui_perf_test/ui_perf_test.cpp @@ -211,15 +211,17 @@ EE_MAIN_FUNC int main( int, char*[] ) { FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); PixelDensity::setPixelDensity( Engine::instance()->getDisplayManager()->getDisplayIndex( 0 )->getPixelDensity() ); - FontTrueType* font = - FontTrueType::New( "NotoSans-Regular", "assets/fonts/NotoSans-Regular.ttf" ).get(); - FontTrueType* iconFont = FontTrueType::New( "icon", "assets/fonts/remixicon.ttf" ).get(); - UIIconTheme* iconTheme = UIIconTheme::New( "remixicon" ); + auto fontHandle = FontTrueType::New( "NotoSans-Regular", "assets/fonts/NotoSans-Regular.ttf" ); + auto iconFontHandle = FontTrueType::New( "icon", "assets/fonts/remixicon.ttf" ); + FontTrueType* font = fontHandle.get(); + FontTrueType* iconFont = iconFontHandle.get(); + auto iconTheme = UIIconTheme::New( "remixicon" ); auto addIcon = [iconTheme, iconFont]( const std::string& name, const Uint32& codePoint ) -> UIIcon* { - auto* icon = UIGlyphIcon::New( name, iconFont, codePoint ); + auto icon = UIGlyphIcon::New( name, iconFont, codePoint ); + auto* result = icon.get(); iconTheme->add( icon ); - return icon; + return result; }; addIcon( "folder", 0xed6a ); addIcon( "folder-open", 0xed70 ); @@ -243,7 +245,7 @@ EE_MAIN_FUNC int main( int, char*[] ) { /*UITheme* theme = UITheme::load( "uitheme" + pd, "uitheme" + pd, "assets/ui/uitheme" + pd + ".eta", font, "assets/ui/uitheme.css" );*/ - UITheme* theme = UITheme::load( "breeze", "breeze", "", font, "assets/ui/breeze.css" ); + auto theme = UITheme::load( "breeze", "breeze", "", font, "assets/ui/breeze.css" ); uiSceneNode->setStyleSheet( theme->getStyleSheet() ); uiSceneNode->getUIThemeManager() ->setDefaultEffectsEnabled( true ) diff --git a/src/tests/unit_tests/resource_prerequisite_tests.cpp b/src/tests/unit_tests/resource_prerequisite_tests.cpp index 58187cec4..236e45214 100644 --- a/src/tests/unit_tests/resource_prerequisite_tests.cpp +++ b/src/tests/unit_tests/resource_prerequisite_tests.cpp @@ -327,6 +327,26 @@ UTEST( ResourcePrerequisites, resourceScopeResolvesPublishedAtlasRegionPatterns EXPECT_EQ( sprite->getNumFrames(), 2u ); } +UTEST( ResourcePrerequisites, resourceScopeOwnsShaderProgramsWhileRegistryOnlyObservesThem ) { + EE::Window::Window* window = createLifecycleTestWindow( "Shader program scope ownership test" ); + ResourceScopePtr scope = ResourceScope::New(); + ShaderProgramPtr program = ShaderProgram::New( "scoped-program" ); + ShaderProgramWeakPtr weakProgram = program; + scope->publishLocalShaderProgram( "scoped-program", program ); + program.reset(); + + ASSERT_FALSE( weakProgram.expired() ); + EXPECT_EQ( scope->findShaderProgram( "scoped-program" ).get(), weakProgram.lock().get() ); + EXPECT_TRUE( ShaderProgramRegistry::existsSingleton() != nullptr ); + + EXPECT_TRUE( scope->eraseLocalShaderProgram( "scoped-program" ) ); + EXPECT_TRUE( weakProgram.expired() ); + + scope.reset(); + window->display( false ); + Engine::destroySingleton(); +} + UTEST( ResourcePrerequisites, textureRegistryTracksStableIdentityAndMemoryWithoutOwning ) { createLifecycleTestWindow( "Texture registry identity test" ); TextureFactory* factory = TextureFactory::instance(); @@ -648,7 +668,7 @@ UTEST( ResourcePrerequisites, uiThemeCatalogIsImportedOnlyByItsOwningScene ) { TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 4, 4 ); ASSERT_TRUE( texture != nullptr ); - UITheme* theme = UITheme::New( "catalog-theme", "catalog-theme" ); + UIThemePtr theme = UITheme::New( "catalog-theme", "catalog-theme" ); NinePatchPtr ninePatch = NinePatch::New( texture, 1, 1, 1, 1, 1, "theme-nine-patch" ); theme->getResourceCatalog()->publishDrawable( "theme-nine-patch", ninePatch ); firstScene->getUIThemeManager()->add( theme ); @@ -658,21 +678,31 @@ UTEST( ResourcePrerequisites, uiThemeCatalogIsImportedOnlyByItsOwningScene ) { EXPECT_EQ( firstResolved->getDrawableType(), Drawable::NINEPATCH ); EXPECT_TRUE( secondScene->getResourceScope()->findDrawable( "theme-nine-patch" ) == nullptr ); - EXPECT_TRUE( firstScene->getUIThemeManager()->remove( theme, false ) ); + EXPECT_TRUE( firstScene->getUIThemeManager()->remove( theme.get() ) ); EXPECT_TRUE( firstScene->getResourceScope()->findDrawable( "theme-nine-patch" ) == nullptr ); - UITheme* defaultOnlyTheme = UITheme::New( "default-only-theme", "default-only-theme" ); + UIThemePtr defaultOnlyTheme = UITheme::New( "default-only-theme", "default-only-theme" ); defaultOnlyTheme->getResourceCatalog()->publishDrawable( "default-nine-patch", ninePatch ); secondScene->getUIThemeManager()->setDefaultTheme( defaultOnlyTheme ); EXPECT_TRUE( secondScene->getResourceScope()->findDrawable( "default-nine-patch" ) != nullptr ); secondScene->getUIThemeManager()->setDefaultTheme( static_cast( nullptr ) ); EXPECT_TRUE( secondScene->getResourceScope()->findDrawable( "default-nine-patch" ) == nullptr ); + UIThemePtr original = UITheme::New( "replace-theme", "replace-theme" ); + UIThemeWeakPtr originalWeak = original; + firstScene->getUIThemeManager()->add( original ); + firstScene->getUIThemeManager()->setDefaultTheme( original.get() ); + original.reset(); + UIThemePtr replacement = UITheme::New( "replace-theme", "replace-theme" ); + firstScene->getUIThemeManager()->add( replacement ); + EXPECT_TRUE( originalWeak.expired() ); + EXPECT_EQ( firstScene->getUIThemeManager()->getDefaultTheme(), replacement.get() ); + firstResolved.reset(); ninePatch.reset(); texture.reset(); - eeDelete( defaultOnlyTheme ); - eeDelete( theme ); + defaultOnlyTheme.reset(); + theme.reset(); eeDelete( secondScene ); eeDelete( firstScene ); window->display( false ); @@ -846,7 +876,7 @@ UTEST( ResourcePrerequisites, textureCreatesIndependentDrawableInstances ) { UTEST( ResourcePrerequisites, uiIconSeparatesSourceLookupFromInstanceCreation ) { auto instanceCount = std::make_shared( 0 ); DrawablePtr source = makeResource( instanceCount ); - UIIcon* icon = UIIcon::New( "counting-icon" ); + UIIconPtr icon = UIIcon::New( "counting-icon" ); icon->setSource( 16, source ); const DrawablePtr& exactSource = icon->getSource( 16 ); @@ -867,7 +897,7 @@ UTEST( ResourcePrerequisites, uiIconSeparatesSourceLookupFromInstanceCreation ) EXPECT_TRUE( source->getColor() == Color::White ); EXPECT_TRUE( second->getColor() == Color::White ); - eeDelete( icon ); + icon.reset(); } UTEST( ResourcePrerequisites, stateListsCloneStateAndChildrenIndependently ) { @@ -1185,9 +1215,9 @@ UTEST( ResourcePrerequisites, engineTeardownReleasesGraphicsBeforeContextsAcross EXPECT_TRUE( SceneManager::existsSingleton() == nullptr ); EXPECT_TRUE( GlobalBatchRenderer::existsSingleton() == nullptr ); EXPECT_TRUE( TextureFactory::existsSingleton() == nullptr ); - EXPECT_TRUE( ShaderProgramManager::existsSingleton() == nullptr ); - EXPECT_TRUE( Graphics::Private::FrameBufferManager::existsSingleton() == nullptr ); - EXPECT_TRUE( Graphics::Private::VertexBufferManager::existsSingleton() == nullptr ); + EXPECT_TRUE( ShaderProgramRegistry::existsSingleton() == nullptr ); + EXPECT_TRUE( Graphics::Private::FrameBufferRegistry::existsSingleton() == nullptr ); + EXPECT_TRUE( Graphics::Private::VertexBufferRegistry::existsSingleton() == nullptr ); EXPECT_TRUE( Renderer::existsSingleton() == nullptr ); } } diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 66fde0b27..458f36de9 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1905,7 +1905,7 @@ const SyntaxColorScheme* App::getCurrentColorScheme() const { } void App::setTheme( const std::string& path ) { - UITheme* theme = nullptr; + UIThemePtr theme; if ( path == "syntax_color_scheme" ) { const SyntaxColorScheme* colorScheme = getCurrentColorScheme(); @@ -1965,12 +1965,12 @@ void App::setTheme( const std::string& path ) { ->setDefaultFontSize( mConfig.ui.fontSize.asPixels( 0, Sizef(), mDisplayDPI ) ) ->add( theme ); - mUISceneNode->setTheme( theme ); + mUISceneNode->setTheme( theme.get() ); mUISceneNode->getRoot()->addClass( "appbackground" ); if ( mTheme ) - mUISceneNode->getUIThemeManager()->remove( mTheme ); + mUISceneNode->getUIThemeManager()->remove( mTheme.get() ); mTheme = theme; diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index e5b3927da..5814d6e7f 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -755,7 +755,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { std::unique_ptr mDateTimeController; std::unique_ptr mFontPickerController; std::string mFileToOpen; - UITheme* mTheme{ nullptr }; + UIThemePtr mTheme; UIStatusBar* mStatusBar{ nullptr }; UISplitter* mMainSplitter{ nullptr }; UIMessageBox* mCloseMsgBox{ nullptr }; diff --git a/src/tools/mapeditor/mapeditor.cpp b/src/tools/mapeditor/mapeditor.cpp index 53b323eb9..853952fb6 100644 --- a/src/tools/mapeditor/mapeditor.cpp +++ b/src/tools/mapeditor/mapeditor.cpp @@ -109,9 +109,9 @@ EE_MAIN_FUNC int main( int, char*[] ) { resPath + "assets/fonts/NotoSans-Regular.ttf", *uiSceneNode->getResourceScope() ); - UITheme* theme = UITheme::load( "uitheme" + pd, "uitheme" + pd, - resPath + "assets/ui/uitheme" + pd + ".eta", font.get(), - resPath + "assets/ui/uitheme.css" ); + auto theme = UITheme::load( "uitheme" + pd, "uitheme" + pd, + resPath + "assets/ui/uitheme" + pd + ".eta", font.get(), + resPath + "assets/ui/uitheme.css" ); /*UITheme* theme = UITheme::load( "uitheme", "uitheme", "", font, resPath + "assets/ui/breeze.css" );*/ diff --git a/src/tools/textureatlaseditor/textureatlaseditor.cpp b/src/tools/textureatlaseditor/textureatlaseditor.cpp index db0e61b85..093e3eca6 100644 --- a/src/tools/textureatlaseditor/textureatlaseditor.cpp +++ b/src/tools/textureatlaseditor/textureatlaseditor.cpp @@ -116,8 +116,8 @@ EE_MAIN_FUNC int main( int, char*[] ) { /*UITheme* theme = UITheme::load( "uitheme" + pd, "uitheme" + pd, resPath + * "assets/ui/uitheme" + pd + ".eta", font, resPath + "assets/ui/uitheme.css" );*/ - UITheme* theme = UITheme::load( "uitheme", "uitheme", "", font.get(), - resPath + "assets/ui/breeze.css" ); + auto theme = UITheme::load( "uitheme", "uitheme", "", font.get(), + resPath + "assets/ui/breeze.css" ); uiSceneNode->combineStyleSheet( theme->getStyleSheet() ); diff --git a/src/tools/uieditor/uieditor.cpp b/src/tools/uieditor/uieditor.cpp index f82c804f5..fc904e943 100644 --- a/src/tools/uieditor/uieditor.cpp +++ b/src/tools/uieditor/uieditor.cpp @@ -593,7 +593,7 @@ void App::loadUITheme( std::string themePath ) { std::string name( FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( themePath ) ) ); - UITheme* uitheme = + auto uitheme = UITheme::loadFromTextureAtlas( UITheme::New( name, name ), tgl.getTextureAtlas() ); mUISceneNode->getUIThemeManager()->setDefaultTheme( uitheme )->add( uitheme ); @@ -654,7 +654,7 @@ void App::refreshLayoutList() { } void App::loadProjectNodes( pugi::xml_node node ) { - mUISceneNode->getUIThemeManager()->setDefaultTheme( mUseDefaultTheme ? mTheme : NULL ); + mUISceneNode->getUIThemeManager()->setDefaultTheme( mUseDefaultTheme ? mTheme : UIThemePtr{} ); for ( pugi::xml_node resources = node; resources; resources = resources.next_sibling() ) { std::string name = String::toLower( std::string( resources.name() ) ); @@ -876,7 +876,7 @@ bool App::onCloseRequestCallback( EE::Window::Window* ) { mMsgBox = UIMessageBox::New( UIMessageBox::OK_CANCEL, "Do you really want to close the current file?\nAll changes will be lost." ); - mMsgBox->setTheme( mTheme ); + mMsgBox->setTheme( mTheme.get() ); mMsgBox->on( Event::OnConfirm, [this]( const Event* ) { mWindow->close(); } ); mMsgBox->on( Event::OnWindowClose, [this]( const Event* ) { mMsgBox = NULL; } ); mMsgBox->setTitle( "Close Editor?" ); @@ -970,7 +970,7 @@ void App::projectOpen( const Event* event ) { void App::showFileDialog( const String& title, const std::function& cb, const std::string& filePattern, const Uint32& dialogFlags ) { UIFileDialog* dialog = UIFileDialog::New( dialogFlags, filePattern ); - dialog->setTheme( mTheme ); + dialog->setTheme( mTheme.get() ); dialog->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_MAXIMIZE_BUTTON | UI_WIN_MODAL ); dialog->setTitle( title ); dialog->on( Event::OpenFile, cb ); @@ -1303,10 +1303,8 @@ void App::init( const Float& pixelDensityConf, const bool& useAppTheme, const st FontTrueType* noniconsFont = loadFont( "nonicons", "fonts/nonicons.ttf" ); FontTrueType* codIconFont = loadFont( "codicon", "fonts/codicon.ttf" ); - UIIconTheme* iconTheme = - IconManager::init( "icons", remixIconFont, noniconsFont, codIconFont ); - UIIconTheme* iconTheme2 = - IconManager::init( "icons", remixIconFont, noniconsFont, codIconFont ); + auto iconTheme = IconManager::init( "icons", remixIconFont, noniconsFont, codIconFont ); + auto iconTheme2 = IconManager::init( "icons", remixIconFont, noniconsFont, codIconFont ); StyleSheetLength fontSize{ 11, StyleSheetLength::Dp }; mMenuIconSize = fontSize.asPixels( 0, Sizef(), mDisplayDPI ); mAppUISceneNode->setStyleSheet( mTheme->getStyleSheet() ); diff --git a/src/tools/uieditor/uieditor.hpp b/src/tools/uieditor/uieditor.hpp index 41e3383c1..bb73c241a 100644 --- a/src/tools/uieditor/uieditor.hpp +++ b/src/tools/uieditor/uieditor.hpp @@ -158,7 +158,7 @@ class App : public UICodeEditorSplitter::Client { EE::Window::Window* mWindow{ nullptr }; UIMessageBox* mMsgBox{ nullptr }; efsw::FileWatcher* mFileWatcher{ nullptr }; - UITheme* mTheme{ nullptr }; + UIThemePtr mTheme; UIWindow* mUIContainer{ nullptr }; UIMenuBar* mUIMenuBar{ nullptr }; UISceneNode* mUISceneNode{ nullptr };