Przeglądaj źródła

More resource async loading work

Marko Pintera 13 lat temu
rodzic
commit
8e4d885080

+ 2 - 2
CamelotD3D9Renderer/Include/CmD3D9GpuProgram.h

@@ -42,9 +42,9 @@ namespace CamelotEngine {
         D3D9GpuProgram();
         D3D9GpuProgram();
         ~D3D9GpuProgram();
         ~D3D9GpuProgram();
 
 
-		virtual void loadImpl(void);
+		virtual void initImpl(void);
 		/** Loads this program to specified device */
 		/** Loads this program to specified device */
-		virtual void loadImpl(IDirect3DDevice9* d3d9Device);
+		virtual void initImpl(IDirect3DDevice9* d3d9Device);
 		/** Overridden from GpuProgram */
 		/** Overridden from GpuProgram */
 		virtual void unload(void);
 		virtual void unload(void);
 
 

+ 2 - 2
CamelotD3D9Renderer/Include/CmD3D9Texture.h

@@ -130,7 +130,7 @@ namespace CamelotEngine {
 		void _createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources);
 		void _createSurfaceList(IDirect3DDevice9* d3d9Device, TextureResources* textureResources);
 	 
 	 
 		/// Loads this texture into the specified device.
 		/// Loads this texture into the specified device.
-		void loadImpl(IDirect3DDevice9* d3d9Device);
+		void initImpl(IDirect3DDevice9* d3d9Device);
 
 
 		/// gets the texture resources attached to the given device.
 		/// gets the texture resources attached to the given device.
 		TextureResources* getTextureResources(IDirect3DDevice9* d3d9Device);
 		TextureResources* getTextureResources(IDirect3DDevice9* d3d9Device);
@@ -157,7 +157,7 @@ namespace CamelotEngine {
 		void copyToTexture( TexturePtr& target );
 		void copyToTexture( TexturePtr& target );
 
 
 		/// overriden from Resource
 		/// overriden from Resource
-		void loadImpl();	
+		void initImpl();	
 
 
 		/// @copydoc Texture::getBuffer
 		/// @copydoc Texture::getBuffer
 		HardwarePixelBufferPtr getBuffer(size_t face, size_t mipmap);
 		HardwarePixelBufferPtr getBuffer(size_t face, size_t mipmap);

+ 5 - 5
CamelotD3D9Renderer/Source/CmD3D9GpuProgram.cpp

@@ -73,7 +73,7 @@ namespace CamelotEngine {
 	}
 	}
 
 
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
-    void D3D9GpuProgram::loadImpl(void)
+    void D3D9GpuProgram::initImpl(void)
     {
     {
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
 
@@ -81,12 +81,12 @@ namespace CamelotEngine {
 		{
 		{
 			IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
 			IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
 
 
-			loadImpl(d3d9Device);
+			initImpl(d3d9Device);
 		}		       
 		}		       
     }
     }
 
 
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
-	void D3D9GpuProgram::loadImpl(IDirect3DDevice9* d3d9Device)
+	void D3D9GpuProgram::initImpl(IDirect3DDevice9* d3d9Device)
 	{
 	{
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
 
@@ -263,7 +263,7 @@ namespace CamelotEngine {
 		// Shader was not found -> load it.
 		// Shader was not found -> load it.
 		if (it == mMapDeviceToVertexShader.end())		
 		if (it == mMapDeviceToVertexShader.end())		
 		{
 		{
-			loadImpl(d3d9Device);		
+			initImpl(d3d9Device);		
 			it = mMapDeviceToVertexShader.find(d3d9Device);
 			it = mMapDeviceToVertexShader.find(d3d9Device);
 		}
 		}
 	
 	
@@ -366,7 +366,7 @@ namespace CamelotEngine {
 		// Shader was not found -> load it.
 		// Shader was not found -> load it.
 		if (it == mMapDeviceToPixelShader.end())		
 		if (it == mMapDeviceToPixelShader.end())		
 		{
 		{
-			loadImpl(d3d9Device);			
+			initImpl(d3d9Device);			
 			it = mMapDeviceToPixelShader.find(d3d9Device);
 			it = mMapDeviceToPixelShader.find(d3d9Device);
 		}
 		}
 
 

+ 3 - 3
CamelotD3D9Renderer/Source/CmD3D9Texture.cpp

@@ -181,7 +181,7 @@ namespace CamelotEngine
 		}		
 		}		
 	}
 	}
 	/****************************************************************************************/
 	/****************************************************************************************/
-	void D3D9Texture::loadImpl()
+	void D3D9Texture::initImpl()
 	{
 	{
 		if (!mInternalResourcesCreated)
 		if (!mInternalResourcesCreated)
 		{
 		{
@@ -197,12 +197,12 @@ namespace CamelotEngine
 		{
 		{
 			IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
 			IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
 
 
-			loadImpl(d3d9Device);
+			initImpl(d3d9Device);
 		}		
 		}		
 	}
 	}
 
 
 	/****************************************************************************************/
 	/****************************************************************************************/
-	void D3D9Texture::loadImpl(IDirect3DDevice9* d3d9Device)
+	void D3D9Texture::initImpl(IDirect3DDevice9* d3d9Device)
 	{		
 	{		
 		if (mUsage & TU_RENDERTARGET)
 		if (mUsage & TU_RENDERTARGET)
 		{
 		{

+ 1 - 1
CamelotGLRenderer/Include/CmGLTexture.h

@@ -61,7 +61,7 @@ namespace CamelotEngine {
 		void getCustomAttribute(const String& name, void* pData);
 		void getCustomAttribute(const String& name, void* pData);
 
 
 		/// @copydoc Resource::loadImpl
 		/// @copydoc Resource::loadImpl
-		void loadImpl();
+		void initImpl();
 
 
     protected:
     protected:
 		/// @copydoc Texture::createInternalResourcesImpl
 		/// @copydoc Texture::createInternalResourcesImpl

+ 1 - 1
CamelotGLRenderer/Source/CmGLTexture.cpp

@@ -246,7 +246,7 @@ namespace CamelotEngine {
         createInternalResources();
         createInternalResources();
     }
     }
 
 
-    void GLTexture::loadImpl()
+    void GLTexture::initImpl()
     {
     {
         if( mUsage & TU_RENDERTARGET )
         if( mUsage & TU_RENDERTARGET )
         {
         {

+ 1 - 1
CamelotGLRenderer/Source/GLSL/include/CmGLSLGpuProgram.h

@@ -92,7 +92,7 @@ namespace CamelotEngine {
 		/// @copydoc Resource::unloadImpl
 		/// @copydoc Resource::unloadImpl
 		void unloadImpl(void);
 		void unloadImpl(void);
 		/// @copydoc Resource::loadImpl
 		/// @copydoc Resource::loadImpl
-		void loadImpl(void);
+		void initImpl(void);
 
 
 
 
     };
     };

+ 1 - 1
CamelotGLRenderer/Source/GLSL/src/CmGLSLGpuProgram.cpp

@@ -66,7 +66,7 @@ namespace CamelotEngine {
         unload(); 
         unload(); 
     }
     }
 	//-----------------------------------------------------------------------------
 	//-----------------------------------------------------------------------------
-    void GLSLGpuProgram::loadImpl(void)
+    void GLSLGpuProgram::initImpl(void)
     {
     {
 		// nothing to load
 		// nothing to load
     }
     }

+ 1 - 1
CamelotRenderer/Include/CmGpuProgram.h

@@ -118,7 +118,7 @@ namespace CamelotEngine {
 
 
 		virtual ~GpuProgram() {}
 		virtual ~GpuProgram() {}
 
 
-		virtual void loadImpl();
+		virtual void initImpl();
 		virtual void unload() {}
 		virtual void unload() {}
 
 
 		/** Sets the source assembly for this program from an in-memory string.
 		/** Sets the source assembly for this program from an in-memory string.

+ 1 - 1
CamelotRenderer/Include/CmHighLevelGpuProgram.h

@@ -98,7 +98,7 @@ namespace CamelotEngine {
         HighLevelGpuProgram();
         HighLevelGpuProgram();
         ~HighLevelGpuProgram();
         ~HighLevelGpuProgram();
 
 
-		virtual void loadImpl();
+		virtual void initImpl();
 		virtual void unload();
 		virtual void unload();
 
 
         /** Creates a new parameters object compatible with this program definition. 
         /** Creates a new parameters object compatible with this program definition. 

+ 1 - 1
CamelotRenderer/Include/CmMesh.h

@@ -40,7 +40,7 @@ namespace CamelotEngine
 
 
 		RenderOperation getRenderOperation(UINT32 subMeshIdx = 0) const;
 		RenderOperation getRenderOperation(UINT32 subMeshIdx = 0) const;
 
 
-		virtual void loadImpl();
+		virtual void initImpl();
 
 
 	private:
 	private:
 		MeshDataPtr mMeshData;
 		MeshDataPtr mMeshData;

+ 2 - 0
CamelotRenderer/Include/CmPrerequisites.h

@@ -102,6 +102,7 @@ namespace CamelotEngine {
 	class Renderable;
 	class Renderable;
 	class Renderer;
 	class Renderer;
 	class RendererFactory;
 	class RendererFactory;
+	class WorkQueue;
 	// Asset import
 	// Asset import
 	class SpecificImporter;
 	class SpecificImporter;
 	class Importer;
 	class Importer;
@@ -137,6 +138,7 @@ namespace CamelotEngine
 	typedef std::shared_ptr<Material> MaterialPtr;
 	typedef std::shared_ptr<Material> MaterialPtr;
 	typedef std::shared_ptr<Renderer> RendererPtr;
 	typedef std::shared_ptr<Renderer> RendererPtr;
 	typedef std::shared_ptr<RendererFactory> RendererFactoryPtr;
 	typedef std::shared_ptr<RendererFactory> RendererFactoryPtr;
+	typedef std::shared_ptr<WorkQueue> WorkQueuePtr;
 
 
 	typedef std::shared_ptr<Component> ComponentPtr;
 	typedef std::shared_ptr<Component> ComponentPtr;
 	typedef std::shared_ptr<GameObject> GameObjectPtr;
 	typedef std::shared_ptr<GameObject> GameObjectPtr;

+ 3 - 9
CamelotRenderer/Include/CmResource.h

@@ -5,12 +5,6 @@
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	enum ResourceState
-	{
-		RS_Unloaded,
-		RS_Loaded
-	};
-
 	/**
 	/**
 	 * @brief	Base class for all resources used in the engine.
 	 * @brief	Base class for all resources used in the engine.
 	 */
 	 */
@@ -20,8 +14,8 @@ namespace CamelotEngine
 		Resource();
 		Resource();
 		virtual ~Resource() {};
 		virtual ~Resource() {};
 
 
-		void load();
-		virtual void loadImpl() = 0;
+		void init();
+		virtual void initImpl() = 0;
 
 
 		const String& getUUID() const { return mUUID; }
 		const String& getUUID() const { return mUUID; }
 
 
@@ -36,7 +30,7 @@ namespace CamelotEngine
 		UINT32 mSize;
 		UINT32 mSize;
 
 
 		// Transient
 		// Transient
-		ResourceState mLoadState;
+		bool mInitialized;
 
 
 	/************************************************************************/
 	/************************************************************************/
 	/* 								SERIALIZATION                      		*/
 	/* 								SERIALIZATION                      		*/

+ 24 - 4
CamelotRenderer/Include/CmResourceRef.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "CmIReflectable.h"
 #include "CmIReflectable.h"
+#include <atomic>
 
 
 template<class _Ty>
 template<class _Ty>
 struct CM_Bool_struct
 struct CM_Bool_struct
@@ -16,20 +17,31 @@ namespace CamelotEngine
 	struct CM_EXPORT ResourceRefData : public IReflectable
 	struct CM_EXPORT ResourceRefData : public IReflectable
 	{
 	{
 		ResourceRefData()
 		ResourceRefData()
-			:mUUIDSet(false)
-		{ }
+		{
+			mIsResolved.store(false);
+		}
 
 
 		std::shared_ptr<Resource> mPtr;
 		std::shared_ptr<Resource> mPtr;
 		String mUUID;
 		String mUUID;
-		bool mUUIDSet;
+		std::atomic_bool mIsResolved; // TODO Low priority. I might not need an atomic here. Volatile bool should do.
 
 
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
 		friend class ResourceRefDataRTTI;
 		friend class ResourceRefDataRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;
+		virtual RTTITypeBase* getRTTI() const;		
 	};
 	};
 
 
 	class CM_EXPORT ResourceRefBase : public IReflectable
 	class CM_EXPORT ResourceRefBase : public IReflectable
 	{
 	{
+	public:
+		/**
+		 * @brief	Checks if the resource is loaded
+		 */
+		bool isResolved() { return mData->mIsResolved.load(); }
+
 	protected:
 	protected:
 		ResourceRefBase();
 		ResourceRefBase();
 
 
@@ -43,6 +55,13 @@ namespace CamelotEngine
 		{
 		{
 			init(std::static_pointer_cast<Resource>(ptr.mData->mPtr));
 			init(std::static_pointer_cast<Resource>(ptr.mData->mPtr));
 		}
 		}
+	private:
+		friend class Resources;
+		/**
+		 * @brief	Sets the resolved flag to true. Should only be called
+		 * 			by Resources class after loading of the resource is fully done.
+		 */
+		void resolve(std::shared_ptr<Resource> ptr);
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
@@ -85,6 +104,7 @@ namespace CamelotEngine
 			return ResourceRef<Resource>(mData->mPtr); 
 			return ResourceRef<Resource>(mData->mPtr); 
 		}
 		}
 
 
+		// TODO Low priority - User can currently try to access these even if resource ptr is not resolved
 		T* get() const { return static_cast<T*>(mData->mPtr.get()); }
 		T* get() const { return static_cast<T*>(mData->mPtr.get()); }
 		T* operator->() const { return get(); }
 		T* operator->() const { return get(); }
 		T& operator*() const { return *get(); }
 		T& operator*() const { return *get(); }

+ 0 - 1
CamelotRenderer/Include/CmResourceRefRTTI.h

@@ -16,7 +16,6 @@ namespace CamelotEngine
 
 
 			if(uuid != "")
 			if(uuid != "")
 			{
 			{
-				obj->mUUIDSet = true;
 				// TODO - I probably want to load the resource here
 				// TODO - I probably want to load the resource here
 				//   - Important: consider that user might just want to load the level meta data and not the actual resources
 				//   - Important: consider that user might just want to load the level meta data and not the actual resources
 				//     (Maybe he wants to stream them in as player goes through the world?)
 				//     (Maybe he wants to stream them in as player goes through the world?)

+ 40 - 2
CamelotRenderer/Include/CmResources.h

@@ -2,11 +2,39 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmModule.h"
 #include "CmModule.h"
+#include "CmWorkQueue.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	class Resources : public Module<Resources>
+	class CM_EXPORT Resources : public Module<Resources>
 	{
 	{
+	private:
+		class CM_EXPORT ResourceRequestHandler : public WorkQueue::RequestHandler
+		{
+			virtual bool canHandleRequest( const WorkQueue::Request* req, const WorkQueue* srcQ );
+			virtual WorkQueue::Response* handleRequest( const WorkQueue::Request* req, const WorkQueue* srcQ );
+		};
+
+		class CM_EXPORT ResourceResponseHandler : public WorkQueue::ResponseHandler
+		{
+			virtual bool canHandleResponse( const WorkQueue::Response* res, const WorkQueue* srcQ );
+			virtual void handleResponse( const WorkQueue::Response* res, const WorkQueue* srcQ );
+		};
+
+		struct CM_EXPORT ResourceLoadRequest
+		{
+			String filePath;
+			BaseResourceRef resource;
+		};
+
+		struct CM_EXPORT ResourceLoadResponse
+		{
+			ResourcePtr rawResource;
+		};
+
+		typedef std::shared_ptr<ResourceLoadRequest> ResourceLoadRequestPtr;
+		typedef std::shared_ptr<ResourceLoadResponse> ResourceLoadResponsePtr;
+
 	public:
 	public:
 		/**
 		/**
 		 * @brief	Constructor.
 		 * @brief	Constructor.
@@ -29,7 +57,9 @@ namespace CamelotEngine
 		 *
 		 *
 		 * @return	Loaded resource, or null if it cannot be found.
 		 * @return	Loaded resource, or null if it cannot be found.
 		 */
 		 */
-		BaseResourceRef loadFromPath(const String& filePath);
+		BaseResourceRef load(const String& filePath);
+
+		BaseResourceRef loadAsync(const String& filePath);
 
 
 		/**
 		/**
 		 * @brief	Loads the resource with the given uuid.
 		 * @brief	Loads the resource with the given uuid.
@@ -77,6 +107,14 @@ namespace CamelotEngine
 		typedef std::shared_ptr<ResourceMetaData> ResourceMetaDataPtr;
 		typedef std::shared_ptr<ResourceMetaData> ResourceMetaDataPtr;
 		map<String, ResourceMetaDataPtr>::type mResourceMetaData;
 		map<String, ResourceMetaDataPtr>::type mResourceMetaData;
 
 
+		ResourceRequestHandler* mRequestHandler;
+		ResourceResponseHandler* mResponseHandler;
+
+		WorkQueuePtr mWorkQueue; // TODO Low priority - I might want to make this more global so other classes can use it
+		UINT16 mWorkQueueChannel;
+
+		ResourcePtr loadInternal(const String& filePath);
+
 		void loadMetaData();
 		void loadMetaData();
 		void saveMetaData(const ResourceMetaDataPtr metaData);
 		void saveMetaData(const ResourceMetaDataPtr metaData);
 
 

+ 6 - 6
CamelotRenderer/Source/CmApplication.cpp

@@ -102,7 +102,7 @@ namespace CamelotEngine
 		}";
 		}";
 
 
 		mFragProg =  HighLevelGpuProgramManager::instance().createProgram(fragShaderCode, "ps_main", "cg", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
 		mFragProg =  HighLevelGpuProgramManager::instance().createProgram(fragShaderCode, "ps_main", "cg", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
-		mFragProg->load();
+		mFragProg->init();
 
 
 		String vertShaderCode = "float4x4 matViewProjection;	\
 		String vertShaderCode = "float4x4 matViewProjection;	\
 								void vs_main(										\
 								void vs_main(										\
@@ -116,17 +116,17 @@ namespace CamelotEngine
 								}";
 								}";
 
 
 		mVertProg =  HighLevelGpuProgramManager::instance().createProgram(vertShaderCode, "vs_main", "cg", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
 		mVertProg =  HighLevelGpuProgramManager::instance().createProgram(vertShaderCode, "vs_main", "cg", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
-		mVertProg->load();
+		mVertProg->init();
 
 
 		HighLevelGpuProgramRef vertProgRef(mVertProg);
 		HighLevelGpuProgramRef vertProgRef(mVertProg);
 
 
 		gResources().create(vertProgRef, "C:\\vertProgCg.vprog", true);
 		gResources().create(vertProgRef, "C:\\vertProgCg.vprog", true);
-		vertProgRef = static_resource_cast<HighLevelGpuProgram>(gResources().loadFromPath("C:\\vertProgCg.vprog"));
+		vertProgRef = static_resource_cast<HighLevelGpuProgram>(gResources().load("C:\\vertProgCg.vprog"));
 
 
 		HighLevelGpuProgramRef fragProgRef(mFragProg);
 		HighLevelGpuProgramRef fragProgRef(mFragProg);
 
 
 		gResources().create(fragProgRef, "C:\\fragProgCg.vprog", true);
 		gResources().create(fragProgRef, "C:\\fragProgCg.vprog", true);
-		fragProgRef = static_resource_cast<HighLevelGpuProgram>(gResources().loadFromPath("C:\\fragProgCg.vprog"));
+		fragProgRef = static_resource_cast<HighLevelGpuProgram>(gResources().load("C:\\fragProgCg.vprog"));
 
 
 		///////////////// GLSL SHADERS ////////////////////////////
 		///////////////// GLSL SHADERS ////////////////////////////
 		//String fragShaderCode = "uniform sampler2D tex; \
 		//String fragShaderCode = "uniform sampler2D tex; \
@@ -173,8 +173,8 @@ namespace CamelotEngine
 		gResources().create(testTex, "C:\\ExportTest.tex", true);
 		gResources().create(testTex, "C:\\ExportTest.tex", true);
 		gResources().create(mDbgMesh, "C:\\ExportMesh.mesh", true);
 		gResources().create(mDbgMesh, "C:\\ExportMesh.mesh", true);
 
 
-		mDbgTexture = static_resource_cast<Texture>(gResources().loadFromPath("C:\\ExportTest.tex"));
-		mDbgMesh = static_resource_cast<Mesh>(gResources().loadFromPath("C:\\ExportMesh.mesh"));
+		mDbgTexture = static_resource_cast<Texture>(gResources().load("C:\\ExportTest.tex"));
+		mDbgMesh = static_resource_cast<Mesh>(gResources().load("C:\\ExportMesh.mesh"));
 
 
 		mDbgTexture = testTex;
 		mDbgTexture = testTex;
 
 

+ 1 - 1
CamelotRenderer/Source/CmCgProgram.cpp

@@ -169,7 +169,7 @@ namespace CamelotEngine {
 					HighLevelGpuProgramManager::instance().createProgram(
 					HighLevelGpuProgramManager::instance().createProgram(
 					hlslSourceFromCg, "main", "hlsl", mType, mProfile);
 					hlslSourceFromCg, "main", "hlsl", mType, mProfile);
 
 
-				vp->load();
+				vp->init();
 
 
 				mAssemblerProgram = vp;
 				mAssemblerProgram = vp;
 			}
 			}

+ 1 - 1
CamelotRenderer/Source/CmGpuProgram.cpp

@@ -61,7 +61,7 @@ namespace CamelotEngine
 		mCompileError = false;
 		mCompileError = false;
     }
     }
     //-----------------------------------------------------------------------------
     //-----------------------------------------------------------------------------
-    void GpuProgram::loadImpl(void)
+    void GpuProgram::initImpl(void)
     {
     {
         // Call polymorphic load
         // Call polymorphic load
 		try 
 		try 

+ 1 - 1
CamelotRenderer/Source/CmGpuProgramManager.cpp

@@ -50,7 +50,7 @@ namespace CamelotEngine {
 		{
 		{
 			prg = createProgram( code, gptype, syntaxCode);
 			prg = createProgram( code, gptype, syntaxCode);
 		}
 		}
-        prg->load();
+        prg->init();
         return prg;
         return prg;
     }
     }
     //---------------------------------------------------------------------------
     //---------------------------------------------------------------------------

+ 2 - 2
CamelotRenderer/Source/CmHighLevelGpuProgram.cpp

@@ -37,7 +37,7 @@ namespace CamelotEngine
     {
     {
     }
     }
     //---------------------------------------------------------------------------
     //---------------------------------------------------------------------------
-    void HighLevelGpuProgram::loadImpl()
+    void HighLevelGpuProgram::initImpl()
     {
     {
 		if (isSupported())
 		if (isSupported())
 		{
 		{
@@ -50,7 +50,7 @@ namespace CamelotEngine
 			// load constructed assembler program (if it exists)
 			// load constructed assembler program (if it exists)
 			if (mAssemblerProgram != nullptr && mAssemblerProgram.get() != this)
 			if (mAssemblerProgram != nullptr && mAssemblerProgram.get() != this)
 			{
 			{
-				mAssemblerProgram->load();
+				mAssemblerProgram->init();
 			}
 			}
 		}
 		}
     }
     }

+ 1 - 1
CamelotRenderer/Source/CmImporter.cpp

@@ -71,7 +71,7 @@ namespace CamelotEngine
 		}
 		}
 
 
 		BaseResourceRef importedResource = importer->import(inputFilePath);
 		BaseResourceRef importedResource = importer->import(inputFilePath);
-		importedResource->load();
+		importedResource->init();
 
 
 		return importedResource;
 		return importedResource;
 	}
 	}

+ 1 - 1
CamelotRenderer/Source/CmMesh.cpp

@@ -160,7 +160,7 @@ namespace CamelotEngine
 		return ro;
 		return ro;
 	}
 	}
 
 
-	void Mesh::loadImpl()
+	void Mesh::initImpl()
 	{
 	{
 		if(mMeshData == nullptr)
 		if(mMeshData == nullptr)
 		{
 		{

+ 5 - 5
CamelotRenderer/Source/CmResource.cpp

@@ -5,20 +5,20 @@
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
 	Resource::Resource()
 	Resource::Resource()
-		:mSize(0), mLoadState(RS_Unloaded)
+		:mSize(0), mInitialized(false)
 	{
 	{
 		// We always generate a random UUID, and then overwrite it with the actual one 
 		// We always generate a random UUID, and then overwrite it with the actual one 
 		// during loading if one was previously generated and saved.
 		// during loading if one was previously generated and saved.
 		mUUID = UUIDGenerator::generateRandom();
 		mUUID = UUIDGenerator::generateRandom();
 	}
 	}
 
 
-	void Resource::load()
+	void Resource::init()
 	{
 	{
-		if(mLoadState != RS_Loaded)
+		if(!mInitialized)
 		{
 		{
-			loadImpl();
+			initImpl();
 
 
-			mLoadState = RS_Loaded;
+			mInitialized = true;
 		}
 		}
 	}
 	}
 		
 		

+ 7 - 2
CamelotRenderer/Source/CmResourceRef.cpp

@@ -2,6 +2,7 @@
 #include "CmResourceRef.h"
 #include "CmResourceRef.h"
 #include "CmResource.h"
 #include "CmResource.h"
 #include "CmResourceRefRTTI.h"
 #include "CmResourceRefRTTI.h"
+#include "CmResources.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
@@ -18,7 +19,11 @@ namespace CamelotEngine
 	ResourceRefBase::ResourceRefBase()
 	ResourceRefBase::ResourceRefBase()
 	{
 	{
 		mData = std::shared_ptr<ResourceRefData>(new ResourceRefData());
 		mData = std::shared_ptr<ResourceRefData>(new ResourceRefData());
-		mData->mUUIDSet = false;
+	}
+
+	void ResourceRefBase::resolve(std::shared_ptr<Resource> ptr) 
+	{ 
+		init(ptr);
 	}
 	}
 
 
 	void ResourceRefBase::init(Resource* ptr)
 	void ResourceRefBase::init(Resource* ptr)
@@ -33,7 +38,7 @@ namespace CamelotEngine
 		if(mData->mPtr)
 		if(mData->mPtr)
 		{
 		{
 			mData->mUUID = mData->mPtr->getUUID();
 			mData->mUUID = mData->mPtr->getUUID();
-			mData->mUUIDSet = true;
+			mData->mIsResolved.store(true); 
 		}
 		}
 	}
 	}
 
 

+ 110 - 13
CamelotRenderer/Source/CmResources.cpp

@@ -10,7 +10,50 @@
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
+	bool Resources::ResourceRequestHandler::canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
+	{
+		return true;
+	}
+
+	WorkQueue::Response* Resources::ResourceRequestHandler::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
+	{
+		ResourceLoadRequestPtr resRequest = boost::any_cast<ResourceLoadRequestPtr>(req->getData());
+
+		ResourceLoadResponsePtr resResponse = ResourceLoadResponsePtr(new Resources::ResourceLoadResponse());
+		resResponse->rawResource = gResources().loadInternal(resRequest->filePath);
+
+		return new WorkQueue::Response(req, true, resResponse);
+	}
+
+	bool Resources::ResourceResponseHandler::canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
+	{
+		return true;
+	}
+
+	void Resources::ResourceResponseHandler::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
+	{
+		if(res->getRequest()->getAborted())
+			return;
+
+		if(res->succeeded())
+		{
+			ResourceLoadResponsePtr resResponse = boost::any_cast<ResourceLoadResponsePtr>(res->getData());
+			ResourceLoadRequestPtr resRequest = boost::any_cast<ResourceLoadRequestPtr>(res->getRequest()->getData());
+
+			if(resRequest->resource != nullptr)
+			{
+				resResponse->rawResource->init();
+				resRequest->resource.resolve(resResponse->rawResource);
+			}
+		}
+		else
+		{
+			gDebug().logWarning("Resource load request failed.");
+		}
+	}
+
 	Resources::Resources(const String& metaDataFolder)
 	Resources::Resources(const String& metaDataFolder)
+		:mRequestHandler(nullptr), mResponseHandler(nullptr)
 	{
 	{
 		mMetaDataFolderPath = metaDataFolder;
 		mMetaDataFolderPath = metaDataFolder;
 
 
@@ -20,36 +63,75 @@ namespace CamelotEngine
 		}
 		}
 
 
 		loadMetaData();
 		loadMetaData();
+
+		mWorkQueue = WorkQueuePtr(new WorkQueue());
+		mWorkQueueChannel = mWorkQueue->getChannel("Resources");
+		mRequestHandler = new ResourceRequestHandler();
+		mResponseHandler = new ResourceResponseHandler();
+
+		mWorkQueue->addRequestHandler(mWorkQueueChannel, mRequestHandler);
+		mWorkQueue->addResponseHandler(mWorkQueueChannel, mResponseHandler);
+
+		// TODO Low priority - I might want to make this more global so other classes can use it
+#if CM_THREAD_SUPPORT
+		mWorkQueue->setWorkerThreadCount(CM_THREAD_HARDWARE_CONCURRENCY);
+#endif
+		mWorkQueue->startup();
 	}
 	}
 
 
 	Resources::~Resources()
 	Resources::~Resources()
 	{
 	{
+		if(mWorkQueue)
+		{
+			if(mRequestHandler != nullptr)
+				mWorkQueue->removeRequestHandler(mWorkQueueChannel, mRequestHandler);
+
+			if(mResponseHandler != nullptr)
+				mWorkQueue->removeResponseHandler(mWorkQueueChannel, mResponseHandler);
+
+			mWorkQueue->shutdown();
+		}
+
+		if(mRequestHandler != nullptr)
+			delete mRequestHandler;
 
 
+		if(mResponseHandler != nullptr)
+			delete mResponseHandler;
 	}
 	}
 
 
-	BaseResourceRef Resources::loadFromPath(const String& filePath)
+	BaseResourceRef Resources::load(const String& filePath)
 	{
 	{
-		FileSerializer fs;
-		std::shared_ptr<IReflectable> loadedData = fs.decode(filePath);
+		// TODO - Make sure this uses the same code as loadAsync. Only forceSyncronous
 
 
 		// TODO - Low priority. Check is file path valid?
 		// TODO - Low priority. Check is file path valid?
 
 
-		if(loadedData == nullptr)
-			CM_EXCEPT(InternalErrorException, "Unable to load resource.");
-
-		if(!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
-			CM_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
-
-		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
-		resource->load();
+		BaseResourceRef resource = loadInternal(filePath);
+		resource->init();
 
 
+		// TODO - This should probably be called in loadInternal, but it isn't thread safe
+		//        - loadAsync never calls this code and it should
 		if(!metaExists_UUID(resource->getUUID()))
 		if(!metaExists_UUID(resource->getUUID()))
 		{
 		{
 			gDebug().logWarning("Loading a resource that doesn't have meta-data. Creating meta-data automatically. Resource path: " + filePath);
 			gDebug().logWarning("Loading a resource that doesn't have meta-data. Creating meta-data automatically. Resource path: " + filePath);
 			addMetaData(resource->getUUID(), filePath);
 			addMetaData(resource->getUUID(), filePath);
 		}
 		}
 
 
-		return BaseResourceRef(resource);
+		return resource;
+	}
+
+	BaseResourceRef Resources::loadAsync(const String& filePath)
+	{
+		// TODO - Low priority. Check is file path valid?
+
+		BaseResourceRef newResource;
+
+		ResourceLoadRequestPtr resRequest = ResourceLoadRequestPtr(new Resources::ResourceLoadRequest());
+		resRequest->filePath = filePath;
+		resRequest->resource = newResource;
+
+		mWorkQueue->addRequest(mWorkQueueChannel, resRequest, 0, false);
+
+		return newResource;
 	}
 	}
 
 
 	BaseResourceRef Resources::loadFromUUID(const String& uuid)
 	BaseResourceRef Resources::loadFromUUID(const String& uuid)
@@ -62,7 +144,22 @@ namespace CamelotEngine
 
 
 		ResourceMetaDataPtr metaEntry = mResourceMetaData[uuid];
 		ResourceMetaDataPtr metaEntry = mResourceMetaData[uuid];
 
 
-		return loadFromPath(metaEntry->mPath);
+		return load(metaEntry->mPath);
+	}
+
+	ResourcePtr Resources::loadInternal(const String& filePath)
+	{
+		FileSerializer fs;
+		std::shared_ptr<IReflectable> loadedData = fs.decode(filePath);
+
+		if(loadedData == nullptr)
+			CM_EXCEPT(InternalErrorException, "Unable to load resource.");
+
+		if(!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
+			CM_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
+
+		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
+		return resource;
 	}
 	}
 
 
 	void Resources::create(BaseResourceRef resource, const String& filePath, bool overwrite)
 	void Resources::create(BaseResourceRef resource, const String& filePath, bool overwrite)

+ 1 - 1
CamelotUtility/Source/CmWorkQueue.cpp

@@ -371,7 +371,7 @@ namespace CamelotEngine {
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
 	void WorkQueue::processResponses() 
 	void WorkQueue::processResponses() 
 	{
 	{
-		// keep going until we run out of responses or out of time
+		// keep going until we run out of responses
 		while(true)
 		while(true)
 		{
 		{
 			Response* response = 0;
 			Response* response = 0;