| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #pragma once
- #include "BsIReflectable.h"
- namespace BansheeEngine
- {
- /** @addtogroup Implementation
- * @{
- */
- /** Data that is shared between all resource handles. */
- struct BS_CORE_EXPORT ResourceHandleData
- {
- ResourceHandleData()
- :mIsCreated(false), mRefCount(0)
- { }
- SPtr<Resource> mPtr;
- String mUUID;
- bool mIsCreated;
- UINT32 mRefCount;
- };
- /**
- * Represents a handle to a resource. Handles are similar to a smart pointers, but they have two advantages:
- * - When loading a resource asynchronously you can be immediately returned the handle that you may use throughout
- * the engine. The handle will be made valid as soon as the resource is loaded.
- * - Handles can be serialized and deserialized, therefore saving/restoring references to their original resource.
- */
- class BS_CORE_EXPORT ResourceHandleBase : public IReflectable
- {
- public:
- virtual ~ResourceHandleBase();
- /**
- * Checks if the resource is loaded. Until resource is loaded this handle is invalid and you may not get the
- * internal resource from it.
- *
- * @param[in] checkDependencies If true, and if resource has any dependencies, this method will also check if
- * they are loaded.
- */
- bool isLoaded(bool checkDependencies = true) const;
- /**
- * Blocks the current thread until the resource is fully loaded.
- *
- * @note Careful not to call this on the thread that does the loading.
- */
- void blockUntilLoaded(bool waitForDependencies = true) const;
- /**
- * Releases an internal reference to this resource held by the resources system, if there is one.
- *
- * @see Resources::release(ResourceHandleBase&)
- */
- void release();
- /** Returns the UUID of the resource the handle is referring to. */
- const String& getUUID() const { return mData != nullptr ? mData->mUUID : StringUtil::BLANK; }
- public: // ***** INTERNAL ******
- /** @name Internal
- * @{
- */
- /** Gets the handle data. For internal use only. */
- const SPtr<ResourceHandleData>& getHandleData() const { return mData; }
- /** @} */
- protected:
- ResourceHandleBase();
- /** Destroys the resource the handle is pointing to. */
- void destroy();
- /**
- * Sets the created flag to true and assigns the resource pointer. Called by the constructors, or if you
- * constructed just using a UUID, then you need to call this manually before you can access the resource from
- * this handle.
- *
- * @note
- * This is needed because two part construction is required due to multithreaded nature of resource loading.
- * @note
- * Internal method.
- */
- void setHandleData(const SPtr<Resource>& ptr, const String& uuid);
- /** Increments the reference count of the handle. Only to be used by Resources for keeping internal references. */
- void addInternalRef();
- /** Decrements the reference count of the handle. Only to be used by ::Resources for keeping internal references. */
- void removeInternalRef();
- /**
- * @note
- * All handles to the same source must share this same handle data. Otherwise things like counting number of
- * references or replacing pointed to resource become impossible without additional logic. */
- SPtr<ResourceHandleData> mData;
- private:
- friend class Resources;
- BS_STATIC_THREAD_SYNCHRONISER(mResourceCreatedCondition)
- BS_STATIC_MUTEX(mResourceCreatedMutex)
- protected:
- inline void throwIfNotLoaded() const;
- };
- /**
- * @copydoc ResourceHandleBase
- *
- * Handles differences in reference counting depending if the handle is normal or weak.
- */
- template <bool WeakHandle>
- class BS_CORE_EXPORT TResourceHandleBase : public ResourceHandleBase { };
- /** Specialization of TResourceHandleBase for weak handles. Weak handles do no reference counting. */
- template<>
- class BS_CORE_EXPORT TResourceHandleBase<true> : public ResourceHandleBase
- {
- public:
- virtual ~TResourceHandleBase() { }
- protected:
- void addRef() { };
- void releaseRef() { };
- /************************************************************************/
- /* RTTI */
- /************************************************************************/
- public:
- friend class WeakResourceHandleRTTI;
- static RTTITypeBase* getRTTIStatic();
- virtual RTTITypeBase* getRTTI() const override;
- };
- /** Specialization of TResourceHandleBase for normal (non-weak) handles. */
- template<>
- class BS_CORE_EXPORT TResourceHandleBase<false> : public ResourceHandleBase
- {
- public:
- virtual ~TResourceHandleBase() { }
- protected:
- void addRef() { if (mData) mData->mRefCount++; };
- void releaseRef()
- {
- if (mData)
- {
- mData->mRefCount--;
- if (mData->mRefCount == 0)
- destroy();
- }
- };
- /************************************************************************/
- /* RTTI */
- /************************************************************************/
- public:
- friend class WeakResourceHandleRTTI;
- friend class ResourceHandleRTTI;
- static RTTITypeBase* getRTTIStatic();
- virtual RTTITypeBase* getRTTI() const override;
- };
- /** @copydoc ResourceHandleBase */
- template <typename T, bool WeakHandle>
- class TResourceHandle : public TResourceHandleBase<WeakHandle>
- {
- public:
- TResourceHandle()
- :TResourceHandleBase()
- { }
- /** Copy constructor. */
- TResourceHandle(const TResourceHandle<T, WeakHandle>& ptr)
- :TResourceHandleBase()
- {
- mData = ptr.getHandleData();
- addRef();
- }
- virtual ~TResourceHandle()
- {
- releaseRef();
- }
- /** Converts a specific handle to generic Resource handle. */
- operator TResourceHandle<Resource, WeakHandle>() const
- {
- TResourceHandle<Resource, WeakHandle> handle;
- handle.setHandleData(getHandleData());
- return handle;
- }
- /**
- * Returns internal resource pointer.
- *
- * @note Throws exception if handle is invalid.
- */
- T* operator->() const { return get(); }
- /**
- * Returns internal resource pointer and dereferences it.
- *
- * @note Throws exception if handle is invalid.
- */
- T& operator*() const { return *get(); }
- /** Clears the handle making it invalid and releases any references held to the resource. */
- TResourceHandle<T, WeakHandle>& operator=(std::nullptr_t ptr)
- {
- releaseRef();
- mData = nullptr;
- return *this;
- }
- /** Normal assignment operator. */
- TResourceHandle<T, WeakHandle>& operator=(const TResourceHandle<T, WeakHandle>& rhs)
- {
- setHandleData(rhs.getHandleData());
- return *this;
- }
- template<class _Ty>
- struct Bool_struct
- {
- int _Member;
- };
- /**
- * Allows direct conversion of handle to bool.
- *
- * @note This is needed because we can't directly convert to bool since then we can assign pointer to bool and
- * that's weird.
- */
- operator int Bool_struct<T>::*() const
- {
- return ((mData != nullptr && !mData->mUUID.empty()) ? &Bool_struct<T>::_Member : 0);
- }
- /**
- * Returns internal resource pointer and dereferences it.
- *
- * @note Throws exception if handle is invalid.
- */
- T* get() const
- {
- throwIfNotLoaded();
- return reinterpret_cast<T*>(mData->mPtr.get());
- }
- /**
- * Returns the internal shared pointer to the resource.
- *
- * @note Throws exception if handle is invalid.
- */
- SPtr<T> getInternalPtr() const
- {
- throwIfNotLoaded();
- return std::static_pointer_cast<T>(mData->mPtr);
- }
- /** Converts a handle into a weak handle. */
- TResourceHandle<T, true> getWeak() const
- {
- TResourceHandle<T, true> handle;
- handle.setHandleData(getHandleData());
- return handle;
- }
- protected:
- friend Resources;
- template<class _T, bool _Weak>
- friend class TResourceHandle;
- template<class _Ty1, class _Ty2, bool Weak>
- friend TResourceHandle<_Ty1, Weak> static_resource_cast(const TResourceHandle<_Ty2, Weak>& other);
- /**
- * Constructs a new valid handle for the provided resource with the provided UUID.
- *
- * @note Handle will take ownership of the provided resource pointer, so make sure you don't delete it elsewhere.
- */
- explicit TResourceHandle(T* ptr, const String& uuid)
- :TResourceHandleBase()
- {
- mData = bs_shared_ptr_new<ResourceHandleData>();
- addRef();
- setHandleData(std::shared_ptr<Resource>(ptr, uuid));
- }
- /**
- * Constructs an invalid handle with the specified UUID. You must call setHandleData() with the actual resource
- * pointer to make the handle valid.
- */
- TResourceHandle(const String& uuid)
- :TResourceHandleBase()
- {
- mData = bs_shared_ptr_new<ResourceHandleData>();
- mData->mUUID = uuid;
- addRef();
- }
- /** Constructs a new valid handle for the provided resource with the provided UUID. */
- TResourceHandle(const SPtr<T> ptr, const String& uuid)
- :TResourceHandleBase()
- {
- mData = bs_shared_ptr_new<ResourceHandleData>();
- addRef();
- setHandleData(ptr, uuid);
- }
- /** Replaces the internal handle data pointer, effectively transforming the handle into a different handle. */
- void setHandleData(const SPtr<ResourceHandleData>& data)
- {
- releaseRef();
- mData = data;
- addRef();
- }
- /** Converts a weak handle into a normal handle. */
- TResourceHandle<T, false> lock() const
- {
- TResourceHandle<Resource, false> handle;
- handle.setHandleData(getHandleData());
- return handle;
- }
- using TResourceHandleBase::setHandleData;
- };
- /** Checks if two handles point to the same resource. */
- template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
- bool operator==(const TResourceHandle<_Ty1, _Weak1>& _Left, const TResourceHandle<_Ty2, _Weak2>& _Right)
- {
- if(_Left.getHandleData() != nullptr && _Right.getHandleData() != nullptr)
- return _Left.getHandleData()->mPtr == _Right.getHandleData()->mPtr;
- return _Left.getHandleData() == _Right.getHandleData();
- }
- /** Checks if a handle is null. */
- template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
- bool operator==(const TResourceHandle<_Ty1, _Weak1>& _Left, std::nullptr_t _Right)
- {
- return _Left.getHandleData() == nullptr || _Left.getHandleData()->mUUID.empty();
- }
- template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
- bool operator!=(const TResourceHandle<_Ty1, _Weak1>& _Left, const TResourceHandle<_Ty2, _Weak2>& _Right)
- {
- return (!(_Left == _Right));
- }
- /** @} */
- /** @addtogroup Resources
- * @{
- */
- /** @copydoc ResourceHandleBase */
- template <typename T>
- using ResourceHandle = TResourceHandle<T, false>;
- /**
- * @copydoc ResourceHandleBase
- *
- * Weak handles don't prevent the resource from being unloaded.
- */
- template <typename T>
- using WeakResourceHandle = TResourceHandle<T, true>;
- /** Casts one resource handle to another. */
- template<class _Ty1, class _Ty2, bool Weak>
- TResourceHandle<_Ty1, Weak> static_resource_cast(const TResourceHandle<_Ty2, Weak>& other)
- {
- TResourceHandle<_Ty1, Weak> handle;
- handle.setHandleData(other.getHandleData());
- return handle;
- }
- /** @} */
- }
|