Browse Source

More work on improving documentation for doxygen generation

BearishSun 9 years ago
parent
commit
986677a738
37 changed files with 10214 additions and 10371 deletions
  1. 12 16
      Source/BansheeCore/Include/BsCorePrerequisites.h
  2. 96 98
      Source/BansheeCore/Include/BsGameObjectRTTI.h
  3. 344 344
      Source/BansheeCore/Include/BsGpuParams.h
  4. 408 411
      Source/BansheeCore/Include/BsInputFwd.h
  5. 46 48
      Source/BansheeCore/Include/BsPixelVolume.h
  6. 265 269
      Source/BansheeCore/Include/BsPrefabDiffRTTI.h
  7. 318 318
      Source/BansheeCore/Include/BsResources.h
  8. 131 135
      Source/BansheeCore/Include/BsTechnique.h
  9. 376 380
      Source/BansheeCore/Include/BsTextData.h
  10. 139 144
      Source/BansheeCore/Source/BsGpuProgramManager.cpp
  11. 381 402
      Source/BansheeCore/Source/BsIconUtility.cpp
  12. 184 186
      Source/BansheeCore/Source/BsPass.cpp
  13. 1777 1790
      Source/BansheeCore/Source/BsPixelUtil.cpp
  14. 1 3
      Source/BansheeD3D9RenderAPI/Include/BsD3D9VideoModeInfo.h
  15. 4 4
      Source/BansheeEditor/Include/BsGizmoManager.h
  16. 654 679
      Source/BansheeEditor/Source/Win32/BsVSCodeEditor.cpp
  17. 565 567
      Source/BansheeEngine/Include/BsCamera.h
  18. 126 126
      Source/BansheeEngine/Include/BsGUIScrollBar.h
  19. 81 81
      Source/BansheeEngine/Include/BsGUISkin.h
  20. 210 212
      Source/BansheeEngine/Include/BsPrerequisites.h
  21. 85 87
      Source/BansheeEngine/Include/BsRendererMaterial.h
  22. 23 27
      Source/BansheeFBXImporter/Source/BsFBXPlugin.cpp
  23. 23 27
      Source/BansheeFontImporter/Source/BsFontPlugin.cpp
  24. 1 3
      Source/BansheeGLRenderAPI/Include/BsGLTextureManager.h
  25. 34 38
      Source/BansheeOISInput/Source/BsOISPlugin.cpp
  26. 22 26
      Source/BansheeSL/Source/BsSLPlugin.cpp
  27. 105 106
      Source/BansheeUtility/Include/BsDebug.h
  28. 622 624
      Source/BansheeUtility/Include/BsPath.h
  29. 206 206
      Source/BansheeUtility/Include/BsRTTIReflectableField.h
  30. 280 283
      Source/BansheeUtility/Include/BsStringFormat.h
  31. 93 95
      Source/BansheeUtility/Include/BsTestSuite.h
  32. 244 245
      Source/BansheeUtility/Include/BsThreadPool.h
  33. 23 25
      Source/BansheeUtility/Include/BsTypes.h
  34. 1284 1286
      Source/BansheeUtility/Source/BsBinarySerializer.cpp
  35. 473 489
      Source/BansheeUtility/Source/BsDataStream.cpp
  36. 557 566
      Source/BansheeUtility/Source/Win32/BsWin32CrashHandler.cpp
  37. 21 25
      Source/RenderBeast/Source/BsRenderBeastPlugin.cpp

+ 12 - 16
Source/BansheeCore/Include/BsCorePrerequisites.h

@@ -529,20 +529,19 @@ namespace BansheeEngine
 namespace BansheeEngine
 {
 	/**
-	 * @brief	Defers function execution until the next frame. If this function is called
-	 * 			within another deferred call, then it will be executed the same frame,
-	 * 			but only after all existing deferred calls are done.
+	 * Defers function execution until the next frame. If this function is called within another deferred call, then it will
+	 * be executed the same frame, but only after all existing deferred calls are done.
 	 * 			
-	 * @note	This method can be used for breaking dependencies among other things. If a class
-	 * 			A depends on class B having something done, but class B also depends in some way on class A,
-	 * 			you can break up the initialization into two separate steps, queuing the second step
-	 * 			using this method.
-	 * 			
-	 *			Similar situation can happen if you have multiple classes being initialized in an undefined order
-	 *			but some of them depend on others. Using this method you can defer the dependent step until next frame,
-	 *			which will ensure everything was initialized.
+	 * @note	
+	 * This method can be used for breaking dependencies among other things. If a class A depends on class B having
+	 * something done, but class B also depends in some way on class A, you can break up the initialization into two
+	 * separate steps, queuing the second step using this method.
+	 * @note
+	 * Similar situation can happen if you have multiple classes being initialized in an undefined order but some of them
+	 * depend on others. Using this method you can defer the dependent step until next frame, which will ensure everything
+	 * was initialized.
 	 *
-	 * @param	callback	The callback.
+	 * @param[in]	callback	The callback.
 	 */
 	void BS_CORE_EXPORT deferredCall(std::function<void()> callback);
 
@@ -555,10 +554,7 @@ namespace BansheeEngine
 	template <typename T, typename A = StdAlloc<T, ProfilerAlloc>>
 	using ProfilerStack = std::stack<T, std::deque<T, A>>;
 
-	/**
-	* @brief	Banshee thread policy that performs special startup/shutdown on threads
-	*			managed by thread pool.
-	*/
+	/** Banshee thread policy that performs special startup/shutdown on threads managed by thread pool. */
 	class BS_CORE_EXPORT ThreadBansheePolicy
 	{
 	public:

+ 96 - 98
Source/BansheeCore/Include/BsGameObjectRTTI.h

@@ -1,99 +1,97 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsRTTIType.h"
-#include "BsGameObject.h"
-#include "BsSceneObject.h"
-#include "BsGameObjectManager.h"
-
-namespace BansheeEngine
-{
-	/** @cond RTTI */
-	/** @addtogroup RTTI-Impl-Core
-	 *  @{
-	 */
-
-	/**	Provides temporary storage for data used during GameObject deserialization. */
-	struct GODeserializationData
-	{
-		GODeserializationData()
-			:isDeserializationParent(false), originalId(0)
-		{ }
-
-		GameObjectPtr ptr;
-		bool isDeserializationParent;
-		UINT64 originalId;
-		Any moreData;
-	};
-
-	class BS_CORE_EXPORT GameObjectRTTI : public RTTIType<GameObject, IReflectable, GameObjectRTTI>
-	{
-	private:
-		String& getName(GameObject* obj) { return obj->mName; }
-		void setName(GameObject* obj, String& name) { obj->mName = name; }
-
-		UINT64& getInstanceID(GameObject* obj) { return obj->mInstanceData->mInstanceId; }
-		void setInstanceID(GameObject* obj, UINT64& instanceId) 
-		{  
-			// We record the ID for later use. Any child RTTI of GameObject must call GameObjectManager::registerObject
-			// with this ID, so we know how to map deserialized GO handles to live objects, otherwise the handle
-			// references will get broken.
-			GameObject* go = static_cast<GameObject*>(obj);
-			GODeserializationData& deserializationData = any_cast_ref<GODeserializationData>(go->mRTTIData);
-
-			deserializationData.originalId = instanceId;
-		}
-
-		UINT32& getLinkId(GameObject* obj) { return obj->mLinkId; }
-		void setLinkId(GameObject* obj, UINT32& linkId) { obj->mLinkId = linkId; }
-
-	public:
-		/**
-		 * @brief	Helper method used for creating Component objects used during deserialization.
-		 */
-		template <typename T>
-		static std::shared_ptr<T> createGameObject()
-		{
-			SPtr<T> component = SceneObject::createEmptyComponent<T>();
-
-			// Every GameObject must store GODeserializationData in its RTTI data field during deserialization
-			component->mRTTIData = GODeserializationData();
-			GODeserializationData& deserializationData = any_cast_ref<GODeserializationData>(component->mRTTIData);
-
-			// Store shared pointer since the system only provides us with raw ones
-			deserializationData.ptr = component;
-
-			return component;
-		}
-
-	public:
-		GameObjectRTTI()
-		{
-			addPlainField("mInstanceID", 0, &GameObjectRTTI::getInstanceID, &GameObjectRTTI::setInstanceID);
-			addPlainField("mName", 1, &GameObjectRTTI::getName, &GameObjectRTTI::setName);
-			addPlainField("mLinkId", 2, &GameObjectRTTI::getLinkId, &GameObjectRTTI::setLinkId);
-		}
-
-		const String& getRTTIName() override
-		{
-			static String name = "GameObject";
-			return name;
-		}
-
-		UINT32 getRTTIId() override
-		{
-			return TID_GameObject;
-		}
-
-		std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class.");
-			return nullptr;
-		}
-	};
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsGameObject.h"
+#include "BsSceneObject.h"
+#include "BsGameObjectManager.h"
+
+namespace BansheeEngine
+{
+	/** @cond RTTI */
+	/** @addtogroup RTTI-Impl-Core
+	 *  @{
+	 */
+
+	/**	Provides temporary storage for data used during GameObject deserialization. */
+	struct GODeserializationData
+	{
+		GODeserializationData()
+			:isDeserializationParent(false), originalId(0)
+		{ }
+
+		GameObjectPtr ptr;
+		bool isDeserializationParent;
+		UINT64 originalId;
+		Any moreData;
+	};
+
+	class BS_CORE_EXPORT GameObjectRTTI : public RTTIType<GameObject, IReflectable, GameObjectRTTI>
+	{
+	private:
+		String& getName(GameObject* obj) { return obj->mName; }
+		void setName(GameObject* obj, String& name) { obj->mName = name; }
+
+		UINT64& getInstanceID(GameObject* obj) { return obj->mInstanceData->mInstanceId; }
+		void setInstanceID(GameObject* obj, UINT64& instanceId) 
+		{  
+			// We record the ID for later use. Any child RTTI of GameObject must call GameObjectManager::registerObject
+			// with this ID, so we know how to map deserialized GO handles to live objects, otherwise the handle
+			// references will get broken.
+			GameObject* go = static_cast<GameObject*>(obj);
+			GODeserializationData& deserializationData = any_cast_ref<GODeserializationData>(go->mRTTIData);
+
+			deserializationData.originalId = instanceId;
+		}
+
+		UINT32& getLinkId(GameObject* obj) { return obj->mLinkId; }
+		void setLinkId(GameObject* obj, UINT32& linkId) { obj->mLinkId = linkId; }
+
+	public:
+		/**	Helper method used for creating Component objects used during deserialization. */
+		template <typename T>
+		static std::shared_ptr<T> createGameObject()
+		{
+			SPtr<T> component = SceneObject::createEmptyComponent<T>();
+
+			// Every GameObject must store GODeserializationData in its RTTI data field during deserialization
+			component->mRTTIData = GODeserializationData();
+			GODeserializationData& deserializationData = any_cast_ref<GODeserializationData>(component->mRTTIData);
+
+			// Store shared pointer since the system only provides us with raw ones
+			deserializationData.ptr = component;
+
+			return component;
+		}
+
+	public:
+		GameObjectRTTI()
+		{
+			addPlainField("mInstanceID", 0, &GameObjectRTTI::getInstanceID, &GameObjectRTTI::setInstanceID);
+			addPlainField("mName", 1, &GameObjectRTTI::getName, &GameObjectRTTI::setName);
+			addPlainField("mLinkId", 2, &GameObjectRTTI::getLinkId, &GameObjectRTTI::setLinkId);
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "GameObject";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_GameObject;
+		}
+
+		std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class.");
+			return nullptr;
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 344 - 344
Source/BansheeCore/Include/BsGpuParams.h

@@ -1,345 +1,345 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsGpuParam.h"
-#include "BsCoreObject.h"
-#include "BsIResourceListener.h"
-#include "BsVectorNI.h"
-#include "BsMatrixNxM.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Implementation
-	 *  @{
-	 */
-	/** @cond INTERNAL */
-
-	/** Stores information needed for binding a texture to the pipeline. */
-	struct BoundTextureInfo
-	{
-		BoundTextureInfo()
-			:isLoadStore(false)
-		{ }
-
-		bool isLoadStore;
-		TextureSurface surface;
-	};
-
-	/**	Helper structure whose specializations convert an engine data type into a GPU program data parameter type.  */
-	template<class T> struct TGpuDataParamInfo { };
-	template<> struct TGpuDataParamInfo < float > { enum { TypeId = GPDT_FLOAT1 }; };
-	template<> struct TGpuDataParamInfo < Vector2 > { enum { TypeId = GPDT_FLOAT2 }; };
-	template<> struct TGpuDataParamInfo < Vector3 > { enum { TypeId = GPDT_FLOAT3 }; };
-	template<> struct TGpuDataParamInfo < Vector4 > { enum { TypeId = GPDT_FLOAT4 }; };
-	template<> struct TGpuDataParamInfo < int > { enum { TypeId = GPDT_INT1 }; };
-	template<> struct TGpuDataParamInfo < Vector2I > { enum { TypeId = GPDT_INT2 }; };
-	template<> struct TGpuDataParamInfo < Vector3I > { enum { TypeId = GPDT_INT3 }; };
-	template<> struct TGpuDataParamInfo < Vector4I > { enum { TypeId = GPDT_INT4 }; };
-	template<> struct TGpuDataParamInfo < Matrix2 > { enum { TypeId = GPDT_MATRIX_2X2 }; };
-	template<> struct TGpuDataParamInfo < Matrix2x3 > { enum { TypeId = GPDT_MATRIX_2X3 }; };
-	template<> struct TGpuDataParamInfo < Matrix2x4 > { enum { TypeId = GPDT_MATRIX_2X3 }; };
-	template<> struct TGpuDataParamInfo < Matrix3 > { enum { TypeId = GPDT_MATRIX_3X3 }; };
-	template<> struct TGpuDataParamInfo < Matrix3x2 > { enum { TypeId = GPDT_MATRIX_3X2 }; };
-	template<> struct TGpuDataParamInfo < Matrix3x4 > { enum { TypeId = GPDT_MATRIX_3X4 }; };
-	template<> struct TGpuDataParamInfo < Matrix4 > { enum { TypeId = GPDT_MATRIX_4X4 }; };
-	template<> struct TGpuDataParamInfo < Matrix4x2 > { enum { TypeId = GPDT_MATRIX_4X2 }; };
-	template<> struct TGpuDataParamInfo < Matrix4x3 > { enum { TypeId = GPDT_MATRIX_4X3 }; };
-	template<> struct TGpuDataParamInfo < Color > { enum { TypeId = GPDT_COLOR }; };
-
-	/** @endcond */
-	
-	/** Contains functionality common for both sim and core thread version of GpuParams. */
-	class BS_CORE_EXPORT GpuParamsBase
-	{
-	public:
-		/**
-		 * Creates new GpuParams object using the specified parameter descriptions.
-		 *
-		 * @param[in]	paramDesc			Reference to parameter descriptions that will be used for finding needed 
-		 *									parameters.
-		 * @param[in]	transposeMatrices	If true the stored matrices will be transposed before submitted to the GPU 
-		 *									(some APIs require different matrix layout).
-		 *
-		 * @note	You normally do not want to call this manually. Instead use GpuProgram::createParameters.
-		 */
-		GpuParamsBase(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
-		virtual ~GpuParamsBase();
-
-		// Note: Disallow copy/assign because it would require some care when copying (copy internal data shared_ptr and
-		// all the internal buffers too). Trivial to implement but not needed at this time. Un-delete and implement if necessary.
-		GpuParamsBase(const GpuParamsBase& other) = delete;
-		GpuParamsBase& operator=(const GpuParamsBase& rhs) = delete;
-
-		/** Returns a description of all stored parameters. */
-		const GpuParamDesc& getParamDesc() const { return *mParamDesc; }
-
-		/**
-		 * Returns the size of a data parameter with the specified name, in bytes. Returns 0 if such parameter doesn't exist.
-		 */
-		UINT32 getDataParamSize(const String& name) const;
-
-		/** Checks if parameter with the specified name exists. */
-		bool hasParam(const String& name) const;
-
-		/**	Checks if texture parameter with the specified name exists. */
-		bool hasTexture(const String& name) const;
-
-		/**	Checks if sampler state parameter with the specified name exists. */
-		bool hasSamplerState(const String& name) const;
-
-		/** Checks if a parameter block with the specified name exists. */
-		bool hasParamBlock(const String& name) const;
-
-		/**
-		 * Checks is the texture at the specified slot to be bound as random load/store texture instead of a normal sampled
-		 * texture.
-		 */
-		bool isLoadStoreTexture(UINT32 slot) const;
-
-		/** Changes the type of the texture at the specified slot. */
-		void setIsLoadStoreTexture(UINT32 slot, bool isLoadStore);
-
-		/** Returns information that determines which texture surfaces to bind as load/store parameters. */
-		const TextureSurface& getLoadStoreSurface(UINT32 slot) const;
-
-		/**	Sets information that determines which texture surfaces to bind	as load/store parameters. */
-		void setLoadStoreSurface(UINT32 slot, const TextureSurface& surface) const;
-
-		/**	Checks whether matrices should be transformed before being written to the parameter buffer. */
-		bool getTransposeMatrices() const { return mTransposeMatrices; }
-
-		/**
-		 * @copydoc	CoreObject::markCoreDirty
-		 *
-		 * @note	Internal method.
-		 */
-		virtual void _markCoreDirty() { }
-
-		/**
-		 * @copydoc	IResourceListener::markResourcesDirty
-		 *
-		 * @note	Internal method.
-		 */
-		virtual void _markResourcesDirty() { }
-
-	protected:
-		/**	Gets a descriptor for a data parameter with the specified name. */
-		GpuParamDataDesc* getParamDesc(const String& name) const;
-
-		GpuParamDescPtr mParamDesc;
-
-		UINT32 mNumParamBlocks;
-		UINT32 mNumTextures;
-		UINT32 mNumSamplerStates;
-
-		BoundTextureInfo* mTextureInfo;
-
-		bool mTransposeMatrices;
-	};
-
-	/** Templated version of GpuParams that contains functionality for both sim and core thread versions of stored data. */
-	template <bool Core>
-	class BS_CORE_EXPORT TGpuParams : public GpuParamsBase
-	{
-	public:
-		template<bool Core> struct TTypes { };
-
-		template<> struct TTypes < false > 
-		{ 
-			typedef GpuParams GpuParamsType; 
-			typedef HTexture TextureType;
-			typedef SamplerStatePtr SamplerType;
-			typedef SPtr<GpuParamBlockBuffer> ParamsBufferType;
-		};
-
-		template<> struct TTypes < true > 
-		{ 
-			typedef GpuParamsCore GpuParamsType;
-			typedef SPtr<TextureCore> TextureType;
-			typedef SPtr<SamplerStateCore> SamplerType;
-			typedef SPtr<GpuParamBlockBufferCore> ParamsBufferType;
-		};
-
-		typedef typename TTypes<Core>::GpuParamsType GpuParamsType;
-		typedef typename TTypes<Core>::TextureType TextureType;
-		typedef typename TTypes<Core>::SamplerType SamplerType;
-		typedef typename TTypes<Core>::ParamsBufferType ParamsBufferType;
-
-		/** @copydoc GpuParamsBase::GpuParamsBase(const GpuParamDescPtr&, bool) */
-		TGpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
-
-		virtual ~TGpuParams();
-
-		/**
-		 * Binds a new parameter buffer to the specified slot. Any following parameter reads or writes that are referencing
-		 * that buffer slot will use the new buffer.
-		 *
-		 * @note	
-		 * This is useful if you want to share a parameter buffer among multiple GPU programs. You would only set the 
-		 * values once and then share the buffer among all other GpuParams.
-		 * @note
-		 * It is up to the caller to guarantee the provided buffer matches parameter block descriptor for this slot.
-		 */
-		void setParamBlockBuffer(UINT32 slot, const ParamsBufferType& paramBlockBuffer);
-
-		/**
-		 * Replaces the parameter buffer with the specified name. Any following parameter reads or writes that are 
-		 * referencing that buffer will use the new buffer.
-		 *
-		 * @note	
-		 * This is useful if you want to share a parameter buffer among multiple GPU programs. You would only set the 
-		 * values once and then share the buffer among all other GpuParams.
-		 * @note
-		 * It is up to the caller to guarantee the provided buffer matches parameter block descriptor for this slot.
-		 */
-		void setParamBlockBuffer(const String& name, const ParamsBufferType& paramBlockBuffer);
-
-		/**
-		 * Returns a handle for the parameter with the specified name. Handle may then be stored and used for quickly 
-		 * setting or retrieving values to/from that parameter.
-		 *
-		 * Throws exception if parameter with that name and type doesn't exist.
-		 *
-		 * Parameter handles will be invalidated when their parent GpuParams object changes.
-		 */
-		template<class T> void getParam(const String& name, TGpuDataParam<T, Core>& output) const;
-
-		/** @copydoc getParam(const String&, TGpuDataParam<T, Core>&) */
-		void getStructParam(const String& name, TGpuParamStruct<Core>& output) const;
-
-		/**
-		 * @copydoc	getParam(const String&, TGpuDataParam<T, Core>&)
-		 */
-		void getTextureParam(const String& name, TGpuParamTexture<Core>& output) const;
-
-		/** @copydoc getParam(const String&, TGpuDataParam<T, Core>&) */
-		void getLoadStoreTextureParam(const String& name, TGpuParamLoadStoreTexture<Core>& output) const;
-
-		/** @copydoc getParam(const String&, TGpuDataParam<T, Core>&) */
-		void getSamplerStateParam(const String& name, TGpuParamSampState<Core>& output) const;
-
-		/**	Gets a parameter block buffer from the specified slot. */
-		ParamsBufferType getParamBlockBuffer(UINT32 slot) const;
-
-		/**	Gets a texture bound to the specified slot. */
-		TextureType getTexture(UINT32 slot);
-
-		/**	Gets a sampler state bound to the specified slot. */
-		SamplerType getSamplerState(UINT32 slot);
-
-		/**	Sets a texture at the specified slot. */
-		void setTexture(UINT32 slot, const TextureType& texture);
-
-		/**	Sets a sampler state at the specified slot. */
-		void setSamplerState(UINT32 slot, const SamplerType& sampler);
-
-	protected:
-		/** @copydoc CoreObject::getThisPtr */
-		virtual SPtr<GpuParamsType> _getThisPtr() const = 0;
-
-		ParamsBufferType* mParamBlockBuffers;
-		TextureType* mTextures;
-		SamplerType* mSamplerStates;
-	};
-
-	/** @} */
-
-	/** @addtogroup RenderAPI
-	 *  @{
-	 */
-
-	/** @cond INTERNAL */
-
-	/**
-	 * @brief	Core thread version of GpuParams.
-	 *
-	 * @note	Core thread only.
-	 */
-	class BS_CORE_EXPORT GpuParamsCore : public CoreObjectCore, public TGpuParams<true>
-	{
-	public:
-		~GpuParamsCore() { }
-
-		/** Uploads all CPU stored parameter buffer data to the GPU buffers. */
-		void updateHardwareBuffers();
-
-		/** @copydoc GpuParamsBase::GpuParamsBase */
-		static SPtr<GpuParamsCore> create(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
-
-	protected:
-		friend class GpuParams;
-
-		/** @copydoc GpuParamsBase::GpuParamsBase */
-		GpuParamsCore(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
-
-		/** @copydoc CoreObject::getThisPtr */
-		SPtr<GpuParamsCore> _getThisPtr() const override;
-
-		/** @copydoc CoreObjectCore::syncToCore */
-		void syncToCore(const CoreSyncData& data) override;
-	};
-
-	/** @endcond */
-
-	/**
-	 * Contains descriptions for all parameters in a GPU program and also allows you to write and read those parameters. 
-	 * All parameter values are stored internally on the CPU, and are only submitted to the GPU once the parameters are 
-	 * bound to the pipeline.
-	 *
-	 * @note	Sim thread only.
-	 */
-	class BS_CORE_EXPORT GpuParams : public CoreObject, public TGpuParams<false>, public IResourceListener
-	{
-	public:
-		~GpuParams() { }
-
-		/**
-		 * @copydoc	CoreObject::markCoreDirty
-		 *
-		 * @note	Internal method.
-		 */
-		void _markCoreDirty() override;
-
-		/**
-		 * @copydoc	IResourceListener::markResourcesDirty
-		 *
-		 * @note	Internal method.
-		 */
-		void _markResourcesDirty() override;
-
-		/** Retrieves a core implementation of a mesh usable only from the core thread. */
-		SPtr<GpuParamsCore> getCore() const;
-
-		/** @copydoc GpuParamsBase::GpuParamsBase */
-		static SPtr<GpuParams> create(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
-
-		/** Contains a lookup table for sizes of all data parameters. Sizes are in bytes. */
-		const static GpuDataParamInfos PARAM_SIZES;
-
-	protected:
-		/** @copydoc GpuParamsBase::GpuParamsBase */
-		GpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
-
-		/** @copydoc CoreObject::getThisPtr */
-		SPtr<GpuParams> _getThisPtr() const override;
-
-		/** @copydoc CoreObject::createCore */
-		SPtr<CoreObjectCore> createCore() const override;
-
-		/** @copydoc CoreObject::syncToCore */
-		CoreSyncData syncToCore(FrameAlloc* allocator) override;
-
-		/** @copydoc IResourceListener::getListenerResources */
-		void getListenerResources(Vector<HResource>& resources) override;
-
-		/** @copydoc IResourceListener::notifyResourceLoaded */
-		void notifyResourceLoaded(const HResource& resource) override { markCoreDirty(); }
-
-		/** @copydoc IResourceListener::notifyResourceChanged */
-		void notifyResourceChanged(const HResource& resource) override { markCoreDirty(); }
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsGpuParam.h"
+#include "BsCoreObject.h"
+#include "BsIResourceListener.h"
+#include "BsVectorNI.h"
+#include "BsMatrixNxM.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Implementation
+	 *  @{
+	 */
+	/** @cond INTERNAL */
+
+	/** Stores information needed for binding a texture to the pipeline. */
+	struct BoundTextureInfo
+	{
+		BoundTextureInfo()
+			:isLoadStore(false)
+		{ }
+
+		bool isLoadStore;
+		TextureSurface surface;
+	};
+
+	/**	Helper structure whose specializations convert an engine data type into a GPU program data parameter type.  */
+	template<class T> struct TGpuDataParamInfo { };
+	template<> struct TGpuDataParamInfo < float > { enum { TypeId = GPDT_FLOAT1 }; };
+	template<> struct TGpuDataParamInfo < Vector2 > { enum { TypeId = GPDT_FLOAT2 }; };
+	template<> struct TGpuDataParamInfo < Vector3 > { enum { TypeId = GPDT_FLOAT3 }; };
+	template<> struct TGpuDataParamInfo < Vector4 > { enum { TypeId = GPDT_FLOAT4 }; };
+	template<> struct TGpuDataParamInfo < int > { enum { TypeId = GPDT_INT1 }; };
+	template<> struct TGpuDataParamInfo < Vector2I > { enum { TypeId = GPDT_INT2 }; };
+	template<> struct TGpuDataParamInfo < Vector3I > { enum { TypeId = GPDT_INT3 }; };
+	template<> struct TGpuDataParamInfo < Vector4I > { enum { TypeId = GPDT_INT4 }; };
+	template<> struct TGpuDataParamInfo < Matrix2 > { enum { TypeId = GPDT_MATRIX_2X2 }; };
+	template<> struct TGpuDataParamInfo < Matrix2x3 > { enum { TypeId = GPDT_MATRIX_2X3 }; };
+	template<> struct TGpuDataParamInfo < Matrix2x4 > { enum { TypeId = GPDT_MATRIX_2X3 }; };
+	template<> struct TGpuDataParamInfo < Matrix3 > { enum { TypeId = GPDT_MATRIX_3X3 }; };
+	template<> struct TGpuDataParamInfo < Matrix3x2 > { enum { TypeId = GPDT_MATRIX_3X2 }; };
+	template<> struct TGpuDataParamInfo < Matrix3x4 > { enum { TypeId = GPDT_MATRIX_3X4 }; };
+	template<> struct TGpuDataParamInfo < Matrix4 > { enum { TypeId = GPDT_MATRIX_4X4 }; };
+	template<> struct TGpuDataParamInfo < Matrix4x2 > { enum { TypeId = GPDT_MATRIX_4X2 }; };
+	template<> struct TGpuDataParamInfo < Matrix4x3 > { enum { TypeId = GPDT_MATRIX_4X3 }; };
+	template<> struct TGpuDataParamInfo < Color > { enum { TypeId = GPDT_COLOR }; };
+
+	/** @endcond */
+	
+	/** Contains functionality common for both sim and core thread version of GpuParams. */
+	class BS_CORE_EXPORT GpuParamsBase
+	{
+	public:
+		/**
+		 * Creates new GpuParams object using the specified parameter descriptions.
+		 *
+		 * @param[in]	paramDesc			Reference to parameter descriptions that will be used for finding needed 
+		 *									parameters.
+		 * @param[in]	transposeMatrices	If true the stored matrices will be transposed before submitted to the GPU 
+		 *									(some APIs require different matrix layout).
+		 *
+		 * @note	You normally do not want to call this manually. Instead use GpuProgram::createParameters.
+		 */
+		GpuParamsBase(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
+		virtual ~GpuParamsBase();
+
+		// Note: Disallow copy/assign because it would require some care when copying (copy internal data shared_ptr and
+		// all the internal buffers too). Trivial to implement but not needed at this time. Un-delete and implement if necessary.
+		GpuParamsBase(const GpuParamsBase& other) = delete;
+		GpuParamsBase& operator=(const GpuParamsBase& rhs) = delete;
+
+		/** Returns a description of all stored parameters. */
+		const GpuParamDesc& getParamDesc() const { return *mParamDesc; }
+
+		/**
+		 * Returns the size of a data parameter with the specified name, in bytes. Returns 0 if such parameter doesn't exist.
+		 */
+		UINT32 getDataParamSize(const String& name) const;
+
+		/** Checks if parameter with the specified name exists. */
+		bool hasParam(const String& name) const;
+
+		/**	Checks if texture parameter with the specified name exists. */
+		bool hasTexture(const String& name) const;
+
+		/**	Checks if sampler state parameter with the specified name exists. */
+		bool hasSamplerState(const String& name) const;
+
+		/** Checks if a parameter block with the specified name exists. */
+		bool hasParamBlock(const String& name) const;
+
+		/**
+		 * Checks is the texture at the specified slot to be bound as random load/store texture instead of a normal sampled
+		 * texture.
+		 */
+		bool isLoadStoreTexture(UINT32 slot) const;
+
+		/** Changes the type of the texture at the specified slot. */
+		void setIsLoadStoreTexture(UINT32 slot, bool isLoadStore);
+
+		/** Returns information that determines which texture surfaces to bind as load/store parameters. */
+		const TextureSurface& getLoadStoreSurface(UINT32 slot) const;
+
+		/**	Sets information that determines which texture surfaces to bind	as load/store parameters. */
+		void setLoadStoreSurface(UINT32 slot, const TextureSurface& surface) const;
+
+		/**	Checks whether matrices should be transformed before being written to the parameter buffer. */
+		bool getTransposeMatrices() const { return mTransposeMatrices; }
+
+		/**
+		 * @copydoc	CoreObject::markCoreDirty
+		 *
+		 * @note	Internal method.
+		 */
+		virtual void _markCoreDirty() { }
+
+		/**
+		 * @copydoc	IResourceListener::markResourcesDirty
+		 *
+		 * @note	Internal method.
+		 */
+		virtual void _markResourcesDirty() { }
+
+	protected:
+		/**	Gets a descriptor for a data parameter with the specified name. */
+		GpuParamDataDesc* getParamDesc(const String& name) const;
+
+		GpuParamDescPtr mParamDesc;
+
+		UINT32 mNumParamBlocks;
+		UINT32 mNumTextures;
+		UINT32 mNumSamplerStates;
+
+		BoundTextureInfo* mTextureInfo;
+
+		bool mTransposeMatrices;
+	};
+
+	/** Templated version of GpuParams that contains functionality for both sim and core thread versions of stored data. */
+	template <bool Core>
+	class BS_CORE_EXPORT TGpuParams : public GpuParamsBase
+	{
+	public:
+		template<bool Core> struct TTypes { };
+
+		template<> struct TTypes < false > 
+		{ 
+			typedef GpuParams GpuParamsType; 
+			typedef HTexture TextureType;
+			typedef SamplerStatePtr SamplerType;
+			typedef SPtr<GpuParamBlockBuffer> ParamsBufferType;
+		};
+
+		template<> struct TTypes < true > 
+		{ 
+			typedef GpuParamsCore GpuParamsType;
+			typedef SPtr<TextureCore> TextureType;
+			typedef SPtr<SamplerStateCore> SamplerType;
+			typedef SPtr<GpuParamBlockBufferCore> ParamsBufferType;
+		};
+
+		typedef typename TTypes<Core>::GpuParamsType GpuParamsType;
+		typedef typename TTypes<Core>::TextureType TextureType;
+		typedef typename TTypes<Core>::SamplerType SamplerType;
+		typedef typename TTypes<Core>::ParamsBufferType ParamsBufferType;
+
+		/** @copydoc GpuParamsBase::GpuParamsBase(const GpuParamDescPtr&, bool) */
+		TGpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
+
+		virtual ~TGpuParams();
+
+		/**
+		 * Binds a new parameter buffer to the specified slot. Any following parameter reads or writes that are referencing
+		 * that buffer slot will use the new buffer.
+		 *
+		 * @note	
+		 * This is useful if you want to share a parameter buffer among multiple GPU programs. You would only set the 
+		 * values once and then share the buffer among all other GpuParams.
+		 * @note
+		 * It is up to the caller to guarantee the provided buffer matches parameter block descriptor for this slot.
+		 */
+		void setParamBlockBuffer(UINT32 slot, const ParamsBufferType& paramBlockBuffer);
+
+		/**
+		 * Replaces the parameter buffer with the specified name. Any following parameter reads or writes that are 
+		 * referencing that buffer will use the new buffer.
+		 *
+		 * @note	
+		 * This is useful if you want to share a parameter buffer among multiple GPU programs. You would only set the 
+		 * values once and then share the buffer among all other GpuParams.
+		 * @note
+		 * It is up to the caller to guarantee the provided buffer matches parameter block descriptor for this slot.
+		 */
+		void setParamBlockBuffer(const String& name, const ParamsBufferType& paramBlockBuffer);
+
+		/**
+		 * Returns a handle for the parameter with the specified name. Handle may then be stored and used for quickly 
+		 * setting or retrieving values to/from that parameter.
+		 *
+		 * Throws exception if parameter with that name and type doesn't exist.
+		 *
+		 * Parameter handles will be invalidated when their parent GpuParams object changes.
+		 */
+		template<class T> void getParam(const String& name, TGpuDataParam<T, Core>& output) const;
+
+		/** @copydoc getParam(const String&, TGpuDataParam<T, Core>&) */
+		void getStructParam(const String& name, TGpuParamStruct<Core>& output) const;
+
+		/**
+		 * @copydoc	getParam(const String&, TGpuDataParam<T, Core>&)
+		 */
+		void getTextureParam(const String& name, TGpuParamTexture<Core>& output) const;
+
+		/** @copydoc getParam(const String&, TGpuDataParam<T, Core>&) */
+		void getLoadStoreTextureParam(const String& name, TGpuParamLoadStoreTexture<Core>& output) const;
+
+		/** @copydoc getParam(const String&, TGpuDataParam<T, Core>&) */
+		void getSamplerStateParam(const String& name, TGpuParamSampState<Core>& output) const;
+
+		/**	Gets a parameter block buffer from the specified slot. */
+		ParamsBufferType getParamBlockBuffer(UINT32 slot) const;
+
+		/**	Gets a texture bound to the specified slot. */
+		TextureType getTexture(UINT32 slot);
+
+		/**	Gets a sampler state bound to the specified slot. */
+		SamplerType getSamplerState(UINT32 slot);
+
+		/**	Sets a texture at the specified slot. */
+		void setTexture(UINT32 slot, const TextureType& texture);
+
+		/**	Sets a sampler state at the specified slot. */
+		void setSamplerState(UINT32 slot, const SamplerType& sampler);
+
+	protected:
+		/** @copydoc CoreObject::getThisPtr */
+		virtual SPtr<GpuParamsType> _getThisPtr() const = 0;
+
+		ParamsBufferType* mParamBlockBuffers;
+		TextureType* mTextures;
+		SamplerType* mSamplerStates;
+	};
+
+	/** @} */
+
+	/** @addtogroup RenderAPI
+	 *  @{
+	 */
+
+	/** @cond INTERNAL */
+
+	/**
+	 * Core thread version of GpuParams.
+	 *
+	 * @note	Core thread only.
+	 */
+	class BS_CORE_EXPORT GpuParamsCore : public CoreObjectCore, public TGpuParams<true>
+	{
+	public:
+		~GpuParamsCore() { }
+
+		/** Uploads all CPU stored parameter buffer data to the GPU buffers. */
+		void updateHardwareBuffers();
+
+		/** @copydoc GpuParamsBase::GpuParamsBase */
+		static SPtr<GpuParamsCore> create(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
+
+	protected:
+		friend class GpuParams;
+
+		/** @copydoc GpuParamsBase::GpuParamsBase */
+		GpuParamsCore(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
+
+		/** @copydoc CoreObject::getThisPtr */
+		SPtr<GpuParamsCore> _getThisPtr() const override;
+
+		/** @copydoc CoreObjectCore::syncToCore */
+		void syncToCore(const CoreSyncData& data) override;
+	};
+
+	/** @endcond */
+
+	/**
+	 * Contains descriptions for all parameters in a GPU program and also allows you to write and read those parameters. 
+	 * All parameter values are stored internally on the CPU, and are only submitted to the GPU once the parameters are 
+	 * bound to the pipeline.
+	 *
+	 * @note	Sim thread only.
+	 */
+	class BS_CORE_EXPORT GpuParams : public CoreObject, public TGpuParams<false>, public IResourceListener
+	{
+	public:
+		~GpuParams() { }
+
+		/**
+		 * @copydoc	CoreObject::markCoreDirty
+		 *
+		 * @note	Internal method.
+		 */
+		void _markCoreDirty() override;
+
+		/**
+		 * @copydoc	IResourceListener::markResourcesDirty
+		 *
+		 * @note	Internal method.
+		 */
+		void _markResourcesDirty() override;
+
+		/** Retrieves a core implementation of a mesh usable only from the core thread. */
+		SPtr<GpuParamsCore> getCore() const;
+
+		/** @copydoc GpuParamsBase::GpuParamsBase */
+		static SPtr<GpuParams> create(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
+
+		/** Contains a lookup table for sizes of all data parameters. Sizes are in bytes. */
+		const static GpuDataParamInfos PARAM_SIZES;
+
+	protected:
+		/** @copydoc GpuParamsBase::GpuParamsBase */
+		GpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
+
+		/** @copydoc CoreObject::getThisPtr */
+		SPtr<GpuParams> _getThisPtr() const override;
+
+		/** @copydoc CoreObject::createCore */
+		SPtr<CoreObjectCore> createCore() const override;
+
+		/** @copydoc CoreObject::syncToCore */
+		CoreSyncData syncToCore(FrameAlloc* allocator) override;
+
+		/** @copydoc IResourceListener::getListenerResources */
+		void getListenerResources(Vector<HResource>& resources) override;
+
+		/** @copydoc IResourceListener::notifyResourceLoaded */
+		void notifyResourceLoaded(const HResource& resource) override { markCoreDirty(); }
+
+		/** @copydoc IResourceListener::notifyResourceChanged */
+		void notifyResourceChanged(const HResource& resource) override { markCoreDirty(); }
+	};
+
+	/** @} */
 }

+ 408 - 411
Source/BansheeCore/Include/BsInputFwd.h

@@ -1,412 +1,409 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsVector2I.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Input
-	 *  @{
-	 */
-
-	/**
-	 * Contains all possible input buttons, including keyboard scan codes, mouse buttons and gamepad buttons.
-	 *
-	 * @note
-	 * These codes are only keyboard scan codes. This means that exact scan code identifier might not correspond to that 
-	 * exact character on users keyboard, depending on users input locale. Only for US locale will these scan code names 
-	 * will match the actual keyboard input. Think of the US key code names as only a convenience for more easily 
-	 * identifying which location on the keyboard a scan code represents.
-	 * @note
-	 * When storing these sequentially make sure to only reference the low order 2 bytes. Two high order bytes are used for 
-	 * various flags.
-	 */
-	enum ButtonCode
-	{
-		BC_UNASSIGNED  = 0x00,
-		BC_ESCAPE      = 0x01,
-		BC_1           = 0x02,
-		BC_2           = 0x03,
-		BC_3           = 0x04,
-		BC_4           = 0x05,
-		BC_5           = 0x06,
-		BC_6           = 0x07,
-		BC_7           = 0x08,
-		BC_8           = 0x09,
-		BC_9           = 0x0A,
-		BC_0           = 0x0B,
-		BC_MINUS       = 0x0C,    // - on main keyboard
-		BC_EQUALS      = 0x0D,
-		BC_BACK        = 0x0E,    // backspace
-		BC_TAB         = 0x0F,
-		BC_Q           = 0x10,
-		BC_W           = 0x11,
-		BC_E           = 0x12,
-		BC_R           = 0x13,
-		BC_T           = 0x14,
-		BC_Y           = 0x15,
-		BC_U           = 0x16,
-		BC_I           = 0x17,
-		BC_O           = 0x18,
-		BC_P           = 0x19,
-		BC_LBRACKET    = 0x1A,
-		BC_RBRACKET    = 0x1B,
-		BC_RETURN      = 0x1C,    // Enter on main keyboard
-		BC_LCONTROL    = 0x1D,
-		BC_A           = 0x1E,
-		BC_S           = 0x1F,
-		BC_D           = 0x20,
-		BC_F           = 0x21,
-		BC_G           = 0x22,
-		BC_H           = 0x23,
-		BC_J           = 0x24,
-		BC_K           = 0x25,
-		BC_L           = 0x26,
-		BC_SEMICOLON   = 0x27,
-		BC_APOSTROPHE  = 0x28,
-		BC_GRAVE       = 0x29,    // accent
-		BC_LSHIFT      = 0x2A,
-		BC_BACKSLASH   = 0x2B,
-		BC_Z           = 0x2C,
-		BC_X           = 0x2D,
-		BC_C           = 0x2E,
-		BC_V           = 0x2F,
-		BC_B           = 0x30,
-		BC_N           = 0x31,
-		BC_M           = 0x32,
-		BC_COMMA       = 0x33,
-		BC_PERIOD      = 0x34,    // . on main keyboard
-		BC_SLASH       = 0x35,    // / on main keyboard
-		BC_RSHIFT      = 0x36,
-		BC_MULTIPLY    = 0x37,    // * on numeric keypad
-		BC_LMENU       = 0x38,    // left Alt
-		BC_SPACE       = 0x39,
-		BC_CAPITAL     = 0x3A,
-		BC_F1          = 0x3B,
-		BC_F2          = 0x3C,
-		BC_F3          = 0x3D,
-		BC_F4          = 0x3E,
-		BC_F5          = 0x3F,
-		BC_F6          = 0x40,
-		BC_F7          = 0x41,
-		BC_F8          = 0x42,
-		BC_F9          = 0x43,
-		BC_F10         = 0x44,
-		BC_NUMLOCK     = 0x45,
-		BC_SCROLL      = 0x46,    // Scroll Lock
-		BC_NUMPAD7     = 0x47,
-		BC_NUMPAD8     = 0x48,
-		BC_NUMPAD9     = 0x49,
-		BC_SUBTRACT    = 0x4A,    // - on numeric keypad
-		BC_NUMPAD4     = 0x4B,
-		BC_NUMPAD5     = 0x4C,
-		BC_NUMPAD6     = 0x4D,
-		BC_ADD         = 0x4E,    // + on numeric keypad
-		BC_NUMPAD1     = 0x4F,
-		BC_NUMPAD2     = 0x50,
-		BC_NUMPAD3     = 0x51,
-		BC_NUMPAD0     = 0x52,
-		BC_DECIMAL     = 0x53,    // . on numeric keypad
-		BC_OEM_102     = 0x56,    // < > | on UK/Germany keyboards
-		BC_F11         = 0x57,
-		BC_F12         = 0x58,
-		BC_F13         = 0x64,    //                     (NEC PC98)
-		BC_F14         = 0x65,    //                     (NEC PC98)
-		BC_F15         = 0x66,    //                     (NEC PC98)
-		BC_KANA        = 0x70,    // (Japanese keyboard)
-		BC_ABNT_C1     = 0x73,    // / ? on Portugese (Brazilian) keyboards
-		BC_CONVERT     = 0x79,    // (Japanese keyboard)
-		BC_NOCONVERT   = 0x7B,    // (Japanese keyboard)
-		BC_YEN         = 0x7D,    // (Japanese keyboard)
-		BC_ABNT_C2     = 0x7E,    // Numpad . on Portugese (Brazilian) keyboards
-		BC_NUMPADEQUALS= 0x8D,    // = on numeric keypad (NEC PC98)
-		BC_PREVTRACK   = 0x90,    // Previous Track (BC_CIRCUMFLEX on Japanese keyboard)
-		BC_AT          = 0x91,    //                     (NEC PC98)
-		BC_COLON       = 0x92,    //                     (NEC PC98)
-		BC_UNDERLINE   = 0x93,    //                     (NEC PC98)
-		BC_KANJI       = 0x94,    // (Japanese keyboard)
-		BC_STOP        = 0x95,    //                     (NEC PC98)
-		BC_AX          = 0x96,    //                     (Japan AX)
-		BC_UNLABELED   = 0x97,    //                        (J3100)
-		BC_NEXTTRACK   = 0x99,    // Next Track
-		BC_NUMPADENTER = 0x9C,    // Enter on numeric keypad
-		BC_RCONTROL    = 0x9D,
-		BC_MUTE        = 0xA0,    // Mute
-		BC_CALCULATOR  = 0xA1,    // Calculator
-		BC_PLAYPAUSE   = 0xA2,    // Play / Pause
-		BC_MEDIASTOP   = 0xA4,    // Media Stop
-		BC_VOLUMEDOWN  = 0xAE,    // Volume -
-		BC_VOLUMEUP    = 0xB0,    // Volume +
-		BC_WEBHOME     = 0xB2,    // Web home
-		BC_NUMPADCOMMA = 0xB3,    // , on numeric keypad (NEC PC98)
-		BC_DIVIDE      = 0xB5,    // / on numeric keypad
-		BC_SYSRQ       = 0xB7,
-		BC_RMENU       = 0xB8,    // right Alt
-		BC_PAUSE       = 0xC5,    // Pause
-		BC_HOME        = 0xC7,    // Home on arrow keypad
-		BC_UP          = 0xC8,    // UpArrow on arrow keypad
-		BC_PGUP        = 0xC9,    // PgUp on arrow keypad
-		BC_LEFT        = 0xCB,    // LeftArrow on arrow keypad
-		BC_RIGHT       = 0xCD,    // RightArrow on arrow keypad
-		BC_END         = 0xCF,    // End on arrow keypad
-		BC_DOWN        = 0xD0,    // DownArrow on arrow keypad
-		BC_PGDOWN      = 0xD1,    // PgDn on arrow keypad
-		BC_INSERT      = 0xD2,    // Insert on arrow keypad
-		BC_DELETE      = 0xD3,    // Delete on arrow keypad
-		BC_LWIN        = 0xDB,    // Left Windows key
-		BC_RWIN        = 0xDC,    // Right Windows key
-		BC_APPS        = 0xDD,    // AppMenu key
-		BC_POWER       = 0xDE,    // System Power
-		BC_SLEEP       = 0xDF,    // System Sleep
-		BC_WAKE        = 0xE3,    // System Wake
-		BC_WEBSEARCH   = 0xE5,    // Web Search
-		BC_WEBFAVORITES= 0xE6,    // Web Favorites
-		BC_WEBREFRESH  = 0xE7,    // Web Refresh
-		BC_WEBSTOP     = 0xE8,    // Web Stop
-		BC_WEBFORWARD  = 0xE9,    // Web Forward
-		BC_WEBBACK     = 0xEA,    // Web Back
-		BC_MYCOMPUTER  = 0xEB,    // My Computer
-		BC_MAIL        = 0xEC,    // Mail
-		BC_MEDIASELECT = 0xED,     // Media Select
-		BC_MOUSE_LEFT = 0x800000EE, // Mouse buttons - Most important bit signifies this key is a mouse button
-		BC_MOUSE_RIGHT = 0x800000EF,
-		BC_MOUSE_MIDDLE = 0x800000F0,
-		BC_MOUSE_BTN4 = 0x800000F1,
-		BC_MOUSE_BTN5 = 0x800000F2,
-		BC_MOUSE_BTN6 = 0x800000F3,
-		BC_MOUSE_BTN7 = 0x800000F4,
-		BC_MOUSE_BTN8 = 0x800000F5,
-		BC_MOUSE_BTN9 = 0x800000F6,
-		BC_MOUSE_BTN10 = 0x800000F7,
-		BC_MOUSE_BTN11 = 0x800000F8,
-		BC_MOUSE_BTN12 = 0x800000F9,
-		BC_MOUSE_BTN13 = 0x800000FA,
-		BC_MOUSE_BTN14 = 0x800000FB,
-		BC_MOUSE_BTN15 = 0x800000FC,
-		BC_MOUSE_BTN16 = 0x800000FD,
-		BC_MOUSE_BTN17 = 0x800000FE,
-		BC_MOUSE_BTN18 = 0x800000FF,
-		BC_MOUSE_BTN19 = 0x80000101,
-		BC_MOUSE_BTN20 = 0x80000102,
-		BC_MOUSE_BTN21 = 0x80000103,
-		BC_MOUSE_BTN22 = 0x80000104,
-		BC_MOUSE_BTN23 = 0x80000105,
-		BC_MOUSE_BTN24 = 0x80000106,
-		BC_MOUSE_BTN25 = 0x80000107,
-		BC_MOUSE_BTN26 = 0x80000108,
-		BC_MOUSE_BTN27 = 0x80000109,
-		BC_MOUSE_BTN28 = 0x8000010A,
-		BC_MOUSE_BTN29 = 0x8000010B,
-		BC_MOUSE_BTN30 = 0x8000010C,
-		BC_MOUSE_BTN31 = 0x8000010D,
-		BC_MOUSE_BTN32 = 0x8000010E,
-		BC_GAMEPAD_A = 0x4000010F, // Joystick/Gamepad buttons- Second most important bit signifies key is a gamepad button
-		BC_GAMEPAD_B = 0x40000110, // Similar to keyboard names, these are for convenience named after Xbox controller buttons
-		BC_GAMEPAD_X = 0x40000111, // but if some other controller is connected you will need to learn yourself which of these
-		BC_GAMEPAD_Y = 0x40000112, // corresponds to which actual button on the controller.
-		BC_GAMEPAD_LB = 0x40000113,
-		BC_GAMEPAD_RB = 0x40000114,
-		BC_GAMEPAD_LS = 0x40000115,
-		BC_GAMEPAD_RS = 0x40000116,
-		BC_GAMEPAD_BACK = 0x40000117,
-		BC_GAMEPAD_START = 0x40000118,
-		BC_GAMEPAD_DPAD_LEFT = 0x40000119,
-		BC_GAMEPAD_DPAD_RIGHT = 0x4000011A,
-		BC_GAMEPAD_DPAD_UP = 0x4000011B,
-		BC_GAMEPAD_DPAD_DOWN = 0x4000011C,
-		BC_GAMEPAD_BTN1 = 0x4000011D,
-		BC_GAMEPAD_BTN2 = 0x4000011E,
-		BC_GAMEPAD_BTN3 = 0x4000011F,
-		BC_GAMEPAD_BTN4 = 0x40000120,
-		BC_GAMEPAD_BTN5 = 0x40000121,
-		BC_GAMEPAD_BTN6 = 0x40000122,
-		BC_GAMEPAD_BTN7 = 0x40000123,
-		BC_GAMEPAD_BTN8 = 0x40000124,
-		BC_GAMEPAD_BTN9 = 0x40000125,
-		BC_GAMEPAD_BTN10 = 0x40000126,
-		BC_GAMEPAD_BTN11 = 0x40000127,
-		BC_GAMEPAD_BTN12 = 0x40000128,
-		BC_GAMEPAD_BTN13 = 0x40000129,
-		BC_GAMEPAD_BTN14 = 0x4000012A,
-		BC_GAMEPAD_BTN15 = 0x4000012B,
-		BC_GAMEPAD_BTN16 = 0x4000012C,
-		BC_GAMEPAD_BTN17 = 0x4000012D,
-		BC_GAMEPAD_BTN18 = 0x4000012E,
-		BC_GAMEPAD_BTN19 = 0x4000012F,
-		BC_GAMEPAD_BTN20 = 0x40000130,
-		BC_Count = 304,
-		BC_NumKeys = 238, // IMPORTANT: Make sure to update these if you modify the values above
-		BC_NumMouse = 32,
-		BC_NumGamepad = 34,
-	};
-
-	/**	Contains data about a button input event. */
-	struct ButtonEvent
-	{
-	public:
-		ButtonEvent()
-			:mIsUsed(false)
-		{ }
-
-		ButtonCode buttonCode; /**< Button code this event is referring to. */
-		UINT64 timestamp; /**< Timestamp in ticks when the event happened. */
-		UINT32 deviceIdx; /**< Index of the device that the event originated from. */
-
-		/**	Query is the pressed button a keyboard button. */
-		bool isKeyboard() const { return (buttonCode & 0xC0000000) == 0; }
-
-		/** Query is the pressed button a mouse button. */
-		bool isMouse() const { return (buttonCode & 0x80000000) != 0; }
-
-		/** Query is the pressed button a gamepad button. */
-		bool isGamepad() const { return (buttonCode & 0x40000000) != 0; }
-
-		/**
-		 * Check if the event has been marked as used. Internally this means nothing but caller might choose to ignore an 
-		 * used event.
-		 */
-		bool isUsed() const { return mIsUsed; }
-
-		/** Mark the event as used. Internally this means nothing but caller might choose to ignore an used event. */
-		void markAsUsed() const { mIsUsed = true; }
-	private:
-		mutable bool mIsUsed;
-	};
-
-	/**
-	 * Pointer buttons. Generally these correspond to mouse buttons, but may be used in some form for touch input as well.
-	 */
-	enum class PointerEventButton
-	{
-		Left, Middle, Right, Count
-	};
-
-	/**	Type of pointer event.*/
-	enum class PointerEventType
-	{
-		CursorMoved,
-		ButtonPressed,
-		ButtonReleased,
-		DoubleClick
-	};
-
-	/**
-	 * Event that gets sent out when user interacts with the screen in some way, usually by moving the mouse cursor or
-	 * using touch input.
-	 */
-	struct PointerEvent
-	{
-	public:
-		PointerEvent()
-			:mIsUsed(false), mouseWheelScrollAmount(0.0f), type(PointerEventType::CursorMoved),
-			shift(false), control(false), alt(false), button(PointerEventButton::Left)
-		{
-			buttonStates[0] = false;
-			buttonStates[1] = false;
-			buttonStates[2] = false;
-		}
-
-		Vector2I screenPos; /**< Screen position where the input event occurred. */
-		Vector2I delta; /**< Change in movement since last sent event. */
-		bool buttonStates[(UINT32)PointerEventButton::Count]; /**< States of the pointer buttons (e.g. mouse buttons). */
-		PointerEventButton button; /**< Button that triggered the pointer event. Might be irrelevant 
-										depending on event type. (e.g. move events don't correspond to a button. */
-		PointerEventType type; /**< Type of the pointer event. */
-
-		bool shift; /**< Is shift button on the keyboard being held down. */
-		bool control; /**< Is control button on the keyboard being held down. */
-		bool alt; /**< Is alt button on the keyboard being held down. */
-
-		float mouseWheelScrollAmount; /**< If mouse wheel is being scrolled, what is the amount. Only relevant for move events. */
-
-		/**
-		 * Check if the event has been marked as used. Internally this means nothing but caller might choose to ignore an 
-		 * used event.
-		 */
-		bool isUsed() const { return mIsUsed; }
-
-		/** Mark the event as used. Internally this means nothing but caller might choose to ignore an used event. */
-		void markAsUsed() const { mIsUsed = true; }
-
-	private:
-		mutable bool mIsUsed;
-	};
-
-	/**	Types of special input commands. */
-	enum class InputCommandType
-	{
-		CursorMoveLeft, CursorMoveRight, CursorMoveUp, CursorMoveDown, 
-		SelectLeft, SelectRight, SelectUp, SelectDown,
-		Escape, Delete, Backspace, Return, Confirm
-	};
-
-	/**
-	 * Event that gets sent out when user inputs some text. These events may be preceeded by normal button events if user 
-	 * is typing on a keyboard. 
-	 */
-	struct TextInputEvent
-	{
-	public:
-		TextInputEvent()
-			:mIsUsed(false)
-		{ }
-
-		UINT32 textChar; /**< Character the that was input. */
-
-		/**
-		 * @brief	Check if the event has been marked as used. Internally this means nothing
-		 *			but caller might choose to ignore an used event.
-		 */
-		bool isUsed() const { return mIsUsed; }
-
-		/**
-		 * @brief	Mark the event as used. Internally this means nothing
-		 *			but caller might choose to ignore an used event.
-		 */
-		void markAsUsed() const { mIsUsed = true; }
-
-	private:
-		mutable bool mIsUsed;
-	};
-
-	/**	Types of input devices. */
-	enum class InputDevice
-	{
-		Keyboard,
-		Mouse,
-		Gamepad,
-		Count // Keep at end
-	};
-
-	/**	Common input axis types. */
-	enum class InputAxis
-	{
-		MouseX, /**< Mouse axis X. */
-		MouseY, /**< Mouse axis Y. */
-		MouseZ, /**< Mouse wheel/scroll axis. */
-		LeftStickX, /**< Gamepad left stick X */
-		LeftStickY, /**<  Gamepad left stick Y */
-		RightStickX, /**< Gamepad right stick X */
-		RightStickY, /**< Gamepad right stick Y */
-		LeftTrigger, /**< Gamepad left trigger */
-		RightTrigger, /**< Gamepad right trigger */
-		Count // Keep at end
-	};
-
-	/**	Modifiers used with along with keyboard buttons. */
-	enum class ButtonModifier
-	{
-		None = 0x00,
-		Shift = 0x01,
-		Ctrl = 0x02,
-		Alt = 0x04,
-		ShiftCtrl = 0x03,
-		CtrlAlt = 0x06,
-		ShiftAlt = 0x05,
-		ShiftCtrlAlt = 0x07
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsVector2I.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Input
+	 *  @{
+	 */
+
+	/**
+	 * Contains all possible input buttons, including keyboard scan codes, mouse buttons and gamepad buttons.
+	 *
+	 * @note
+	 * These codes are only keyboard scan codes. This means that exact scan code identifier might not correspond to that 
+	 * exact character on users keyboard, depending on users input locale. Only for US locale will these scan code names 
+	 * will match the actual keyboard input. Think of the US key code names as only a convenience for more easily 
+	 * identifying which location on the keyboard a scan code represents.
+	 * @note
+	 * When storing these sequentially make sure to only reference the low order 2 bytes. Two high order bytes are used for 
+	 * various flags.
+	 */
+	enum ButtonCode
+	{
+		BC_UNASSIGNED  = 0x00,
+		BC_ESCAPE      = 0x01,
+		BC_1           = 0x02,
+		BC_2           = 0x03,
+		BC_3           = 0x04,
+		BC_4           = 0x05,
+		BC_5           = 0x06,
+		BC_6           = 0x07,
+		BC_7           = 0x08,
+		BC_8           = 0x09,
+		BC_9           = 0x0A,
+		BC_0           = 0x0B,
+		BC_MINUS       = 0x0C,    // - on main keyboard
+		BC_EQUALS      = 0x0D,
+		BC_BACK        = 0x0E,    // backspace
+		BC_TAB         = 0x0F,
+		BC_Q           = 0x10,
+		BC_W           = 0x11,
+		BC_E           = 0x12,
+		BC_R           = 0x13,
+		BC_T           = 0x14,
+		BC_Y           = 0x15,
+		BC_U           = 0x16,
+		BC_I           = 0x17,
+		BC_O           = 0x18,
+		BC_P           = 0x19,
+		BC_LBRACKET    = 0x1A,
+		BC_RBRACKET    = 0x1B,
+		BC_RETURN      = 0x1C,    // Enter on main keyboard
+		BC_LCONTROL    = 0x1D,
+		BC_A           = 0x1E,
+		BC_S           = 0x1F,
+		BC_D           = 0x20,
+		BC_F           = 0x21,
+		BC_G           = 0x22,
+		BC_H           = 0x23,
+		BC_J           = 0x24,
+		BC_K           = 0x25,
+		BC_L           = 0x26,
+		BC_SEMICOLON   = 0x27,
+		BC_APOSTROPHE  = 0x28,
+		BC_GRAVE       = 0x29,    // accent
+		BC_LSHIFT      = 0x2A,
+		BC_BACKSLASH   = 0x2B,
+		BC_Z           = 0x2C,
+		BC_X           = 0x2D,
+		BC_C           = 0x2E,
+		BC_V           = 0x2F,
+		BC_B           = 0x30,
+		BC_N           = 0x31,
+		BC_M           = 0x32,
+		BC_COMMA       = 0x33,
+		BC_PERIOD      = 0x34,    // . on main keyboard
+		BC_SLASH       = 0x35,    // / on main keyboard
+		BC_RSHIFT      = 0x36,
+		BC_MULTIPLY    = 0x37,    // * on numeric keypad
+		BC_LMENU       = 0x38,    // left Alt
+		BC_SPACE       = 0x39,
+		BC_CAPITAL     = 0x3A,
+		BC_F1          = 0x3B,
+		BC_F2          = 0x3C,
+		BC_F3          = 0x3D,
+		BC_F4          = 0x3E,
+		BC_F5          = 0x3F,
+		BC_F6          = 0x40,
+		BC_F7          = 0x41,
+		BC_F8          = 0x42,
+		BC_F9          = 0x43,
+		BC_F10         = 0x44,
+		BC_NUMLOCK     = 0x45,
+		BC_SCROLL      = 0x46,    // Scroll Lock
+		BC_NUMPAD7     = 0x47,
+		BC_NUMPAD8     = 0x48,
+		BC_NUMPAD9     = 0x49,
+		BC_SUBTRACT    = 0x4A,    // - on numeric keypad
+		BC_NUMPAD4     = 0x4B,
+		BC_NUMPAD5     = 0x4C,
+		BC_NUMPAD6     = 0x4D,
+		BC_ADD         = 0x4E,    // + on numeric keypad
+		BC_NUMPAD1     = 0x4F,
+		BC_NUMPAD2     = 0x50,
+		BC_NUMPAD3     = 0x51,
+		BC_NUMPAD0     = 0x52,
+		BC_DECIMAL     = 0x53,    // . on numeric keypad
+		BC_OEM_102     = 0x56,    // < > | on UK/Germany keyboards
+		BC_F11         = 0x57,
+		BC_F12         = 0x58,
+		BC_F13         = 0x64,    //                     (NEC PC98)
+		BC_F14         = 0x65,    //                     (NEC PC98)
+		BC_F15         = 0x66,    //                     (NEC PC98)
+		BC_KANA        = 0x70,    // (Japanese keyboard)
+		BC_ABNT_C1     = 0x73,    // / ? on Portugese (Brazilian) keyboards
+		BC_CONVERT     = 0x79,    // (Japanese keyboard)
+		BC_NOCONVERT   = 0x7B,    // (Japanese keyboard)
+		BC_YEN         = 0x7D,    // (Japanese keyboard)
+		BC_ABNT_C2     = 0x7E,    // Numpad . on Portugese (Brazilian) keyboards
+		BC_NUMPADEQUALS= 0x8D,    // = on numeric keypad (NEC PC98)
+		BC_PREVTRACK   = 0x90,    // Previous Track (BC_CIRCUMFLEX on Japanese keyboard)
+		BC_AT          = 0x91,    //                     (NEC PC98)
+		BC_COLON       = 0x92,    //                     (NEC PC98)
+		BC_UNDERLINE   = 0x93,    //                     (NEC PC98)
+		BC_KANJI       = 0x94,    // (Japanese keyboard)
+		BC_STOP        = 0x95,    //                     (NEC PC98)
+		BC_AX          = 0x96,    //                     (Japan AX)
+		BC_UNLABELED   = 0x97,    //                        (J3100)
+		BC_NEXTTRACK   = 0x99,    // Next Track
+		BC_NUMPADENTER = 0x9C,    // Enter on numeric keypad
+		BC_RCONTROL    = 0x9D,
+		BC_MUTE        = 0xA0,    // Mute
+		BC_CALCULATOR  = 0xA1,    // Calculator
+		BC_PLAYPAUSE   = 0xA2,    // Play / Pause
+		BC_MEDIASTOP   = 0xA4,    // Media Stop
+		BC_VOLUMEDOWN  = 0xAE,    // Volume -
+		BC_VOLUMEUP    = 0xB0,    // Volume +
+		BC_WEBHOME     = 0xB2,    // Web home
+		BC_NUMPADCOMMA = 0xB3,    // , on numeric keypad (NEC PC98)
+		BC_DIVIDE      = 0xB5,    // / on numeric keypad
+		BC_SYSRQ       = 0xB7,
+		BC_RMENU       = 0xB8,    // right Alt
+		BC_PAUSE       = 0xC5,    // Pause
+		BC_HOME        = 0xC7,    // Home on arrow keypad
+		BC_UP          = 0xC8,    // UpArrow on arrow keypad
+		BC_PGUP        = 0xC9,    // PgUp on arrow keypad
+		BC_LEFT        = 0xCB,    // LeftArrow on arrow keypad
+		BC_RIGHT       = 0xCD,    // RightArrow on arrow keypad
+		BC_END         = 0xCF,    // End on arrow keypad
+		BC_DOWN        = 0xD0,    // DownArrow on arrow keypad
+		BC_PGDOWN      = 0xD1,    // PgDn on arrow keypad
+		BC_INSERT      = 0xD2,    // Insert on arrow keypad
+		BC_DELETE      = 0xD3,    // Delete on arrow keypad
+		BC_LWIN        = 0xDB,    // Left Windows key
+		BC_RWIN        = 0xDC,    // Right Windows key
+		BC_APPS        = 0xDD,    // AppMenu key
+		BC_POWER       = 0xDE,    // System Power
+		BC_SLEEP       = 0xDF,    // System Sleep
+		BC_WAKE        = 0xE3,    // System Wake
+		BC_WEBSEARCH   = 0xE5,    // Web Search
+		BC_WEBFAVORITES= 0xE6,    // Web Favorites
+		BC_WEBREFRESH  = 0xE7,    // Web Refresh
+		BC_WEBSTOP     = 0xE8,    // Web Stop
+		BC_WEBFORWARD  = 0xE9,    // Web Forward
+		BC_WEBBACK     = 0xEA,    // Web Back
+		BC_MYCOMPUTER  = 0xEB,    // My Computer
+		BC_MAIL        = 0xEC,    // Mail
+		BC_MEDIASELECT = 0xED,     // Media Select
+		BC_MOUSE_LEFT = 0x800000EE, // Mouse buttons - Most important bit signifies this key is a mouse button
+		BC_MOUSE_RIGHT = 0x800000EF,
+		BC_MOUSE_MIDDLE = 0x800000F0,
+		BC_MOUSE_BTN4 = 0x800000F1,
+		BC_MOUSE_BTN5 = 0x800000F2,
+		BC_MOUSE_BTN6 = 0x800000F3,
+		BC_MOUSE_BTN7 = 0x800000F4,
+		BC_MOUSE_BTN8 = 0x800000F5,
+		BC_MOUSE_BTN9 = 0x800000F6,
+		BC_MOUSE_BTN10 = 0x800000F7,
+		BC_MOUSE_BTN11 = 0x800000F8,
+		BC_MOUSE_BTN12 = 0x800000F9,
+		BC_MOUSE_BTN13 = 0x800000FA,
+		BC_MOUSE_BTN14 = 0x800000FB,
+		BC_MOUSE_BTN15 = 0x800000FC,
+		BC_MOUSE_BTN16 = 0x800000FD,
+		BC_MOUSE_BTN17 = 0x800000FE,
+		BC_MOUSE_BTN18 = 0x800000FF,
+		BC_MOUSE_BTN19 = 0x80000101,
+		BC_MOUSE_BTN20 = 0x80000102,
+		BC_MOUSE_BTN21 = 0x80000103,
+		BC_MOUSE_BTN22 = 0x80000104,
+		BC_MOUSE_BTN23 = 0x80000105,
+		BC_MOUSE_BTN24 = 0x80000106,
+		BC_MOUSE_BTN25 = 0x80000107,
+		BC_MOUSE_BTN26 = 0x80000108,
+		BC_MOUSE_BTN27 = 0x80000109,
+		BC_MOUSE_BTN28 = 0x8000010A,
+		BC_MOUSE_BTN29 = 0x8000010B,
+		BC_MOUSE_BTN30 = 0x8000010C,
+		BC_MOUSE_BTN31 = 0x8000010D,
+		BC_MOUSE_BTN32 = 0x8000010E,
+		BC_GAMEPAD_A = 0x4000010F, // Joystick/Gamepad buttons- Second most important bit signifies key is a gamepad button
+		BC_GAMEPAD_B = 0x40000110, // Similar to keyboard names, these are for convenience named after Xbox controller buttons
+		BC_GAMEPAD_X = 0x40000111, // but if some other controller is connected you will need to learn yourself which of these
+		BC_GAMEPAD_Y = 0x40000112, // corresponds to which actual button on the controller.
+		BC_GAMEPAD_LB = 0x40000113,
+		BC_GAMEPAD_RB = 0x40000114,
+		BC_GAMEPAD_LS = 0x40000115,
+		BC_GAMEPAD_RS = 0x40000116,
+		BC_GAMEPAD_BACK = 0x40000117,
+		BC_GAMEPAD_START = 0x40000118,
+		BC_GAMEPAD_DPAD_LEFT = 0x40000119,
+		BC_GAMEPAD_DPAD_RIGHT = 0x4000011A,
+		BC_GAMEPAD_DPAD_UP = 0x4000011B,
+		BC_GAMEPAD_DPAD_DOWN = 0x4000011C,
+		BC_GAMEPAD_BTN1 = 0x4000011D,
+		BC_GAMEPAD_BTN2 = 0x4000011E,
+		BC_GAMEPAD_BTN3 = 0x4000011F,
+		BC_GAMEPAD_BTN4 = 0x40000120,
+		BC_GAMEPAD_BTN5 = 0x40000121,
+		BC_GAMEPAD_BTN6 = 0x40000122,
+		BC_GAMEPAD_BTN7 = 0x40000123,
+		BC_GAMEPAD_BTN8 = 0x40000124,
+		BC_GAMEPAD_BTN9 = 0x40000125,
+		BC_GAMEPAD_BTN10 = 0x40000126,
+		BC_GAMEPAD_BTN11 = 0x40000127,
+		BC_GAMEPAD_BTN12 = 0x40000128,
+		BC_GAMEPAD_BTN13 = 0x40000129,
+		BC_GAMEPAD_BTN14 = 0x4000012A,
+		BC_GAMEPAD_BTN15 = 0x4000012B,
+		BC_GAMEPAD_BTN16 = 0x4000012C,
+		BC_GAMEPAD_BTN17 = 0x4000012D,
+		BC_GAMEPAD_BTN18 = 0x4000012E,
+		BC_GAMEPAD_BTN19 = 0x4000012F,
+		BC_GAMEPAD_BTN20 = 0x40000130,
+		BC_Count = 304,
+		BC_NumKeys = 238, // IMPORTANT: Make sure to update these if you modify the values above
+		BC_NumMouse = 32,
+		BC_NumGamepad = 34,
+	};
+
+	/**	Contains data about a button input event. */
+	struct ButtonEvent
+	{
+	public:
+		ButtonEvent()
+			:mIsUsed(false)
+		{ }
+
+		ButtonCode buttonCode; /**< Button code this event is referring to. */
+		UINT64 timestamp; /**< Timestamp in ticks when the event happened. */
+		UINT32 deviceIdx; /**< Index of the device that the event originated from. */
+
+		/**	Query is the pressed button a keyboard button. */
+		bool isKeyboard() const { return (buttonCode & 0xC0000000) == 0; }
+
+		/** Query is the pressed button a mouse button. */
+		bool isMouse() const { return (buttonCode & 0x80000000) != 0; }
+
+		/** Query is the pressed button a gamepad button. */
+		bool isGamepad() const { return (buttonCode & 0x40000000) != 0; }
+
+		/**
+		 * Check if the event has been marked as used. Internally this means nothing but caller might choose to ignore an 
+		 * used event.
+		 */
+		bool isUsed() const { return mIsUsed; }
+
+		/** Mark the event as used. Internally this means nothing but caller might choose to ignore an used event. */
+		void markAsUsed() const { mIsUsed = true; }
+	private:
+		mutable bool mIsUsed;
+	};
+
+	/**
+	 * Pointer buttons. Generally these correspond to mouse buttons, but may be used in some form for touch input as well.
+	 */
+	enum class PointerEventButton
+	{
+		Left, Middle, Right, Count
+	};
+
+	/**	Type of pointer event.*/
+	enum class PointerEventType
+	{
+		CursorMoved,
+		ButtonPressed,
+		ButtonReleased,
+		DoubleClick
+	};
+
+	/**
+	 * Event that gets sent out when user interacts with the screen in some way, usually by moving the mouse cursor or
+	 * using touch input.
+	 */
+	struct PointerEvent
+	{
+	public:
+		PointerEvent()
+			:mIsUsed(false), mouseWheelScrollAmount(0.0f), type(PointerEventType::CursorMoved),
+			shift(false), control(false), alt(false), button(PointerEventButton::Left)
+		{
+			buttonStates[0] = false;
+			buttonStates[1] = false;
+			buttonStates[2] = false;
+		}
+
+		Vector2I screenPos; /**< Screen position where the input event occurred. */
+		Vector2I delta; /**< Change in movement since last sent event. */
+		bool buttonStates[(UINT32)PointerEventButton::Count]; /**< States of the pointer buttons (e.g. mouse buttons). */
+		PointerEventButton button; /**< Button that triggered the pointer event. Might be irrelevant 
+										depending on event type. (e.g. move events don't correspond to a button. */
+		PointerEventType type; /**< Type of the pointer event. */
+
+		bool shift; /**< Is shift button on the keyboard being held down. */
+		bool control; /**< Is control button on the keyboard being held down. */
+		bool alt; /**< Is alt button on the keyboard being held down. */
+
+		float mouseWheelScrollAmount; /**< If mouse wheel is being scrolled, what is the amount. Only relevant for move events. */
+
+		/**
+		 * Check if the event has been marked as used. Internally this means nothing but caller might choose to ignore an 
+		 * used event.
+		 */
+		bool isUsed() const { return mIsUsed; }
+
+		/** Mark the event as used. Internally this means nothing but caller might choose to ignore an used event. */
+		void markAsUsed() const { mIsUsed = true; }
+
+	private:
+		mutable bool mIsUsed;
+	};
+
+	/**	Types of special input commands. */
+	enum class InputCommandType
+	{
+		CursorMoveLeft, CursorMoveRight, CursorMoveUp, CursorMoveDown, 
+		SelectLeft, SelectRight, SelectUp, SelectDown,
+		Escape, Delete, Backspace, Return, Confirm
+	};
+
+	/**
+	 * Event that gets sent out when user inputs some text. These events may be preceeded by normal button events if user 
+	 * is typing on a keyboard. 
+	 */
+	struct TextInputEvent
+	{
+	public:
+		TextInputEvent()
+			:mIsUsed(false)
+		{ }
+
+		UINT32 textChar; /**< Character the that was input. */
+
+		/**
+		 * Check if the event has been marked as used. Internally this means nothing but caller might choose to ignore an
+		 * used event.
+		 */
+		bool isUsed() const { return mIsUsed; }
+
+		/** Mark the event as used. Internally this means nothing but caller might choose to ignore an used event. */
+		void markAsUsed() const { mIsUsed = true; }
+
+	private:
+		mutable bool mIsUsed;
+	};
+
+	/**	Types of input devices. */
+	enum class InputDevice
+	{
+		Keyboard,
+		Mouse,
+		Gamepad,
+		Count // Keep at end
+	};
+
+	/**	Common input axis types. */
+	enum class InputAxis
+	{
+		MouseX, /**< Mouse axis X. */
+		MouseY, /**< Mouse axis Y. */
+		MouseZ, /**< Mouse wheel/scroll axis. */
+		LeftStickX, /**< Gamepad left stick X */
+		LeftStickY, /**<  Gamepad left stick Y */
+		RightStickX, /**< Gamepad right stick X */
+		RightStickY, /**< Gamepad right stick Y */
+		LeftTrigger, /**< Gamepad left trigger */
+		RightTrigger, /**< Gamepad right trigger */
+		Count // Keep at end
+	};
+
+	/**	Modifiers used with along with keyboard buttons. */
+	enum class ButtonModifier
+	{
+		None = 0x00,
+		Shift = 0x01,
+		Ctrl = 0x02,
+		Alt = 0x04,
+		ShiftCtrl = 0x03,
+		CtrlAlt = 0x06,
+		ShiftAlt = 0x05,
+		ShiftCtrlAlt = 0x07
+	};
+
+	/** @} */
 }

+ 46 - 48
Source/BansheeCore/Include/BsPixelVolume.h

@@ -1,49 +1,47 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Utility-Core
-	 *  @{
-	 */
-
-	/**	Represents a 3D region of pixels used for referencing pixel data. */
-	struct BS_CORE_EXPORT PixelVolume
-	{
-		UINT32 left, top, right, bottom, front, back;
-
-		PixelVolume()
-			: left(0), top(0), right(1), bottom(1), front(0), back(1)
-		{ }
-
-		PixelVolume(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom):
-			left(left), top(top), right(right), bottom(bottom), front(0), back(1)
-		{
-			assert(right >= left && bottom >= top && back >= front);
-		}
-
-		PixelVolume(UINT32 left, UINT32 top, UINT32 front, UINT32 right, UINT32 bottom, UINT32 back):
-			left(left), top(top), right(right), bottom(bottom), front(front), back(back)
-		{
-			assert(right >= left && bottom >= top && back >= front);
-		}
-            
-		/**
-		 * @brief	Return true if the other box is a part of this one.
-		 */
-		bool contains(const PixelVolume &volume) const
-		{
-			return (volume.left >= left && volume.top >= top && volume.front >= front &&
-				volume.right <= right && volume.bottom <= bottom && volume.back <= back);
-		}
-            
-		UINT32 getWidth() const { return right-left; }
-		UINT32 getHeight() const { return bottom-top; }
-		UINT32 getDepth() const { return back-front; }
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Utility-Core
+	 *  @{
+	 */
+
+	/**	Represents a 3D region of pixels used for referencing pixel data. */
+	struct BS_CORE_EXPORT PixelVolume
+	{
+		UINT32 left, top, right, bottom, front, back;
+
+		PixelVolume()
+			: left(0), top(0), right(1), bottom(1), front(0), back(1)
+		{ }
+
+		PixelVolume(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom):
+			left(left), top(top), right(right), bottom(bottom), front(0), back(1)
+		{
+			assert(right >= left && bottom >= top && back >= front);
+		}
+
+		PixelVolume(UINT32 left, UINT32 top, UINT32 front, UINT32 right, UINT32 bottom, UINT32 back):
+			left(left), top(top), right(right), bottom(bottom), front(front), back(back)
+		{
+			assert(right >= left && bottom >= top && back >= front);
+		}
+            
+		/**	Return true if the other box is a part of this one. */
+		bool contains(const PixelVolume &volume) const
+		{
+			return (volume.left >= left && volume.top >= top && volume.front >= front &&
+				volume.right <= right && volume.bottom <= bottom && volume.back <= back);
+		}
+            
+		UINT32 getWidth() const { return right-left; }
+		UINT32 getHeight() const { return bottom-top; }
+		UINT32 getDepth() const { return back-front; }
+	};
+
+	/** @} */
 }

+ 265 - 269
Source/BansheeCore/Include/BsPrefabDiffRTTI.h

@@ -1,270 +1,266 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsRTTIType.h"
-#include "BsPrefabDiff.h"
-#include "BsSerializedObject.h"
-#include "BsGameObjectManager.h"
-#include "BsBinarySerializer.h"
-
-namespace BansheeEngine
-{
-	/** @cond RTTI */
-	/** @addtogroup RTTI-Impl-Core
-	 *  @{
-	 */
-
-	class BS_CORE_EXPORT PrefabComponentDiffRTTI : public RTTIType < PrefabComponentDiff, IReflectable, PrefabComponentDiffRTTI >
-	{
-	private:
-		BS_PLAIN_MEMBER(id)
-		BS_REFLPTR_MEMBER(data);
-	public:
-		PrefabComponentDiffRTTI()
-		{
-			BS_ADD_PLAIN_FIELD(id, 0);
-			BS_ADD_REFLPTR_FIELD(data, 1);
-		}
-
-		const String& getRTTIName() override
-		{
-			static String name = "PrefabComponentDiff";
-			return name;
-		}
-
-		UINT32 getRTTIId() override
-		{
-			return TID_PrefabComponentDiff;
-		}
-
-		std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<PrefabComponentDiff>();
-		}
-	};
-
-	class BS_CORE_EXPORT PrefabObjectDiffRTTI : public RTTIType < PrefabObjectDiff, IReflectable, PrefabObjectDiffRTTI >
-	{
-	private:
-		BS_PLAIN_MEMBER(id)
-
-		BS_PLAIN_MEMBER(name)
-		BS_PLAIN_MEMBER(position);
-		BS_PLAIN_MEMBER(rotation);
-		BS_PLAIN_MEMBER(scale);
-		BS_PLAIN_MEMBER(isActive);
-		BS_PLAIN_MEMBER(soFlags);
-
-		BS_REFLPTR_MEMBER_VEC(componentDiffs)
-		BS_PLAIN_MEMBER_VEC(removedComponents)
-		BS_REFLPTR_MEMBER_VEC(addedComponents)
-
-		BS_REFLPTR_MEMBER_VEC(childDiffs)
-		BS_PLAIN_MEMBER_VEC(removedChildren)
-		BS_REFLPTR_MEMBER_VEC(addedChildren)
-	public:
-		PrefabObjectDiffRTTI()
-		{
-			BS_ADD_PLAIN_FIELD(id, 0);
-			BS_ADD_PLAIN_FIELD(name, 1);
-
-			BS_ADD_REFLPTR_FIELD_ARR(componentDiffs, 2);
-			BS_ADD_PLAIN_FIELD_ARR(removedComponents, 3);
-			BS_ADD_REFLPTR_FIELD_ARR(addedComponents, 4);
-			BS_ADD_REFLPTR_FIELD_ARR(childDiffs, 5);
-
-			BS_ADD_PLAIN_FIELD_ARR(removedChildren, 6);
-			BS_ADD_REFLPTR_FIELD_ARR(addedChildren, 7);
-
-			BS_ADD_PLAIN_FIELD(position, 8);
-			BS_ADD_PLAIN_FIELD(rotation, 9);
-			BS_ADD_PLAIN_FIELD(scale, 10);
-			BS_ADD_PLAIN_FIELD(isActive, 11);
-			BS_ADD_PLAIN_FIELD(soFlags, 12);
-		}
-
-		const String& getRTTIName() override
-		{
-			static String name = "PrefabObjectDiff";
-			return name;
-		}
-
-		UINT32 getRTTIId() override
-		{
-			return TID_PrefabObjectDiff;
-		}
-
-		std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<PrefabObjectDiff>();
-		}
-	};
-
-	class BS_CORE_EXPORT PrefabDiffRTTI : public RTTIType < PrefabDiff, IReflectable, PrefabDiffRTTI >
-	{
-		/**
-		 * @brief	Contains data about a game object handle serialized in a prefab diff. 
-		 */
-		struct SerializedHandle
-		{
-			SPtr<SerializedObject> object;
-			SPtr<GameObjectHandleBase> handle;
-		};
-
-	private:
-		BS_REFLPTR_MEMBER(mRoot);
-	public:
-		PrefabDiffRTTI()
-		{
-			BS_ADD_REFLPTR_FIELD(mRoot, 0);
-		}
-
-		void onDeserializationStarted(IReflectable* obj) override
-		{
-			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
-
-			if (GameObjectManager::instance().isGameObjectDeserializationActive())
-				GameObjectManager::instance().registerOnDeserializationEndCallback(std::bind(&PrefabDiffRTTI::delayedOnDeserializationEnded, prefabDiff));
-		}
-
-		void onDeserializationEnded(IReflectable* obj) override
-		{
-			assert(GameObjectManager::instance().isGameObjectDeserializationActive());
-
-			// Make sure to deserialize all game object handles since their IDs need to be updated. Normally they are
-			// updated automatically upon deserialization but since we store them in intermediate form we need to manually
-			// deserialize and reserialize them in order to update their IDs.
-			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
-
-			Stack<SPtr<PrefabObjectDiff>> todo;
-
-			if (prefabDiff->mRoot != nullptr)
-				todo.push(prefabDiff->mRoot);
-
-			UnorderedSet<SPtr<SerializedObject>> handleObjects;
-
-			while (!todo.empty())
-			{
-				SPtr<PrefabObjectDiff> current = todo.top();
-				todo.pop();
-
-				for (auto& component : current->addedComponents)
-					findGameObjectHandles(component, handleObjects);
-
-				for (auto& child : current->addedChildren)
-					findGameObjectHandles(child, handleObjects);
-
-				for (auto& component : current->componentDiffs)
-					findGameObjectHandles(component->data, handleObjects);
-
-				for (auto& child : current->childDiffs)
-					todo.push(child);
-			}
-
-			Vector<SerializedHandle> handleData(handleObjects.size());
-
-			UINT32 idx = 0;
-			BinarySerializer bs;
-			for (auto& handleObject : handleObjects)
-			{
-				SerializedHandle& handle = handleData[idx];
-
-				handle.object = handleObject;
-				handle.handle = std::static_pointer_cast<GameObjectHandleBase>(bs._decodeIntermediate(handleObject));
-
-				idx++;
-			}
-
-			prefabDiff->mRTTIData = handleData;
-		}
-
-		/**
-		 * @brief	Decodes GameObjectHandles from their binary format, because during deserialization GameObjectManager
-		 *			will update all object IDs and we want to keep the handles up to date.So we deserialize them
-		 *			and allow them to be updated before storing them back into binary format.
-		 */
-		static void delayedOnDeserializationEnded(PrefabDiff* prefabDiff)
-		{
-			Vector<SerializedHandle>& handleData = any_cast_ref<Vector<SerializedHandle>>(prefabDiff->mRTTIData);
-
-			BinarySerializer bs;
-			for (auto& serializedHandle : handleData)
-			{
-				if (serializedHandle.handle != nullptr)
-					*serializedHandle.object = *bs._encodeIntermediate(serializedHandle.handle.get());
-			}
-
-			prefabDiff->mRTTIData = nullptr;
-		}
-
-		/**
-		 * @brief	Scans the entire hierarchy and find all serialized GameObjectHandle objects.
-		 */
-		static void findGameObjectHandles(const SPtr<SerializedObject>& serializedObject, UnorderedSet<SPtr<SerializedObject>>& handleObjects)
-		{
-			for (auto& subObject : serializedObject->subObjects)
-			{
-				RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
-				if (rtti == nullptr)
-					continue;
-
-				if (rtti->getRTTIId() == TID_GameObjectHandleBase)
-				{
-					handleObjects.insert(serializedObject);
-					return;
-				}
-
-				for (auto& child : subObject.entries)
-				{
-					RTTIField* curGenericField = rtti->findField(child.second.fieldId);
-					if (curGenericField == nullptr)
-						continue;
-
-					SPtr<SerializedInstance> entryData = child.second.serialized;
-					if (entryData == nullptr)
-						continue;
-
-					if (rtti_is_of_type<SerializedArray>(entryData))
-					{
-						SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
-						
-						for (auto& arrayElem : arrayData->entries)
-						{
-							if (arrayElem.second.serialized != nullptr && rtti_is_of_type<SerializedObject>(arrayElem.second.serialized))
-							{
-								SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
-								findGameObjectHandles(arrayElemData, handleObjects);
-							}
-						}
-					}
-					else if(rtti_is_of_type<SerializedObject>(entryData))
-					{
-						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
-						findGameObjectHandles(fieldObjectData, handleObjects);
-					}
-				}
-			}
-		}
-
-		const String& getRTTIName() override
-		{
-			static String name = "PrefabDiff";
-			return name;
-		}
-
-		UINT32 getRTTIId() override
-		{
-			return TID_PrefabDiff;
-		}
-
-		std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<PrefabDiff>();
-		}
-	};
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsPrefabDiff.h"
+#include "BsSerializedObject.h"
+#include "BsGameObjectManager.h"
+#include "BsBinarySerializer.h"
+
+namespace BansheeEngine
+{
+	/** @cond RTTI */
+	/** @addtogroup RTTI-Impl-Core
+	 *  @{
+	 */
+
+	class BS_CORE_EXPORT PrefabComponentDiffRTTI : public RTTIType < PrefabComponentDiff, IReflectable, PrefabComponentDiffRTTI >
+	{
+	private:
+		BS_PLAIN_MEMBER(id)
+		BS_REFLPTR_MEMBER(data);
+	public:
+		PrefabComponentDiffRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(id, 0);
+			BS_ADD_REFLPTR_FIELD(data, 1);
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "PrefabComponentDiff";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_PrefabComponentDiff;
+		}
+
+		std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<PrefabComponentDiff>();
+		}
+	};
+
+	class BS_CORE_EXPORT PrefabObjectDiffRTTI : public RTTIType < PrefabObjectDiff, IReflectable, PrefabObjectDiffRTTI >
+	{
+	private:
+		BS_PLAIN_MEMBER(id)
+
+		BS_PLAIN_MEMBER(name)
+		BS_PLAIN_MEMBER(position);
+		BS_PLAIN_MEMBER(rotation);
+		BS_PLAIN_MEMBER(scale);
+		BS_PLAIN_MEMBER(isActive);
+		BS_PLAIN_MEMBER(soFlags);
+
+		BS_REFLPTR_MEMBER_VEC(componentDiffs)
+		BS_PLAIN_MEMBER_VEC(removedComponents)
+		BS_REFLPTR_MEMBER_VEC(addedComponents)
+
+		BS_REFLPTR_MEMBER_VEC(childDiffs)
+		BS_PLAIN_MEMBER_VEC(removedChildren)
+		BS_REFLPTR_MEMBER_VEC(addedChildren)
+	public:
+		PrefabObjectDiffRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(id, 0);
+			BS_ADD_PLAIN_FIELD(name, 1);
+
+			BS_ADD_REFLPTR_FIELD_ARR(componentDiffs, 2);
+			BS_ADD_PLAIN_FIELD_ARR(removedComponents, 3);
+			BS_ADD_REFLPTR_FIELD_ARR(addedComponents, 4);
+			BS_ADD_REFLPTR_FIELD_ARR(childDiffs, 5);
+
+			BS_ADD_PLAIN_FIELD_ARR(removedChildren, 6);
+			BS_ADD_REFLPTR_FIELD_ARR(addedChildren, 7);
+
+			BS_ADD_PLAIN_FIELD(position, 8);
+			BS_ADD_PLAIN_FIELD(rotation, 9);
+			BS_ADD_PLAIN_FIELD(scale, 10);
+			BS_ADD_PLAIN_FIELD(isActive, 11);
+			BS_ADD_PLAIN_FIELD(soFlags, 12);
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "PrefabObjectDiff";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_PrefabObjectDiff;
+		}
+
+		std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<PrefabObjectDiff>();
+		}
+	};
+
+	class BS_CORE_EXPORT PrefabDiffRTTI : public RTTIType < PrefabDiff, IReflectable, PrefabDiffRTTI >
+	{
+		/**	Contains data about a game object handle serialized in a prefab diff.  */
+		struct SerializedHandle
+		{
+			SPtr<SerializedObject> object;
+			SPtr<GameObjectHandleBase> handle;
+		};
+
+	private:
+		BS_REFLPTR_MEMBER(mRoot);
+	public:
+		PrefabDiffRTTI()
+		{
+			BS_ADD_REFLPTR_FIELD(mRoot, 0);
+		}
+
+		void onDeserializationStarted(IReflectable* obj) override
+		{
+			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
+
+			if (GameObjectManager::instance().isGameObjectDeserializationActive())
+				GameObjectManager::instance().registerOnDeserializationEndCallback(std::bind(&PrefabDiffRTTI::delayedOnDeserializationEnded, prefabDiff));
+		}
+
+		void onDeserializationEnded(IReflectable* obj) override
+		{
+			assert(GameObjectManager::instance().isGameObjectDeserializationActive());
+
+			// Make sure to deserialize all game object handles since their IDs need to be updated. Normally they are
+			// updated automatically upon deserialization but since we store them in intermediate form we need to manually
+			// deserialize and reserialize them in order to update their IDs.
+			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
+
+			Stack<SPtr<PrefabObjectDiff>> todo;
+
+			if (prefabDiff->mRoot != nullptr)
+				todo.push(prefabDiff->mRoot);
+
+			UnorderedSet<SPtr<SerializedObject>> handleObjects;
+
+			while (!todo.empty())
+			{
+				SPtr<PrefabObjectDiff> current = todo.top();
+				todo.pop();
+
+				for (auto& component : current->addedComponents)
+					findGameObjectHandles(component, handleObjects);
+
+				for (auto& child : current->addedChildren)
+					findGameObjectHandles(child, handleObjects);
+
+				for (auto& component : current->componentDiffs)
+					findGameObjectHandles(component->data, handleObjects);
+
+				for (auto& child : current->childDiffs)
+					todo.push(child);
+			}
+
+			Vector<SerializedHandle> handleData(handleObjects.size());
+
+			UINT32 idx = 0;
+			BinarySerializer bs;
+			for (auto& handleObject : handleObjects)
+			{
+				SerializedHandle& handle = handleData[idx];
+
+				handle.object = handleObject;
+				handle.handle = std::static_pointer_cast<GameObjectHandleBase>(bs._decodeIntermediate(handleObject));
+
+				idx++;
+			}
+
+			prefabDiff->mRTTIData = handleData;
+		}
+
+		/**
+		 * Decodes GameObjectHandles from their binary format, because during deserialization GameObjectManager will update
+		 * all object IDs and we want to keep the handles up to date.So we deserialize them and allow them to be updated
+		 * before storing them back into binary format.
+		 */
+		static void delayedOnDeserializationEnded(PrefabDiff* prefabDiff)
+		{
+			Vector<SerializedHandle>& handleData = any_cast_ref<Vector<SerializedHandle>>(prefabDiff->mRTTIData);
+
+			BinarySerializer bs;
+			for (auto& serializedHandle : handleData)
+			{
+				if (serializedHandle.handle != nullptr)
+					*serializedHandle.object = *bs._encodeIntermediate(serializedHandle.handle.get());
+			}
+
+			prefabDiff->mRTTIData = nullptr;
+		}
+
+		/**	Scans the entire hierarchy and find all serialized GameObjectHandle objects. */
+		static void findGameObjectHandles(const SPtr<SerializedObject>& serializedObject, UnorderedSet<SPtr<SerializedObject>>& handleObjects)
+		{
+			for (auto& subObject : serializedObject->subObjects)
+			{
+				RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
+				if (rtti == nullptr)
+					continue;
+
+				if (rtti->getRTTIId() == TID_GameObjectHandleBase)
+				{
+					handleObjects.insert(serializedObject);
+					return;
+				}
+
+				for (auto& child : subObject.entries)
+				{
+					RTTIField* curGenericField = rtti->findField(child.second.fieldId);
+					if (curGenericField == nullptr)
+						continue;
+
+					SPtr<SerializedInstance> entryData = child.second.serialized;
+					if (entryData == nullptr)
+						continue;
+
+					if (rtti_is_of_type<SerializedArray>(entryData))
+					{
+						SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
+						
+						for (auto& arrayElem : arrayData->entries)
+						{
+							if (arrayElem.second.serialized != nullptr && rtti_is_of_type<SerializedObject>(arrayElem.second.serialized))
+							{
+								SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
+								findGameObjectHandles(arrayElemData, handleObjects);
+							}
+						}
+					}
+					else if(rtti_is_of_type<SerializedObject>(entryData))
+					{
+						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
+						findGameObjectHandles(fieldObjectData, handleObjects);
+					}
+				}
+			}
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "PrefabDiff";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_PrefabDiff;
+		}
+
+		std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<PrefabDiff>();
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 318 - 318
Source/BansheeCore/Include/BsResources.h

@@ -1,319 +1,319 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsModule.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Resources
-	 *  @{
-	 */
-
-	/**
-	 * Manager for dealing with all engine resources. It allows you to save new resources and load existing ones.
-	 *
-	 * @note	Sim thread only.
-	 */
-	class BS_CORE_EXPORT Resources : public Module<Resources>
-	{
-		struct LoadedResourceData
-		{
-			LoadedResourceData()
-				:numInternalRefs(0)
-			{ }
-
-			LoadedResourceData(const WeakResourceHandle<Resource>& resource)
-				:resource(resource), numInternalRefs(0)
-			{ }
-
-			WeakResourceHandle<Resource> resource;
-			UINT32 numInternalRefs;
-		};
-
-		struct ResourceLoadData
-		{
-			ResourceLoadData(const WeakResourceHandle<Resource>& resource, UINT32 numDependencies)
-				:resData(resource), remainingDependencies(numDependencies)
-			{ }
-
-			LoadedResourceData resData;
-			ResourcePtr loadedData;
-			UINT32 remainingDependencies;
-			Vector<HResource> dependencies;
-			bool notifyImmediately;
-		};
-
-	public:
-		Resources();
-		~Resources();
-
-		/**
-		 * Loads the resource from a given path. Returns an empty handle if resource can't be loaded. Resource is loaded 
-		 * synchronously.
-		 *			
-		 * All loaded resources are reference counted and will be automatically unloaded when all of their references go out
-		 * of scope. 
-		 *			
-		 * @param[in]	filePath				File path to the resource to load. This can be absolute or relative to 
-		 *										the working folder.
-		 * @param[in]	loadDependencies		If true all resources referenced by the root resource will be loaded as well.
-		 * @param[in]	keepInternalReference	If true the resource system will keep an internal reference to the resource
-		 *										so it doesn't get destroyed with it goes out of scope. You can call 
-		 *										release() to release the internal reference. Each call to load will create
-		 *										a new internal reference and therefore must be followed by the same number
-		 *										of release calls. 
-		 *										If dependencies are being loaded, they will not have internal references 
-		 *										created regardless of this parameter.
-		 *			
-		 * @see		release(ResourceHandleBase&), unloadAllUnused()
-		 */
-		HResource load(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true);
-
-		/** @copydoc load(const Path&, bool) */
-		template <class T>
-		ResourceHandle<T> load(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true)
-		{
-			return static_resource_cast<T>(load(filePath, loadDependencies, keepInternalReference));
-		}
-
-		/**
-		 * Loads the resource for the provided weak resource handle, or returns a loaded resource if already loaded.
-		 * 			
-		 * @see		load(const Path&, bool)
-		 */
-		HResource load(const WeakResourceHandle<Resource>& handle, bool loadDependencies = true, bool keepInternalReference = true);
-
-		/** @copydoc load(const WeakResourceHandle<T>&, bool) */
-		template <class T>
-		ResourceHandle<T> load(const WeakResourceHandle<T>& handle, bool loadDependencies = true, bool keepInternalReference = true)
-		{
-			return static_resource_cast<T>(load((const WeakResourceHandle<Resource>&)handle, loadDependencies, keepInternalReference));
-		}
-
-		/**
-		 * Loads the resource asynchronously. Initially returned resource handle will be invalid until resource loading is 
-		 * done.
-		 *
-		 * @param[in]	filePath	Full pathname of the file.
-		 * 						
-		 * @note	
-		 * You can use returned invalid handle in many engine systems as the engine will check for handle validity before 
-		 * using it.
-		 *			
-		 * @see		load(const Path&, bool)
-		 */
-		HResource loadAsync(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true);
-
-		/** @copydoc loadAsync */
-		template <class T>
-		ResourceHandle<T> loadAsync(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true)
-		{
-			return static_resource_cast<T>(loadAsync(filePath, loadDependencies, keepInternalReference));
-		}
-
-		/**
-		 * Loads the resource with the given UUID. Returns an empty handle if resource can't be loaded.
-		 *
-		 * @param[in]	uuid					UUID of the resource to load.
-		 * @param[in]	async					If true resource will be loaded asynchronously. Handle to non-loaded
-		 *										resource will be returned immediately while loading will continue in the 
-		 *										background.		
-		 * @param[in]	loadDependencies		If true all resources referenced by the root resource will be loaded as well.
-		 * @param[in]	keepInternalReference	If true the resource system will keep an internal reference to the resource 
-		 *										so it doesn't get destroyed with it goes out of scope. You can call 
-		 *										release() to release the internal reference. Each call to load will create 
-		 *										a new internal reference and therefore must be followed by the same number 
-		 *										of release calls. 
-		 *										If dependencies are being loaded, they will not have internal references 
-		 *										created regardless of this parameter.	
-		 *													
-		 * @see		load(const Path&, bool)
-		 */
-		HResource loadFromUUID(const String& uuid, bool async = false, bool loadDependencies = true, bool keepInternalReference = true);
-
-		/**
-		 * Releases an internal reference to the resource held by the resources system. This allows the resource to be 
-		 * unloaded when it goes out of scope, if the resource was loaded with @p keepInternalReference parameter.
-		 *
-		 * Alternatively you can also skip manually calling release() and call ::unloadAllUnused which will unload all 
-		 * resources that do not have any external references, but you lose the fine grained control of what will be 
-		 * unloaded.
-		 *			
-		 * @param	resourceHandle	Handle of the resource to release.
-		 */
-		void release(ResourceHandleBase& resource);
-
-		/**
-		 * Finds all resources that aren't being referenced outside of the resources system and unloads them.
-		 * 			
-		 * @see		release(ResourceHandleBase&)
-		 */
-		void unloadAllUnused();
-
-		/**
-		 * Saves the resource at the specified location.
-		 *
-		 * @param[in]	resource 	Handle to the resource.
-		 * @param[in]	filePath 	Full pathname of the file to save as.
-		 * @param[in]	overwrite	(optional) If true, any existing resource at the specified location will be overwritten.
-		 * 			
-		 * @note
-		 * If the resource is a GpuResource and you are in some way modifying it from the core thread, make sure all those
-		 * commands are submitted before you call this method. Otherwise an obsolete version of the resource might get saved.
-		 * @note
-		 * If saving a core thread resource this is a potentially very slow operation as we must wait on the core thread 
-		 * and the GPU in order to read the resource.
-		 */
-		void save(const HResource& resource, const Path& filePath, bool overwrite);
-
-		/**
-		 * @brief	Saves an existing resource to its previous location.
-		 *
-		 * @param	resource 	Handle to the resource.
-		 *
-		 * @note	
-		 * If the resource is a GpuResource and you are in some way modifying it from the Core thread, make sure all those
-		 * commands are submitted before you call this method. Otherwise an obsolete version of the resource might get saved.
-		 * @note
-		 * If saving a core thread resource this is a potentially very slow operation as we must wait on the core thread 
-		 * and the GPU in order to read the resource.
-		 */
-		void save(const HResource& resource);
-
-		/**
-		 * Updates an existing resource handle with a new resource. Caller must ensure that new resource type matches the 
-		 * original resource type.
-		 */
-		void update(HResource& handle, const ResourcePtr& resource);
-
-		/**
-		 * Returns a list of dependencies from the resources at the specified path. Resource will not be loaded or parsed, 
-		 * but instead the saved list of dependencies will be read from the file and returned.
-		 *
-		 * @param[in]	filePath	Full path to the resource to get dependencies for.
-		 * @return					List of dependencies represented as UUIDs.
-		 */
-		Vector<String> getDependencies(const Path& filePath);
-
-		/**
-		 * Checks is the resource with the specified UUID loaded.
-		 *
-		 * @param[in]	uuid			UUID of the resource to check.
-		 * @param[in]	checkInProgress	Should this method also check resources that are in progress of being 
-		 *								asynchronously loaded.					
-		 * @return						True if loaded or loading in progress, false otherwise.
-		 */
-		bool isLoaded(const String& uuid, bool checkInProgress = true);
-
-		/**
-		 *Allows you to set a resource manifest containing UUID <-> file path mapping that is used when resolving 
-		 * resource references.
-		 *
-		 * @note	
-		 * If you want objects that reference resources (using ResourceHandles) to be able to find that resource even after
-		 * application restart, then you must save the resource manifest before closing the application and restore it 
-		 * upon startup. Otherwise resources will be assigned brand new UUIDs and references will be broken.
-		 */
-		void registerResourceManifest(const ResourceManifestPtr& manifest);
-
-		/**	Unregisters a resource manifest previously registered with registerResourceManifest(). */
-		void unregisterResourceManifest(const ResourceManifestPtr& manifest);
-
-		/**
-		 * Allows you to retrieve resource manifest containing UUID <-> file path mapping that is used when resolving 
-		 * resource references.
-		 * 			
-		 * @note	
-		 * Resources module internally holds a "Default" manifest that it automatically updated whenever a resource is saved.
-		 *
-		 * @see		registerResourceManifest
-		 */
-		ResourceManifestPtr getResourceManifest(const String& name) const;
-
-		/** Attempts to retrieve file path from the provided UUID. Returns true if successful, false otherwise. */
-		bool getFilePathFromUUID(const String& uuid, Path& filePath) const;
-
-		/** Attempts to retrieve UUID from the provided file path. Returns true if successful, false otherwise. */
-		bool getUUIDFromFilePath(const Path& path, String& uuid) const;
-
-		/**
-		 * Called when the resource has been successfully loaded. 
-		 *
-		 * @note	
-		 * It is undefined from which thread this will get called from. Most definitely not the sim thread if resource was
-		 * being loaded asynchronously.
-		 */
-		Event<void(const HResource&)> onResourceLoaded;
-
-		/**
-		 * Called when the resource has been destroyed. Provides UUID of the destroyed resource.
-		 *
-		 * @note	It is undefined from which thread this will get called from.
-		 */
-		Event<void(const String&)> onResourceDestroyed;
-
-		/**
-		 * Called when the internal resource the handle is pointing to has changed.
-		 *
-		 * @note	It is undefined from which thread this will get called from.
-		 */
-		Event<void(const HResource&)> onResourceModified;
-
-	public: // ***** INTERNAL ******
-		/** @cond INTERNAL */
-
-		/**
-		 * Creates a new resource handle from a resource pointer. 
-		 *
-		 * @note	Internal method used primarily be resource factory methods.
-		 */
-		HResource _createResourceHandle(const ResourcePtr& obj);
-
-		/** Returns an existing handle for the specified UUID if one exists, or creates a new one. */
-		HResource _getResourceHandle(const String& uuid);
-
-		/** @endcond */
-	private:
-		friend class ResourceHandleBase;
-
-		/**
-		 * Starts resource loading or returns an already loaded resource. Both UUID and filePath must match the	same 
-		 * resource, although you may provide an empty path in which case the resource will be retrieved from memory if its
-		 * currently loaded.
-		 * 			
-		 * @param[in]	incrementRef	Determines should the internal reference count be incremented.
-		 */
-		HResource loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool incrementRef);
-
-		/** Performs actually reading and deserializing of the resource file. Called from various worker threads. */
-		ResourcePtr loadFromDiskAndDeserialize(const Path& filePath);
-
-		/**	Triggered when individual resource has finished loading. */
-		void loadComplete(HResource& resource);
-
-		/**	Callback triggered when the task manager is ready to process the loading task. */
-		void loadCallback(const Path& filePath, HResource& resource);
-
-		/**	Destroys a resource, freeing its memory. */
-		void destroy(ResourceHandleBase& resource);
-
-	private:
-		Vector<ResourceManifestPtr> mResourceManifests;
-		ResourceManifestPtr mDefaultResourceManifest;
-
-		BS_MUTEX(mInProgressResourcesMutex);
-		BS_MUTEX(mLoadedResourceMutex);
-
-		UnorderedMap<String, WeakResourceHandle<Resource>> mHandles;
-		UnorderedMap<String, LoadedResourceData> mLoadedResources;
-		UnorderedMap<String, ResourceLoadData*> mInProgressResources; // Resources that are being asynchronously loaded
-		UnorderedMap<String, Vector<ResourceLoadData*>> mDependantLoads; // Allows dependency to be notified when a dependant is loaded
-	};
-
-	/** Provides easier access to Resources manager. */
-	BS_CORE_EXPORT Resources& gResources();
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Resources
+	 *  @{
+	 */
+
+	/**
+	 * Manager for dealing with all engine resources. It allows you to save new resources and load existing ones.
+	 *
+	 * @note	Sim thread only.
+	 */
+	class BS_CORE_EXPORT Resources : public Module<Resources>
+	{
+		struct LoadedResourceData
+		{
+			LoadedResourceData()
+				:numInternalRefs(0)
+			{ }
+
+			LoadedResourceData(const WeakResourceHandle<Resource>& resource)
+				:resource(resource), numInternalRefs(0)
+			{ }
+
+			WeakResourceHandle<Resource> resource;
+			UINT32 numInternalRefs;
+		};
+
+		struct ResourceLoadData
+		{
+			ResourceLoadData(const WeakResourceHandle<Resource>& resource, UINT32 numDependencies)
+				:resData(resource), remainingDependencies(numDependencies)
+			{ }
+
+			LoadedResourceData resData;
+			ResourcePtr loadedData;
+			UINT32 remainingDependencies;
+			Vector<HResource> dependencies;
+			bool notifyImmediately;
+		};
+
+	public:
+		Resources();
+		~Resources();
+
+		/**
+		 * Loads the resource from a given path. Returns an empty handle if resource can't be loaded. Resource is loaded 
+		 * synchronously.
+		 *			
+		 * All loaded resources are reference counted and will be automatically unloaded when all of their references go out
+		 * of scope. 
+		 *			
+		 * @param[in]	filePath				File path to the resource to load. This can be absolute or relative to 
+		 *										the working folder.
+		 * @param[in]	loadDependencies		If true all resources referenced by the root resource will be loaded as well.
+		 * @param[in]	keepInternalReference	If true the resource system will keep an internal reference to the resource
+		 *										so it doesn't get destroyed with it goes out of scope. You can call 
+		 *										release() to release the internal reference. Each call to load will create
+		 *										a new internal reference and therefore must be followed by the same number
+		 *										of release calls. 
+		 *										If dependencies are being loaded, they will not have internal references 
+		 *										created regardless of this parameter.
+		 *			
+		 * @see		release(ResourceHandleBase&), unloadAllUnused()
+		 */
+		HResource load(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true);
+
+		/** @copydoc load(const Path&, bool) */
+		template <class T>
+		ResourceHandle<T> load(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true)
+		{
+			return static_resource_cast<T>(load(filePath, loadDependencies, keepInternalReference));
+		}
+
+		/**
+		 * Loads the resource for the provided weak resource handle, or returns a loaded resource if already loaded.
+		 * 			
+		 * @see		load(const Path&, bool)
+		 */
+		HResource load(const WeakResourceHandle<Resource>& handle, bool loadDependencies = true, bool keepInternalReference = true);
+
+		/** @copydoc load(const WeakResourceHandle<T>&, bool) */
+		template <class T>
+		ResourceHandle<T> load(const WeakResourceHandle<T>& handle, bool loadDependencies = true, bool keepInternalReference = true)
+		{
+			return static_resource_cast<T>(load((const WeakResourceHandle<Resource>&)handle, loadDependencies, keepInternalReference));
+		}
+
+		/**
+		 * Loads the resource asynchronously. Initially returned resource handle will be invalid until resource loading is 
+		 * done.
+		 *
+		 * @param[in]	filePath	Full pathname of the file.
+		 * 						
+		 * @note	
+		 * You can use returned invalid handle in many engine systems as the engine will check for handle validity before 
+		 * using it.
+		 *			
+		 * @see		load(const Path&, bool)
+		 */
+		HResource loadAsync(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true);
+
+		/** @copydoc loadAsync */
+		template <class T>
+		ResourceHandle<T> loadAsync(const Path& filePath, bool loadDependencies = true, bool keepInternalReference = true)
+		{
+			return static_resource_cast<T>(loadAsync(filePath, loadDependencies, keepInternalReference));
+		}
+
+		/**
+		 * Loads the resource with the given UUID. Returns an empty handle if resource can't be loaded.
+		 *
+		 * @param[in]	uuid					UUID of the resource to load.
+		 * @param[in]	async					If true resource will be loaded asynchronously. Handle to non-loaded
+		 *										resource will be returned immediately while loading will continue in the 
+		 *										background.		
+		 * @param[in]	loadDependencies		If true all resources referenced by the root resource will be loaded as well.
+		 * @param[in]	keepInternalReference	If true the resource system will keep an internal reference to the resource 
+		 *										so it doesn't get destroyed with it goes out of scope. You can call 
+		 *										release() to release the internal reference. Each call to load will create 
+		 *										a new internal reference and therefore must be followed by the same number 
+		 *										of release calls. 
+		 *										If dependencies are being loaded, they will not have internal references 
+		 *										created regardless of this parameter.	
+		 *													
+		 * @see		load(const Path&, bool)
+		 */
+		HResource loadFromUUID(const String& uuid, bool async = false, bool loadDependencies = true, bool keepInternalReference = true);
+
+		/**
+		 * Releases an internal reference to the resource held by the resources system. This allows the resource to be 
+		 * unloaded when it goes out of scope, if the resource was loaded with @p keepInternalReference parameter.
+		 *
+		 * Alternatively you can also skip manually calling release() and call ::unloadAllUnused which will unload all 
+		 * resources that do not have any external references, but you lose the fine grained control of what will be 
+		 * unloaded.
+		 *			
+		 * @param[in]	resourceHandle	Handle of the resource to release.
+		 */
+		void release(ResourceHandleBase& resource);
+
+		/**
+		 * Finds all resources that aren't being referenced outside of the resources system and unloads them.
+		 * 			
+		 * @see		release(ResourceHandleBase&)
+		 */
+		void unloadAllUnused();
+
+		/**
+		 * Saves the resource at the specified location.
+		 *
+		 * @param[in]	resource 	Handle to the resource.
+		 * @param[in]	filePath 	Full pathname of the file to save as.
+		 * @param[in]	overwrite	(optional) If true, any existing resource at the specified location will be overwritten.
+		 * 			
+		 * @note
+		 * If the resource is a GpuResource and you are in some way modifying it from the core thread, make sure all those
+		 * commands are submitted before you call this method. Otherwise an obsolete version of the resource might get saved.
+		 * @note
+		 * If saving a core thread resource this is a potentially very slow operation as we must wait on the core thread 
+		 * and the GPU in order to read the resource.
+		 */
+		void save(const HResource& resource, const Path& filePath, bool overwrite);
+
+		/**
+		 * Saves an existing resource to its previous location.
+		 *
+		 * @param[in]	resource 	Handle to the resource.
+		 *
+		 * @note	
+		 * If the resource is a GpuResource and you are in some way modifying it from the Core thread, make sure all those
+		 * commands are submitted before you call this method. Otherwise an obsolete version of the resource might get saved.
+		 * @note
+		 * If saving a core thread resource this is a potentially very slow operation as we must wait on the core thread 
+		 * and the GPU in order to read the resource.
+		 */
+		void save(const HResource& resource);
+
+		/**
+		 * Updates an existing resource handle with a new resource. Caller must ensure that new resource type matches the 
+		 * original resource type.
+		 */
+		void update(HResource& handle, const ResourcePtr& resource);
+
+		/**
+		 * Returns a list of dependencies from the resources at the specified path. Resource will not be loaded or parsed, 
+		 * but instead the saved list of dependencies will be read from the file and returned.
+		 *
+		 * @param[in]	filePath	Full path to the resource to get dependencies for.
+		 * @return					List of dependencies represented as UUIDs.
+		 */
+		Vector<String> getDependencies(const Path& filePath);
+
+		/**
+		 * Checks is the resource with the specified UUID loaded.
+		 *
+		 * @param[in]	uuid			UUID of the resource to check.
+		 * @param[in]	checkInProgress	Should this method also check resources that are in progress of being 
+		 *								asynchronously loaded.					
+		 * @return						True if loaded or loading in progress, false otherwise.
+		 */
+		bool isLoaded(const String& uuid, bool checkInProgress = true);
+
+		/**
+		 *Allows you to set a resource manifest containing UUID <-> file path mapping that is used when resolving 
+		 * resource references.
+		 *
+		 * @note	
+		 * If you want objects that reference resources (using ResourceHandles) to be able to find that resource even after
+		 * application restart, then you must save the resource manifest before closing the application and restore it 
+		 * upon startup. Otherwise resources will be assigned brand new UUIDs and references will be broken.
+		 */
+		void registerResourceManifest(const ResourceManifestPtr& manifest);
+
+		/**	Unregisters a resource manifest previously registered with registerResourceManifest(). */
+		void unregisterResourceManifest(const ResourceManifestPtr& manifest);
+
+		/**
+		 * Allows you to retrieve resource manifest containing UUID <-> file path mapping that is used when resolving 
+		 * resource references.
+		 * 			
+		 * @note	
+		 * Resources module internally holds a "Default" manifest that it automatically updated whenever a resource is saved.
+		 *
+		 * @see		registerResourceManifest
+		 */
+		ResourceManifestPtr getResourceManifest(const String& name) const;
+
+		/** Attempts to retrieve file path from the provided UUID. Returns true if successful, false otherwise. */
+		bool getFilePathFromUUID(const String& uuid, Path& filePath) const;
+
+		/** Attempts to retrieve UUID from the provided file path. Returns true if successful, false otherwise. */
+		bool getUUIDFromFilePath(const Path& path, String& uuid) const;
+
+		/**
+		 * Called when the resource has been successfully loaded. 
+		 *
+		 * @note	
+		 * It is undefined from which thread this will get called from. Most definitely not the sim thread if resource was
+		 * being loaded asynchronously.
+		 */
+		Event<void(const HResource&)> onResourceLoaded;
+
+		/**
+		 * Called when the resource has been destroyed. Provides UUID of the destroyed resource.
+		 *
+		 * @note	It is undefined from which thread this will get called from.
+		 */
+		Event<void(const String&)> onResourceDestroyed;
+
+		/**
+		 * Called when the internal resource the handle is pointing to has changed.
+		 *
+		 * @note	It is undefined from which thread this will get called from.
+		 */
+		Event<void(const HResource&)> onResourceModified;
+
+	public: // ***** INTERNAL ******
+		/** @cond INTERNAL */
+
+		/**
+		 * Creates a new resource handle from a resource pointer. 
+		 *
+		 * @note	Internal method used primarily be resource factory methods.
+		 */
+		HResource _createResourceHandle(const ResourcePtr& obj);
+
+		/** Returns an existing handle for the specified UUID if one exists, or creates a new one. */
+		HResource _getResourceHandle(const String& uuid);
+
+		/** @endcond */
+	private:
+		friend class ResourceHandleBase;
+
+		/**
+		 * Starts resource loading or returns an already loaded resource. Both UUID and filePath must match the	same 
+		 * resource, although you may provide an empty path in which case the resource will be retrieved from memory if its
+		 * currently loaded.
+		 * 			
+		 * @param[in]	incrementRef	Determines should the internal reference count be incremented.
+		 */
+		HResource loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool incrementRef);
+
+		/** Performs actually reading and deserializing of the resource file. Called from various worker threads. */
+		ResourcePtr loadFromDiskAndDeserialize(const Path& filePath);
+
+		/**	Triggered when individual resource has finished loading. */
+		void loadComplete(HResource& resource);
+
+		/**	Callback triggered when the task manager is ready to process the loading task. */
+		void loadCallback(const Path& filePath, HResource& resource);
+
+		/**	Destroys a resource, freeing its memory. */
+		void destroy(ResourceHandleBase& resource);
+
+	private:
+		Vector<ResourceManifestPtr> mResourceManifests;
+		ResourceManifestPtr mDefaultResourceManifest;
+
+		BS_MUTEX(mInProgressResourcesMutex);
+		BS_MUTEX(mLoadedResourceMutex);
+
+		UnorderedMap<String, WeakResourceHandle<Resource>> mHandles;
+		UnorderedMap<String, LoadedResourceData> mLoadedResources;
+		UnorderedMap<String, ResourceLoadData*> mInProgressResources; // Resources that are being asynchronously loaded
+		UnorderedMap<String, Vector<ResourceLoadData*>> mDependantLoads; // Allows dependency to be notified when a dependant is loaded
+	};
+
+	/** Provides easier access to Resources manager. */
+	BS_CORE_EXPORT Resources& gResources();
+
+	/** @} */
 }

+ 131 - 135
Source/BansheeCore/Include/BsTechnique.h

@@ -1,136 +1,132 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsIReflectable.h"
-#include "BsCoreObject.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Implementation
-	 *  @{
-	 */
-
-	/**
-	 * Technique represents a specific implementation of a shader. Contains a number of passes that will be executed when 
-	 * rendering objects using this technique.
-	 *
-	 * @note	
-	 * Normally you want to have a separate technique for every render system and renderer your application supports. 
-	 * For example, if you are supporting DirectX11 and OpenGL you will want to have two techniques, one using HLSL based 
-	 * GPU programs, other using GLSL. Those techniques should try to mirror each others end results.
-	 */
-	class BS_CORE_EXPORT TechniqueBase
-	{
-	public:
-		TechniqueBase(const StringID& renderAPI, const StringID& renderer);
-		virtual ~TechniqueBase() { }
-
-		/**
-		 * @brief	Checks if this technique is supported based on current
-		 *			render and other systems.
-		 */
-		bool isSupported() const;
-
-	protected:
-		StringID mRenderAPI;
-		StringID mRenderer;
-	};
-
-	/**
-	 * @copydoc	TechniqueBase
-	 *
-	 * @note	Templated version that is used for implementing 
-	 *			both sim and core versions of Technique.
-	 */
-	template<bool Core>
-	class BS_CORE_EXPORT TTechnique : public TechniqueBase
-	{
-	public:
-		template<bool Core> struct TPassType { };
-		template<> struct TPassType < false > { typedef Pass Type; };
-		template<> struct TPassType < true > { typedef PassCore Type; };
-
-		typedef typename TPassType<Core>::Type PassType;
-		
-		TTechnique();
-		TTechnique(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<PassType>>& passes);
-		virtual ~TTechnique() { }
-
-		/**	Returns a pass with the specified index. */
-		SPtr<PassType> getPass(UINT32 idx) const;
-
-		/**	Returns total number of passes. */
-		UINT32 getNumPasses() const { return (UINT32)mPasses.size(); }
-
-	protected:
-		Vector<SPtr<PassType>> mPasses;
-	};
-
-	/** @} */
-
-	/** @addtogroup Material
-	 *  @{
-	 */
-
-	/** @cond INTERNAL */
-
-	/**
-	 * @copydoc	TechniqueBase
-	 *
-	 * @note	Core thread.
-	 */
-	class BS_CORE_EXPORT TechniqueCore : public CoreObjectCore, public TTechnique<true>
-	{
-	public:
-		TechniqueCore(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<PassCore>>& passes);
-
-		/** Creates a new technique. */
-		static SPtr<TechniqueCore> create(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<PassCore>>& passes);
-	};
-
-	/** @endcond */
-
-	/**
-	 * @copydoc	TechniqueBase
-	 *
-	 * @note	Sim thread.
-	 */
-	class BS_CORE_EXPORT Technique : public IReflectable, public CoreObject, public TTechnique<false>
-	{
-	public:
-		Technique(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<Pass>>& passes);
-
-		/** Retrieves an implementation of a technique usable only from the core thread. */
-		SPtr<TechniqueCore> getCore() const;
-
-		/** Creates a new technique. */
-		static TechniquePtr create(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<Pass>>& passes);
-
-	protected:
-		/** @copydoc CoreObject::createCore */
-		SPtr<CoreObjectCore> createCore() const override;
-
-		/** @copydoc CoreObject::getCoreDependencies */
-		void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
-
-		/**	Creates a new technique but doesn't initialize it. */
-		static TechniquePtr createEmpty();
-
-	private:
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-		
-		/** Serialization only constructor. */
-		Technique();
-
-	public:
-		friend class TechniqueRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;	
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsIReflectable.h"
+#include "BsCoreObject.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Implementation
+	 *  @{
+	 */
+
+	/**
+	 * Technique represents a specific implementation of a shader. Contains a number of passes that will be executed when 
+	 * rendering objects using this technique.
+	 *
+	 * @note	
+	 * Normally you want to have a separate technique for every render system and renderer your application supports. 
+	 * For example, if you are supporting DirectX11 and OpenGL you will want to have two techniques, one using HLSL based 
+	 * GPU programs, other using GLSL. Those techniques should try to mirror each others end results.
+	 */
+	class BS_CORE_EXPORT TechniqueBase
+	{
+	public:
+		TechniqueBase(const StringID& renderAPI, const StringID& renderer);
+		virtual ~TechniqueBase() { }
+
+		/**	Checks if this technique is supported based on current render and other systems. */
+		bool isSupported() const;
+
+	protected:
+		StringID mRenderAPI;
+		StringID mRenderer;
+	};
+
+	/**
+	 * @copydoc	TechniqueBase
+	 *
+	 * @note	Templated version that is used for implementing both sim and core versions of Technique.
+	 */
+	template<bool Core>
+	class BS_CORE_EXPORT TTechnique : public TechniqueBase
+	{
+	public:
+		template<bool Core> struct TPassType { };
+		template<> struct TPassType < false > { typedef Pass Type; };
+		template<> struct TPassType < true > { typedef PassCore Type; };
+
+		typedef typename TPassType<Core>::Type PassType;
+		
+		TTechnique();
+		TTechnique(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<PassType>>& passes);
+		virtual ~TTechnique() { }
+
+		/**	Returns a pass with the specified index. */
+		SPtr<PassType> getPass(UINT32 idx) const;
+
+		/**	Returns total number of passes. */
+		UINT32 getNumPasses() const { return (UINT32)mPasses.size(); }
+
+	protected:
+		Vector<SPtr<PassType>> mPasses;
+	};
+
+	/** @} */
+
+	/** @addtogroup Material
+	 *  @{
+	 */
+
+	/** @cond INTERNAL */
+
+	/**
+	 * @copydoc	TechniqueBase
+	 *
+	 * @note	Core thread.
+	 */
+	class BS_CORE_EXPORT TechniqueCore : public CoreObjectCore, public TTechnique<true>
+	{
+	public:
+		TechniqueCore(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<PassCore>>& passes);
+
+		/** Creates a new technique. */
+		static SPtr<TechniqueCore> create(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<PassCore>>& passes);
+	};
+
+	/** @endcond */
+
+	/**
+	 * @copydoc	TechniqueBase
+	 *
+	 * @note	Sim thread.
+	 */
+	class BS_CORE_EXPORT Technique : public IReflectable, public CoreObject, public TTechnique<false>
+	{
+	public:
+		Technique(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<Pass>>& passes);
+
+		/** Retrieves an implementation of a technique usable only from the core thread. */
+		SPtr<TechniqueCore> getCore() const;
+
+		/** Creates a new technique. */
+		static TechniquePtr create(const StringID& renderAPI, const StringID& renderer, const Vector<SPtr<Pass>>& passes);
+
+	protected:
+		/** @copydoc CoreObject::createCore */
+		SPtr<CoreObjectCore> createCore() const override;
+
+		/** @copydoc CoreObject::getCoreDependencies */
+		void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
+
+		/**	Creates a new technique but doesn't initialize it. */
+		static TechniquePtr createEmpty();
+
+	private:
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+		
+		/** Serialization only constructor. */
+		Technique();
+
+	public:
+		friend class TechniqueRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;	
+	};
+
+	/** @} */
 }

+ 376 - 380
Source/BansheeCore/Include/BsTextData.h

@@ -1,381 +1,377 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsFontDesc.h"
-#include "BsVector2I.h"
-
-namespace BansheeEngine
-{
-	/** @cond INTERNAL */
-	/** @addtogroup Implementation
-	 *  @{
-	 */
-
-	/**
-	 * This object takes as input a string, a font and optionally some constraints (like word wrap) and outputs a set of 
-	 * character data you may use for rendering or metrics.
-	 */
-	class TextDataBase
-	{
-	protected:
-		/**
-		 * Represents a single word as a set of characters, or optionally just a blank space of a certain length.
-		 *
-		 * @note	Due to the way allocation is handled, this class is not allowed to have a destructor.
-		 */
-		class TextWord
-		{
-		public:
-			/**
-			 * @brief	Initializes the word and signals if it just a space (or multiple spaces), or 
-			 *			an actual word with letters.
-			 */
-			void init(bool spacer);
-
-			/**
-			 * Appends a new character to the word.
-			 *
-			 * @param[in]	charIdx		Sequential index of the character in the original string.
-			 * @param[in]	desc		Character description from the font.
-			 * @return					How many pixels did the added character expand the word by.
-			 */
-			UINT32 addChar(UINT32 charIdx, const CHAR_DESC& desc);
-
-			/** Adds a space to the word. Word must have previously have been declared as a "spacer". */
-			void addSpace(UINT32 spaceWidth);
-
-			/**	Returns the width of the word in pixels. */
-			UINT32 getWidth() const { return mWidth; }
-
-			/**
-			 * @brief	Returns height of the word in pixels.
-			 */
-			UINT32 getHeight() const { return mHeight; }
-
-			/**
-			 * Calculates new width of the word if we were to add the provided character, without actually adding it.
-			 *
-			 * @param[in]	desc	Character description from the font.
-			 * @return				Width of the word in pixels with the character appended to it.
-			 */
-			UINT32 calcWidthWithChar(const CHAR_DESC& desc);
-
-			/**
-			 * @brief	Returns true if word is a spacer. Spacers contain just a space 
-			 *			of a certain length with no actual characters.
-			 */
-			bool isSpacer() const { return mSpacer; }
-
-			/**	Returns the number of characters in the word. */
-			UINT32 getNumChars() const { return mLastChar == nullptr ? 0 : (mCharsEnd - mCharsStart + 1); }
-
-			/**	Returns the index of the starting character in the word. */
-			UINT32 getCharsStart() const { return mCharsStart; }
-
-			/**	Returns the index of the last character in the word. */
-			UINT32 getCharsEnd() const { return mCharsEnd; }
-
-			/**
-			 * Calculates width of the character by which it would expand the width of the word if it was added to it.
-			 *
-			 * @param[in]	prevDesc	Descriptor of the character preceding the one we need the width for. Can be null.
-			 * @param[in]	desc		Character description from the font.
-			 * @return 					How many pixels would the added character expand the word by.
-			 */
-			static UINT32 calcCharWidth(const CHAR_DESC* prevDesc, const CHAR_DESC& desc);
-
-		private:
-			UINT32 mCharsStart, mCharsEnd;
-			UINT32 mWidth;
-			UINT32 mHeight;
-
-			const CHAR_DESC* mLastChar;
-
-			bool mSpacer;
-			UINT32 mSpaceWidth;
-		};
-
-		/**
-		 * Contains information about a single texture page that contains rendered character data.
-		 *
-		 * @note	Due to the way allocation is handled, this class is not allowed to have a destructor.
-		 */
-		struct PageInfo
-		{
-			UINT32 numQuads;
-			HTexture texture;
-		};
-
-	public:
-		/**
-		 * Represents a single line as a set of words.
-		 *
-		 * @note	Due to the way allocation is handled, this class is not allowed to have a destructor.
-		 */
-		class BS_CORE_EXPORT TextLine
-		{
-		public:
-			/**	Returns width of the line in pixels. */
-			UINT32 getWidth() const { return mWidth; }
-
-			/**	Returns height of the line in pixels. */
-			UINT32 getHeight() const { return mHeight; }
-
-			/**	Returns an offset used to separate two lines. */
-			UINT32 getYOffset() const { return mTextData->getLineHeight(); }
-
-			/**
-			 * Calculates new width of the line if we were to add the provided character, without actually adding it.
-			 *
-			 * @param[in]	desc	Character description from the font.
-			 * @return				Width of the line in pixels with the character appended to it.
-			 */
-			UINT32 calcWidthWithChar(const CHAR_DESC& desc);
-
-			/**
-			 * Fills the vertex/uv/index buffers for the specified page, with all the character data needed for rendering.
-			 *
-			 * @param[in]	page		The page.
-			 * @param[out]	vertices	Pre-allocated array where character vertices will be written.
-			 * @param[out]	uvs			Pre-allocated array where character uv coordinates will be written.
-			 * @param[out]	indexes 	Pre-allocated array where character indices will be written.
-			 * @param[in]	offset		Offsets the location at which the method writes to the buffers. Counted as number 
-			 *							of quads.
-			 * @param[in]	size		Total number of quads that can fit into the specified buffers.
-			 * @return					Number of quads that were written.
-			 */
-			UINT32 fillBuffer(UINT32 page, Vector2* vertices, Vector2* uvs, UINT32* indexes, UINT32 offset, UINT32 size) const;
-
-			/**	Checks are we at a word boundary (i.e. next added character will start a new word). */
-			bool isAtWordBoundary() const;
-
-			/**	Returns the total number of characters on this line. */
-			UINT32 getNumChars() const;
-
-			/**
-			 * Query if this line was created explicitly due to a newline character. As opposed to a line that was created
-			 * because a word couldn't fit on the previous line.
-			 */
-			bool hasNewlineChar() const { return mHasNewline; }
-		private:
-			friend class TextDataBase;
-
-			/**
-			 * Appends a new character to the line.
-			 *
-			 * @param[in]	charIdx		Sequential index of the character in the original string.
-			 * @param[in]	desc		Character description from the font.
-			 */
-			void add(UINT32 charIdx, const CHAR_DESC& charDesc);
-
-			/**	Appends a space to the line. */
-			void addSpace(UINT32 spaceWidth);
-
-			/**
-			 * Adds a new word to the line.
-			 *
-			 * @param[in]	wordIdx		Sequential index of the word in the original string. Spaces are counted as words as
-			 *							well.
-			 * @param[in]	word		Description of the word.
-			 */
-			void addWord(UINT32 wordIdx, const TextWord& word);
-
-			/** Initializes the line. Must be called after construction. */
-			void init(TextDataBase* textData);
-
-			/**
-			 * Finalizes the line. Do not add new characters/words after a line has been finalized.
-			 *
-			 * @param[in]	hasNewlineChar	Set to true if line was create due to an explicit newline char. As opposed to a
-			 *								line that was created because a word couldn't fit on the previous line.
-			 */
-			void finalize(bool hasNewlineChar);
-
-			/**	Returns true if the line contains no words. */
-			bool isEmpty() const { return mIsEmpty; }
-
-			/**	Removes last word from the line and returns its sequential index. */
-			UINT32 removeLastWord();
-
-			/**	Calculates the line width and height in pixels. */
-			void calculateBounds();
-
-		private:
-			TextDataBase* mTextData;
-			UINT32 mWordsStart, mWordsEnd;
-
-			UINT32 mWidth;
-			UINT32 mHeight;
-
-			bool mIsEmpty;
-			bool mHasNewline;
-		};
-
-	public:
-		/**
-		 * Initializes a new text data using the specified string and font. Text will attempt to fit into the provided area.
-		 * If enabled it will wrap words to new line when they don't fit. Individual words will be broken into multiple 
-		 * pieces if they don't fit on a single line when word break is enabled, otherwise they will be clipped. If the 
-		 * specified area is zero size then the text will not be clipped or word wrapped in any way.
-		 *
-		 * After this object is constructed you may call various getter methods to get needed information.
-		 */
-		BS_CORE_EXPORT TextDataBase(const WString& text, const HFont& font, UINT32 fontSize,
-			UINT32 width = 0, UINT32 height = 0, bool wordWrap = false, bool wordBreak = true);
-		BS_CORE_EXPORT virtual ~TextDataBase() { }
-
-		/**	Returns the number of lines that were generated. */
-		BS_CORE_EXPORT UINT32 getNumLines() const { return mNumLines; }
-
-		/**	Returns the number of font pages references by the used characters. */
-		BS_CORE_EXPORT UINT32 getNumPages() const { return mNumPageInfos; }
-
-		/**	Returns the height of a line in pixels. */
-		BS_CORE_EXPORT UINT32 getLineHeight() const;
-
-		/**	Gets information describing a single line at the specified index. */
-		BS_CORE_EXPORT const TextLine& getLine(UINT32 idx) const { return mLines[idx]; }
-
-		/**	Returns font texture for the provided page index.  */
-		BS_CORE_EXPORT const HTexture& getTextureForPage(UINT32 page) const;
-
-		/**	Returns the number of quads used by all the characters in the provided page. */
-		BS_CORE_EXPORT UINT32 getNumQuadsForPage(UINT32 page) const { return mPageInfos[page].numQuads; }
-
-		/**	Returns the width of the actual text in pixels. */
-		BS_CORE_EXPORT UINT32 getWidth() const;
-
-		/**	Returns the height of the actual text in pixels. */
-		BS_CORE_EXPORT UINT32 getHeight() const;
-
-	protected:
-		/**
-		 * Copies internally stored data in temporary buffers to a persistent buffer.
-		 *
-		 * @param[in]	text			Text originally used for creating the internal temporary buffer data.
-		 * @param[in]	buffer			Memory location to copy the data to. If null then no data will be copied and the
-		 *								parameter @p size will contain the required buffer size.
-		 * @param[in]	size			Size of the provided memory buffer, or if the buffer is null, this will contain the 
-		 *								required buffer size after method exists.
-		 * @param[in]	freeTemporary	If true the internal temporary data will be freed after copying.
-		 *
-		 * @note	Must be called after text data has been constructed and is in the temporary buffers.
-		 */
-		BS_CORE_EXPORT void generatePersistentData(const WString& text, UINT8* buffer, UINT32& size, bool freeTemporary = true);
-	private:
-		friend class TextLine;
-
-		/**	Returns Y offset that determines the line on which the characters are placed. In pixels. */
-		INT32 getBaselineOffset() const;
-
-		/**	Returns the width of a single space in pixels. */
-		UINT32 getSpaceWidth() const;
-
-		/** Gets a description of a single character referenced by its sequential index based on the original string. */
-		const CHAR_DESC& getChar(UINT32 idx) const { return *mChars[idx]; }
-
-		/** Gets a description of a single word referenced by its sequential index based on the original string. */
-		const TextWord& getWord(UINT32 idx) const { return mWords[idx]; }
-
-	protected:
-		const CHAR_DESC** mChars;
-		UINT32 mNumChars;
-
-		TextWord* mWords;
-		UINT32 mNumWords;
-
-		TextLine* mLines;
-		UINT32 mNumLines;
-
-		PageInfo* mPageInfos;
-		UINT32 mNumPageInfos;
-
-		HFont mFont;
-		SPtr<const FontBitmap> mFontData;
-
-		// Static buffers used to reduce runtime memory allocation
-	protected:
-		/** Stores per-thread memory buffers used to reduce memory allocation. */
-		// Note: I could replace this with the global frame allocator to avoid the extra logic
-		struct BufferData
-		{
-			BufferData();
-			~BufferData();
-
-			/**
-			 * Allocates a new word and adds it to the buffer. Returns index of the word in the word buffer.
-			 *
-			 * @param[in]	spacer	Specify true if the word is only to contain spaces. (Spaces are considered a special 
-			 *						type of word).
-			 */
-			UINT32 allocWord(bool spacer);
-
-			/** Allocates a new line and adds it to the buffer. Returns index of the line in the line buffer. */
-			UINT32 allocLine(TextDataBase* textData);
-
-			/**
-			 * Increments the count of characters for the referenced page, and optionally creates page info if it doesn't
-			 * already exist.
-			 */
-			void addCharToPage(UINT32 page, const FontBitmap& fontData);
-
-			/**	Resets all allocation counters, but doesn't actually release memory. */
-			void deallocAll();
-
-			TextWord* WordBuffer;
-			UINT32 WordBufferSize;
-			UINT32 NextFreeWord;
-
-			TextLine* LineBuffer;
-			UINT32 LineBufferSize;
-			UINT32 NextFreeLine;
-
-			PageInfo* PageBuffer;
-			UINT32 PageBufferSize;
-			UINT32 NextFreePageInfo;
-		};
-
-		static BS_THREADLOCAL BufferData* MemBuffer;
-
-		/**	Allocates an initial set of buffers that will be reused while parsing text data. */
-		static void initAlloc();
-	};
-
-	/** @} */
-
-	/** @addtogroup Text
-	 *  @{
-	 */
-
-	/** @copydoc TextDataBase */
-	template<class Alloc = GenAlloc>
-	class TextData : public TextDataBase
-	{
-	public:
-		/** @copydoc TextDataBase::TextDataBase */
-		TextData(const WString& text, const HFont& font, UINT32 fontSize,
-			UINT32 width = 0, UINT32 height = 0, bool wordWrap = false, bool wordBreak = true)
-			:TextDataBase(text, font, fontSize, width, height, wordWrap, wordBreak), mData(nullptr)
-		{
-			UINT32 totalBufferSize = 0;
-			generatePersistentData(text, nullptr, totalBufferSize);
-
-			mData = (UINT8*)bs_alloc<Alloc>(totalBufferSize);
-			generatePersistentData(text, (UINT8*)mData, totalBufferSize);
-		}
-
-		~TextData()
-		{
-			if (mData != nullptr)
-				bs_free<Alloc>(mData);
-		}
-
-	private:
-		UINT8* mData;
-	};
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsFontDesc.h"
+#include "BsVector2I.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Implementation
+	 *  @{
+	 */
+
+	/**
+	 * This object takes as input a string, a font and optionally some constraints (like word wrap) and outputs a set of 
+	 * character data you may use for rendering or metrics.
+	 */
+	class TextDataBase
+	{
+	protected:
+		/**
+		 * Represents a single word as a set of characters, or optionally just a blank space of a certain length.
+		 *
+		 * @note	Due to the way allocation is handled, this class is not allowed to have a destructor.
+		 */
+		class TextWord
+		{
+		public:
+			/**
+			 * Initializes the word and signals if it just a space (or multiple spaces), or an actual word with letters.
+			 */
+			void init(bool spacer);
+
+			/**
+			 * Appends a new character to the word.
+			 *
+			 * @param[in]	charIdx		Sequential index of the character in the original string.
+			 * @param[in]	desc		Character description from the font.
+			 * @return					How many pixels did the added character expand the word by.
+			 */
+			UINT32 addChar(UINT32 charIdx, const CHAR_DESC& desc);
+
+			/** Adds a space to the word. Word must have previously have been declared as a "spacer". */
+			void addSpace(UINT32 spaceWidth);
+
+			/**	Returns the width of the word in pixels. */
+			UINT32 getWidth() const { return mWidth; }
+
+			/**	Returns height of the word in pixels. */
+			UINT32 getHeight() const { return mHeight; }
+
+			/**
+			 * Calculates new width of the word if we were to add the provided character, without actually adding it.
+			 *
+			 * @param[in]	desc	Character description from the font.
+			 * @return				Width of the word in pixels with the character appended to it.
+			 */
+			UINT32 calcWidthWithChar(const CHAR_DESC& desc);
+
+			/**
+			 * Returns true if word is a spacer. Spacers contain just a space of a certain length with no actual characters.
+			 */
+			bool isSpacer() const { return mSpacer; }
+
+			/**	Returns the number of characters in the word. */
+			UINT32 getNumChars() const { return mLastChar == nullptr ? 0 : (mCharsEnd - mCharsStart + 1); }
+
+			/**	Returns the index of the starting character in the word. */
+			UINT32 getCharsStart() const { return mCharsStart; }
+
+			/**	Returns the index of the last character in the word. */
+			UINT32 getCharsEnd() const { return mCharsEnd; }
+
+			/**
+			 * Calculates width of the character by which it would expand the width of the word if it was added to it.
+			 *
+			 * @param[in]	prevDesc	Descriptor of the character preceding the one we need the width for. Can be null.
+			 * @param[in]	desc		Character description from the font.
+			 * @return 					How many pixels would the added character expand the word by.
+			 */
+			static UINT32 calcCharWidth(const CHAR_DESC* prevDesc, const CHAR_DESC& desc);
+
+		private:
+			UINT32 mCharsStart, mCharsEnd;
+			UINT32 mWidth;
+			UINT32 mHeight;
+
+			const CHAR_DESC* mLastChar;
+
+			bool mSpacer;
+			UINT32 mSpaceWidth;
+		};
+
+		/**
+		 * Contains information about a single texture page that contains rendered character data.
+		 *
+		 * @note	Due to the way allocation is handled, this class is not allowed to have a destructor.
+		 */
+		struct PageInfo
+		{
+			UINT32 numQuads;
+			HTexture texture;
+		};
+
+	public:
+		/**
+		 * Represents a single line as a set of words.
+		 *
+		 * @note	Due to the way allocation is handled, this class is not allowed to have a destructor.
+		 */
+		class BS_CORE_EXPORT TextLine
+		{
+		public:
+			/**	Returns width of the line in pixels. */
+			UINT32 getWidth() const { return mWidth; }
+
+			/**	Returns height of the line in pixels. */
+			UINT32 getHeight() const { return mHeight; }
+
+			/**	Returns an offset used to separate two lines. */
+			UINT32 getYOffset() const { return mTextData->getLineHeight(); }
+
+			/**
+			 * Calculates new width of the line if we were to add the provided character, without actually adding it.
+			 *
+			 * @param[in]	desc	Character description from the font.
+			 * @return				Width of the line in pixels with the character appended to it.
+			 */
+			UINT32 calcWidthWithChar(const CHAR_DESC& desc);
+
+			/**
+			 * Fills the vertex/uv/index buffers for the specified page, with all the character data needed for rendering.
+			 *
+			 * @param[in]	page		The page.
+			 * @param[out]	vertices	Pre-allocated array where character vertices will be written.
+			 * @param[out]	uvs			Pre-allocated array where character uv coordinates will be written.
+			 * @param[out]	indexes 	Pre-allocated array where character indices will be written.
+			 * @param[in]	offset		Offsets the location at which the method writes to the buffers. Counted as number 
+			 *							of quads.
+			 * @param[in]	size		Total number of quads that can fit into the specified buffers.
+			 * @return					Number of quads that were written.
+			 */
+			UINT32 fillBuffer(UINT32 page, Vector2* vertices, Vector2* uvs, UINT32* indexes, UINT32 offset, UINT32 size) const;
+
+			/**	Checks are we at a word boundary (i.e. next added character will start a new word). */
+			bool isAtWordBoundary() const;
+
+			/**	Returns the total number of characters on this line. */
+			UINT32 getNumChars() const;
+
+			/**
+			 * Query if this line was created explicitly due to a newline character. As opposed to a line that was created
+			 * because a word couldn't fit on the previous line.
+			 */
+			bool hasNewlineChar() const { return mHasNewline; }
+		private:
+			friend class TextDataBase;
+
+			/**
+			 * Appends a new character to the line.
+			 *
+			 * @param[in]	charIdx		Sequential index of the character in the original string.
+			 * @param[in]	desc		Character description from the font.
+			 */
+			void add(UINT32 charIdx, const CHAR_DESC& charDesc);
+
+			/**	Appends a space to the line. */
+			void addSpace(UINT32 spaceWidth);
+
+			/**
+			 * Adds a new word to the line.
+			 *
+			 * @param[in]	wordIdx		Sequential index of the word in the original string. Spaces are counted as words as
+			 *							well.
+			 * @param[in]	word		Description of the word.
+			 */
+			void addWord(UINT32 wordIdx, const TextWord& word);
+
+			/** Initializes the line. Must be called after construction. */
+			void init(TextDataBase* textData);
+
+			/**
+			 * Finalizes the line. Do not add new characters/words after a line has been finalized.
+			 *
+			 * @param[in]	hasNewlineChar	Set to true if line was create due to an explicit newline char. As opposed to a
+			 *								line that was created because a word couldn't fit on the previous line.
+			 */
+			void finalize(bool hasNewlineChar);
+
+			/**	Returns true if the line contains no words. */
+			bool isEmpty() const { return mIsEmpty; }
+
+			/**	Removes last word from the line and returns its sequential index. */
+			UINT32 removeLastWord();
+
+			/**	Calculates the line width and height in pixels. */
+			void calculateBounds();
+
+		private:
+			TextDataBase* mTextData;
+			UINT32 mWordsStart, mWordsEnd;
+
+			UINT32 mWidth;
+			UINT32 mHeight;
+
+			bool mIsEmpty;
+			bool mHasNewline;
+		};
+
+	public:
+		/**
+		 * Initializes a new text data using the specified string and font. Text will attempt to fit into the provided area.
+		 * If enabled it will wrap words to new line when they don't fit. Individual words will be broken into multiple 
+		 * pieces if they don't fit on a single line when word break is enabled, otherwise they will be clipped. If the 
+		 * specified area is zero size then the text will not be clipped or word wrapped in any way.
+		 *
+		 * After this object is constructed you may call various getter methods to get needed information.
+		 */
+		BS_CORE_EXPORT TextDataBase(const WString& text, const HFont& font, UINT32 fontSize,
+			UINT32 width = 0, UINT32 height = 0, bool wordWrap = false, bool wordBreak = true);
+		BS_CORE_EXPORT virtual ~TextDataBase() { }
+
+		/**	Returns the number of lines that were generated. */
+		BS_CORE_EXPORT UINT32 getNumLines() const { return mNumLines; }
+
+		/**	Returns the number of font pages references by the used characters. */
+		BS_CORE_EXPORT UINT32 getNumPages() const { return mNumPageInfos; }
+
+		/**	Returns the height of a line in pixels. */
+		BS_CORE_EXPORT UINT32 getLineHeight() const;
+
+		/**	Gets information describing a single line at the specified index. */
+		BS_CORE_EXPORT const TextLine& getLine(UINT32 idx) const { return mLines[idx]; }
+
+		/**	Returns font texture for the provided page index.  */
+		BS_CORE_EXPORT const HTexture& getTextureForPage(UINT32 page) const;
+
+		/**	Returns the number of quads used by all the characters in the provided page. */
+		BS_CORE_EXPORT UINT32 getNumQuadsForPage(UINT32 page) const { return mPageInfos[page].numQuads; }
+
+		/**	Returns the width of the actual text in pixels. */
+		BS_CORE_EXPORT UINT32 getWidth() const;
+
+		/**	Returns the height of the actual text in pixels. */
+		BS_CORE_EXPORT UINT32 getHeight() const;
+
+	protected:
+		/**
+		 * Copies internally stored data in temporary buffers to a persistent buffer.
+		 *
+		 * @param[in]	text			Text originally used for creating the internal temporary buffer data.
+		 * @param[in]	buffer			Memory location to copy the data to. If null then no data will be copied and the
+		 *								parameter @p size will contain the required buffer size.
+		 * @param[in]	size			Size of the provided memory buffer, or if the buffer is null, this will contain the 
+		 *								required buffer size after method exists.
+		 * @param[in]	freeTemporary	If true the internal temporary data will be freed after copying.
+		 *
+		 * @note	Must be called after text data has been constructed and is in the temporary buffers.
+		 */
+		BS_CORE_EXPORT void generatePersistentData(const WString& text, UINT8* buffer, UINT32& size, bool freeTemporary = true);
+	private:
+		friend class TextLine;
+
+		/**	Returns Y offset that determines the line on which the characters are placed. In pixels. */
+		INT32 getBaselineOffset() const;
+
+		/**	Returns the width of a single space in pixels. */
+		UINT32 getSpaceWidth() const;
+
+		/** Gets a description of a single character referenced by its sequential index based on the original string. */
+		const CHAR_DESC& getChar(UINT32 idx) const { return *mChars[idx]; }
+
+		/** Gets a description of a single word referenced by its sequential index based on the original string. */
+		const TextWord& getWord(UINT32 idx) const { return mWords[idx]; }
+
+	protected:
+		const CHAR_DESC** mChars;
+		UINT32 mNumChars;
+
+		TextWord* mWords;
+		UINT32 mNumWords;
+
+		TextLine* mLines;
+		UINT32 mNumLines;
+
+		PageInfo* mPageInfos;
+		UINT32 mNumPageInfos;
+
+		HFont mFont;
+		SPtr<const FontBitmap> mFontData;
+
+		// Static buffers used to reduce runtime memory allocation
+	protected:
+		/** Stores per-thread memory buffers used to reduce memory allocation. */
+		// Note: I could replace this with the global frame allocator to avoid the extra logic
+		struct BufferData
+		{
+			BufferData();
+			~BufferData();
+
+			/**
+			 * Allocates a new word and adds it to the buffer. Returns index of the word in the word buffer.
+			 *
+			 * @param[in]	spacer	Specify true if the word is only to contain spaces. (Spaces are considered a special 
+			 *						type of word).
+			 */
+			UINT32 allocWord(bool spacer);
+
+			/** Allocates a new line and adds it to the buffer. Returns index of the line in the line buffer. */
+			UINT32 allocLine(TextDataBase* textData);
+
+			/**
+			 * Increments the count of characters for the referenced page, and optionally creates page info if it doesn't
+			 * already exist.
+			 */
+			void addCharToPage(UINT32 page, const FontBitmap& fontData);
+
+			/**	Resets all allocation counters, but doesn't actually release memory. */
+			void deallocAll();
+
+			TextWord* WordBuffer;
+			UINT32 WordBufferSize;
+			UINT32 NextFreeWord;
+
+			TextLine* LineBuffer;
+			UINT32 LineBufferSize;
+			UINT32 NextFreeLine;
+
+			PageInfo* PageBuffer;
+			UINT32 PageBufferSize;
+			UINT32 NextFreePageInfo;
+		};
+
+		static BS_THREADLOCAL BufferData* MemBuffer;
+
+		/**	Allocates an initial set of buffers that will be reused while parsing text data. */
+		static void initAlloc();
+	};
+
+	/** @} */
+
+	/** @addtogroup Text
+	 *  @{
+	 */
+
+	/** @copydoc TextDataBase */
+	template<class Alloc = GenAlloc>
+	class TextData : public TextDataBase
+	{
+	public:
+		/** @copydoc TextDataBase::TextDataBase */
+		TextData(const WString& text, const HFont& font, UINT32 fontSize,
+			UINT32 width = 0, UINT32 height = 0, bool wordWrap = false, bool wordBreak = true)
+			:TextDataBase(text, font, fontSize, width, height, wordWrap, wordBreak), mData(nullptr)
+		{
+			UINT32 totalBufferSize = 0;
+			generatePersistentData(text, nullptr, totalBufferSize);
+
+			mData = (UINT8*)bs_alloc<Alloc>(totalBufferSize);
+			generatePersistentData(text, (UINT8*)mData, totalBufferSize);
+		}
+
+		~TextData()
+		{
+			if (mData != nullptr)
+				bs_free<Alloc>(mData);
+		}
+
+	private:
+		UINT8* mData;
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 139 - 144
Source/BansheeCore/Source/BsGpuProgramManager.cpp

@@ -1,144 +1,139 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsGpuProgramManager.h"
-#include "BsRenderAPI.h"
-
-namespace BansheeEngine 
-{
-	String sNullLang = "null";
-
-	/**
-	 * @brief	Null GPU program used in place of GPU programs we cannot create.
-	 *			Null programs don't do anything.
-	 */
-	class NullProgramCore : public GpuProgramCore
-	{
-	public:
-		NullProgramCore()
-			:GpuProgramCore("", "", GPT_VERTEX_PROGRAM, GPP_NONE, nullptr)
-		{ }
-
-		~NullProgramCore() { }
-
-		bool isSupported() const { return false; }
-		const String& getLanguage() const { return sNullLang; }
-
-	protected:
-		void loadFromSource() {}
-
-		void buildConstantDefinitions() const { }
-	};
-
-	/**
-	 * @brief	Factory that creates null GPU programs. 
-	 */
-	class NullProgramFactory : public GpuProgramFactory
-	{
-	public:
-		NullProgramFactory() {}
-		~NullProgramFactory() {}
-
-		const String& getLanguage() const override
-		{ 
-			return sNullLang;
-		}
-
-		SPtr<GpuProgramCore> create(const String& source, const String& entryPoint, GpuProgramType gptype, 
-			GpuProgramProfile profile, bool requiresAdjacencyInformation) override
-		{
-			SPtr<NullProgramCore> ret = bs_shared_ptr_new<NullProgramCore>();
-			ret->_setThisPtr(ret);
-
-			return ret;
-		}
-
-		SPtr<GpuProgramCore> create(GpuProgramType type) override
-		{
-			SPtr<NullProgramCore> ret = bs_shared_ptr_new<NullProgramCore>();
-			ret->_setThisPtr(ret);
-
-			return ret;
-		}
-	};
-
-	GpuProgramPtr GpuProgramManager::create(const String& source, const String& entryPoint, const String& language,
-		GpuProgramType gptype, GpuProgramProfile profile,
-		bool requiresAdjacencyInformation)
-	{
-		GpuProgram* program = new (bs_alloc<GpuProgram>()) GpuProgram(source, entryPoint, language, gptype, profile, requiresAdjacencyInformation);
-		GpuProgramPtr ret = bs_core_ptr<GpuProgram>(program);
-		ret->_setThisPtr(ret);
-		ret->initialize();
-
-		return ret;
-	}
-
-	GpuProgramPtr GpuProgramManager::createEmpty(const String& language, GpuProgramType type)
-	{
-		GpuProgram* program = new (bs_alloc<GpuProgram>()) GpuProgram("", "", language, GPT_VERTEX_PROGRAM, GPP_VS_1_1, false);
-		GpuProgramPtr ret = bs_core_ptr<GpuProgram>(program);
-		ret->_setThisPtr(ret);
-
-		return ret;
-	}
-
-	GpuProgramCoreManager::GpuProgramCoreManager()
-	{
-		mNullFactory = bs_new<NullProgramFactory>();
-		addFactory(mNullFactory);
-	}
-
-	GpuProgramCoreManager::~GpuProgramCoreManager()
-	{
-		bs_delete((NullProgramFactory*)mNullFactory);
-	}
-
-	void GpuProgramCoreManager::addFactory(GpuProgramFactory* factory)
-	{
-		mFactories[factory->getLanguage()] = factory;
-	}
-
-	void GpuProgramCoreManager::removeFactory(GpuProgramFactory* factory)
-    {
-        FactoryMap::iterator it = mFactories.find(factory->getLanguage());
-        if (it != mFactories.end() && it->second == factory)
-        {
-            mFactories.erase(it);
-        }
-    }
-
-	GpuProgramFactory* GpuProgramCoreManager::getFactory(const String& language)
-	{
-		FactoryMap::iterator i = mFactories.find(language);
-
-		if (i == mFactories.end())
-			i = mFactories.find(sNullLang);
-
-		return i->second;
-	}
-
-	bool GpuProgramCoreManager::isLanguageSupported(const String& lang)
-	{
-		FactoryMap::iterator i = mFactories.find(lang);
-
-		return i != mFactories.end();
-	}
-
-	SPtr<GpuProgramCore> GpuProgramCoreManager::create(const String& source, const String& entryPoint, const String& language,
-		GpuProgramType gptype, GpuProgramProfile profile, bool requiresAdjacencyInformation)
-    {
-		SPtr<GpuProgramCore> ret = createInternal(source, entryPoint, language, gptype, profile, requiresAdjacencyInformation);
-		ret->initialize();
-
-        return ret;
-    }
-
-	SPtr<GpuProgramCore> GpuProgramCoreManager::createInternal(const String& source, const String& entryPoint, const String& language,
-		GpuProgramType gptype, GpuProgramProfile profile, bool requiresAdjacencyInformation)
-	{
-		GpuProgramFactory* factory = getFactory(language);
-		SPtr<GpuProgramCore> ret = factory->create(source, entryPoint, gptype, profile, requiresAdjacencyInformation);
-
-		return ret;
-	}
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsGpuProgramManager.h"
+#include "BsRenderAPI.h"
+
+namespace BansheeEngine 
+{
+	String sNullLang = "null";
+
+	/** Null GPU program used in place of GPU programs we cannot create. Null programs don't do anything. */
+	class NullProgramCore : public GpuProgramCore
+	{
+	public:
+		NullProgramCore()
+			:GpuProgramCore("", "", GPT_VERTEX_PROGRAM, GPP_NONE, nullptr)
+		{ }
+
+		~NullProgramCore() { }
+
+		bool isSupported() const { return false; }
+		const String& getLanguage() const { return sNullLang; }
+
+	protected:
+		void loadFromSource() {}
+
+		void buildConstantDefinitions() const { }
+	};
+
+	/**	Factory that creates null GPU programs.  */
+	class NullProgramFactory : public GpuProgramFactory
+	{
+	public:
+		NullProgramFactory() {}
+		~NullProgramFactory() {}
+
+		const String& getLanguage() const override
+		{ 
+			return sNullLang;
+		}
+
+		SPtr<GpuProgramCore> create(const String& source, const String& entryPoint, GpuProgramType gptype, 
+			GpuProgramProfile profile, bool requiresAdjacencyInformation) override
+		{
+			SPtr<NullProgramCore> ret = bs_shared_ptr_new<NullProgramCore>();
+			ret->_setThisPtr(ret);
+
+			return ret;
+		}
+
+		SPtr<GpuProgramCore> create(GpuProgramType type) override
+		{
+			SPtr<NullProgramCore> ret = bs_shared_ptr_new<NullProgramCore>();
+			ret->_setThisPtr(ret);
+
+			return ret;
+		}
+	};
+
+	GpuProgramPtr GpuProgramManager::create(const String& source, const String& entryPoint, const String& language,
+		GpuProgramType gptype, GpuProgramProfile profile,
+		bool requiresAdjacencyInformation)
+	{
+		GpuProgram* program = new (bs_alloc<GpuProgram>()) GpuProgram(source, entryPoint, language, gptype, profile, requiresAdjacencyInformation);
+		GpuProgramPtr ret = bs_core_ptr<GpuProgram>(program);
+		ret->_setThisPtr(ret);
+		ret->initialize();
+
+		return ret;
+	}
+
+	GpuProgramPtr GpuProgramManager::createEmpty(const String& language, GpuProgramType type)
+	{
+		GpuProgram* program = new (bs_alloc<GpuProgram>()) GpuProgram("", "", language, GPT_VERTEX_PROGRAM, GPP_VS_1_1, false);
+		GpuProgramPtr ret = bs_core_ptr<GpuProgram>(program);
+		ret->_setThisPtr(ret);
+
+		return ret;
+	}
+
+	GpuProgramCoreManager::GpuProgramCoreManager()
+	{
+		mNullFactory = bs_new<NullProgramFactory>();
+		addFactory(mNullFactory);
+	}
+
+	GpuProgramCoreManager::~GpuProgramCoreManager()
+	{
+		bs_delete((NullProgramFactory*)mNullFactory);
+	}
+
+	void GpuProgramCoreManager::addFactory(GpuProgramFactory* factory)
+	{
+		mFactories[factory->getLanguage()] = factory;
+	}
+
+	void GpuProgramCoreManager::removeFactory(GpuProgramFactory* factory)
+    {
+        FactoryMap::iterator it = mFactories.find(factory->getLanguage());
+        if (it != mFactories.end() && it->second == factory)
+        {
+            mFactories.erase(it);
+        }
+    }
+
+	GpuProgramFactory* GpuProgramCoreManager::getFactory(const String& language)
+	{
+		FactoryMap::iterator i = mFactories.find(language);
+
+		if (i == mFactories.end())
+			i = mFactories.find(sNullLang);
+
+		return i->second;
+	}
+
+	bool GpuProgramCoreManager::isLanguageSupported(const String& lang)
+	{
+		FactoryMap::iterator i = mFactories.find(lang);
+
+		return i != mFactories.end();
+	}
+
+	SPtr<GpuProgramCore> GpuProgramCoreManager::create(const String& source, const String& entryPoint, const String& language,
+		GpuProgramType gptype, GpuProgramProfile profile, bool requiresAdjacencyInformation)
+    {
+		SPtr<GpuProgramCore> ret = createInternal(source, entryPoint, language, gptype, profile, requiresAdjacencyInformation);
+		ret->initialize();
+
+        return ret;
+    }
+
+	SPtr<GpuProgramCore> GpuProgramCoreManager::createInternal(const String& source, const String& entryPoint, const String& language,
+		GpuProgramType gptype, GpuProgramProfile profile, bool requiresAdjacencyInformation)
+	{
+		GpuProgramFactory* factory = getFactory(language);
+		SPtr<GpuProgramCore> ret = factory->create(source, entryPoint, gptype, profile, requiresAdjacencyInformation);
+
+		return ret;
+	}
+}

+ 381 - 402
Source/BansheeCore/Source/BsIconUtility.cpp

@@ -1,403 +1,382 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsIconUtility.h"
-#include "BsPixelData.h"
-#include "BsColor.h"
-#include "BsException.h"
-
-#define MSDOS_SIGNATURE 0x5A4D
-#define PE_SIGNATURE 0x00004550
-#define PE_32BIT_SIGNATURE 0x10B
-#define PE_64BIT_SIGNATURE 0x20B
-#define PE_NUM_DIRECTORY_ENTRIES 16
-#define PE_SECTION_UNINITIALIZED_DATA 0x00000080
-#define	PE_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
-#define PE_IMAGE_RT_ICON 3
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	MS-DOS header found at the beggining in a PE format file.
-	 */
-	struct MSDOSHeader
-	{
-		UINT16 signature;
-		UINT16 lastSize;
-		UINT16 numBlocks;
-		UINT16 numReloc;
-		UINT16 hdrSize;
-		UINT16 minAlloc;
-		UINT16 maxAlloc;
-		UINT16 ss;
-		UINT16 sp;
-		UINT16 checksum;
-		UINT16 ip;
-		UINT16 cs;
-		UINT16 relocPos;
-		UINT16 numOverlay;
-		UINT16 reserved1[4];
-		UINT16 oemId;
-		UINT16 oemInfo;
-		UINT16 reserved2[10];
-		UINT32 lfanew;
-	};
-
-	/**
-	 * @brief	COFF header found in a PE format file.
-	 */
-	struct COFFHeader
-	{
-		UINT16 machine;
-		UINT16 numSections;
-		UINT32 timeDateStamp;
-		UINT32 ptrSymbolTable;
-		UINT32 numSymbols;
-		UINT16 sizeOptHeader;
-		UINT16 characteristics;
-	};
-
-	/**
-	 * @brief	Contains address and size of data areas in a PE image.
-	 */
-	struct PEDataDirectory
-	{
-		UINT32 virtualAddress;
-		UINT32 size;
-	};
-
-	/**
-	 * @brief	Optional header in a 32-bit PE format file.
-	 */
-	struct PEOptionalHeader32
-	{
-		UINT16 signature;
-		UINT8 majorLinkerVersion;
-		UINT8 minorLinkerVersion;
-		UINT32 sizeCode;
-		UINT32 sizeInitializedData;
-		UINT32 sizeUninitializedData;
-		UINT32 addressEntryPoint;
-		UINT32 baseCode;
-		UINT32 baseData;
-		UINT32 baseImage;
-		UINT32 alignmentSection;
-		UINT32 alignmentFile;
-		UINT16 majorOSVersion;
-		UINT16 minorOSVersion;
-		UINT16 majorImageVersion;
-		UINT16 minorImageVersion;
-		UINT16 majorSubsystemVersion;
-		UINT16 minorSubsystemVersion;
-		UINT32 reserved;
-		UINT32 sizeImage;
-		UINT32 sizeHeaders;
-		UINT32 checksum;
-		UINT16 subsystem;
-		UINT16 characteristics;
-		UINT32 sizeStackReserve;
-		UINT32 sizeStackCommit;
-		UINT32 sizeHeapReserve;
-		UINT32 sizeHeapCommit;
-		UINT32 loaderFlags;
-		UINT32 NumRvaAndSizes;
-		PEDataDirectory dataDirectory[16];
-	};
-
-	/**
-	 * @brief	Optional header in a 64-bit PE format file.
-	 */
-	struct PEOptionalHeader64
-	{
-		UINT16 signature;
-		UINT8 majorLinkerVersion;
-		UINT8 minorLinkerVersion;
-		UINT32 sizeCode;
-		UINT32 sizeInitializedData;
-		UINT32 sizeUninitializedData;
-		UINT32 addressEntryPoint;
-		UINT32 baseCode;
-		UINT64 baseImage;
-		UINT32 alignmentSection;
-		UINT32 alignmentFile;
-		UINT16 majorOSVersion;
-		UINT16 minorOSVersion;
-		UINT16 majorImageVersion;
-		UINT16 minorImageVersion;
-		UINT16 majorSubsystemVersion;
-		UINT16 minorSubsystemVersion;
-		UINT32 reserved;
-		UINT32 sizeImage;
-		UINT32 sizeHeaders;
-		UINT32 checksum;
-		UINT16 subsystem;
-		UINT16 characteristics;
-		UINT64 sizeStackReserve;
-		UINT64 sizeStackCommit;
-		UINT64 sizeHeapReserve;
-		UINT64 sizeHeapCommit;
-		UINT32 loaderFlags;
-		UINT32 NumRvaAndSizes;
-		PEDataDirectory dataDirectory[16];
-	};
-
-	/**
-	 * @brief	A section header in a PE format file.
-	 */
-	struct PESectionHeader
-	{
-		char name[8];
-		UINT32 virtualSize;
-		UINT32 relativeVirtualAddress;
-		UINT32 physicalSize;
-		UINT32 physicalAddress;
-		UINT8 deprecated[12];
-		UINT32 flags;
-	};
-
-	/**
-	 * @brief	A resource table header within a .rsrc section in a PE format file.
-	 */
-	struct PEImageResourceDirectory
-	{
-		UINT32 flags;
-		UINT32 timeDateStamp;
-		UINT16 majorVersion;
-		UINT16 minorVersion;
-		UINT16 numNamedEntries;
-		UINT16 numIdEntries;
-	};
-
-	/**
-	 * @brief	A single entry in a resource table within a .rsrc section in a PE format file.
-	 */
-	struct PEImageResourceEntry
-	{
-		UINT32 type;
-		UINT32 offsetDirectory : 31;
-		UINT32 isDirectory : 1;
-	};
-
-	/**
-	 * @brief	An entry in a resource table referencing resource data. Found within a 
-	 * 			.rsrc section in a PE format file.
-	 */
-	struct PEImageResourceEntryData
-	{
-		UINT32 offsetData;
-		UINT32 size;
-		UINT32 codePage;
-		UINT32 resourceHandle;
-	};
-
-	/**
-	 * @brief	Header used in icon file format.
-	 */
-	struct IconHeader
-	{
-		UINT32 size;
-		INT32 width;
-		INT32 height;
-		UINT16 planes;
-		UINT16 bitCount;
-		UINT32 compression;
-		UINT32 sizeImage;
-		INT32 xPelsPerMeter;
-		INT32 yPelsPerMeter;
-		UINT32 clrUsed;
-		UINT32 clrImportant;
-	};
-
-	void IconUtility::updateIconExe(const Path& path, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
-	{
-		// A PE file is structured as such:
-		//  - MSDOS Header
-		//  - PE Signature
-		//  - COFF Header
-		//  - PE Optional Header
-		//  - One or multiple sections
-		//   - .code
-		//   - .data
-		//   - ...
-		//   - .rsrc
-		//    - icon/cursor/etc data
-
-		std::fstream stream;
-		stream.open(path.toString().c_str(), std::ios::in | std::ios::out | std::ios::binary);
-
-		// First check magic number to ensure file is even an executable
-		UINT16 magicNum;
-		stream.read((char*)&magicNum, sizeof(magicNum));
-		if (magicNum != MSDOS_SIGNATURE)
-			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
-
-		// Read the MSDOS header and skip over it
-		stream.seekg(0);
-
-		MSDOSHeader msdosHeader;
-		stream.read((char*)&msdosHeader, sizeof(MSDOSHeader));
-
-		// Read PE signature
-		stream.seekg(msdosHeader.lfanew);
-
-		UINT32 peSignature;
-		stream.read((char*)&peSignature, sizeof(peSignature));
-
-		if (peSignature != PE_SIGNATURE)
-			BS_EXCEPT(InvalidStateException, "Provided file is not in PE format.");
-
-		// Read COFF header
-		COFFHeader coffHeader;
-		stream.read((char*)&coffHeader, sizeof(COFFHeader));
-
-		if (coffHeader.sizeOptHeader == 0) // .exe files always have an optional header
-			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
-
-		UINT32 numSectionHeaders = coffHeader.numSections;
-
-		// Read optional header
-		auto optionalHeaderPos = stream.tellg();
-
-		UINT16 optionalHeaderSignature;
-		stream.read((char*)&optionalHeaderSignature, sizeof(optionalHeaderSignature));
-
-		PEDataDirectory* dataDirectory = nullptr;
-		stream.seekg(optionalHeaderPos);
-		if (optionalHeaderSignature == PE_32BIT_SIGNATURE)
-		{
-			PEOptionalHeader32 optionalHeader;
-			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
-
-			dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE;
-		}
-		else if (optionalHeaderSignature == PE_64BIT_SIGNATURE)
-		{
-			PEOptionalHeader64 optionalHeader;
-			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
-
-			dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE;
-		}
-		else
-			BS_EXCEPT(InvalidStateException, "Unrecognized PE format.");
-
-		// Read section headers
-		auto sectionHeaderPos = optionalHeaderPos + (std::ifstream::pos_type)coffHeader.sizeOptHeader;
-		stream.seekg(sectionHeaderPos);
-
-		PESectionHeader* sectionHeaders = bs_stack_alloc<PESectionHeader>(numSectionHeaders);
-		stream.read((char*)sectionHeaders, sizeof(PESectionHeader) * numSectionHeaders);
-
-		// Look for .rsrc section header
-		std::function<void(PEImageResourceDirectory*, PEImageResourceDirectory*, UINT8*, UINT32)> setIconData =
-			[&](PEImageResourceDirectory* base, PEImageResourceDirectory* current, UINT8* imageData, UINT32 sectionAddress)
-		{
-			UINT32 numEntries = current->numIdEntries; // Not supporting name entries
-			PEImageResourceEntry* entries = (PEImageResourceEntry*)(current + 1);
-
-			for (UINT32 i = 0; i < numEntries; i++)
-			{
-				// Only at root does the type identify resource type
-				if (base == current && entries[i].type != PE_IMAGE_RT_ICON)
-					continue;
-
-				if (entries[i].isDirectory)
-				{
-					PEImageResourceDirectory* child = (PEImageResourceDirectory*)(((UINT8*)base) + entries[i].offsetDirectory);
-					setIconData(base, child, imageData, sectionAddress);
-				}
-				else
-				{
-					PEImageResourceEntryData* data = (PEImageResourceEntryData*)(((UINT8*)base) + entries[i].offsetDirectory);
-
-					UINT8* iconData = imageData + (data->offsetData - sectionAddress);
-					updateIconData(iconData, pixelsPerSize);
-				}
-			}
-		};
-
-		for (UINT32 i = 0; i < numSectionHeaders; i++)
-		{
-			if (sectionHeaders[i].flags & PE_SECTION_UNINITIALIZED_DATA)
-				continue;
-
-			if (strcmp(sectionHeaders[i].name, ".rsrc") == 0)
-			{
-				UINT32 imageSize = sectionHeaders[i].physicalSize;
-				UINT8* imageData = (UINT8*)bs_stack_alloc(imageSize);
-
-				stream.seekg(sectionHeaders[i].physicalAddress);
-				stream.read((char*)imageData, imageSize);
-
-				UINT32 resourceDirOffset = dataDirectory->virtualAddress - sectionHeaders[i].relativeVirtualAddress;
-				PEImageResourceDirectory* resourceDirectory = (PEImageResourceDirectory*)&imageData[resourceDirOffset];
-
-				setIconData(resourceDirectory, resourceDirectory, imageData, sectionHeaders[i].relativeVirtualAddress);
-				stream.seekp(sectionHeaders[i].physicalAddress);
-				stream.write((char*)imageData, imageSize);
-
-				bs_stack_free(imageData);
-			}
-		}
-
-		bs_stack_free(sectionHeaders);
-		stream.close();
-	}
-
-	void IconUtility::updateIconData(UINT8* iconData, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
-	{
-		IconHeader* iconHeader = (IconHeader*)iconData;
-
-		if (iconHeader->size != sizeof(IconHeader) || iconHeader->compression != 0
-			|| iconHeader->planes != 1 || iconHeader->bitCount != 32)
-		{
-			// Unsupported format
-			return;
-		}
-
-		UINT8* iconPixels = iconData + sizeof(IconHeader);
-		UINT32 width = iconHeader->width;
-		UINT32 height = iconHeader->height / 2;
-
-		auto iterFind = pixelsPerSize.find(width);
-		if (iterFind == pixelsPerSize.end() || iterFind->second->getWidth() != width
-			|| iterFind->second->getHeight() != height)
-		{
-			// No icon of this size provided
-			return;
-		}
-
-		// Write colors
-		PixelDataPtr srcPixels = iterFind->second;
-		UINT32* colorData = (UINT32*)iconPixels;
-
-		UINT32 idx = 0;
-		for (INT32 y = (INT32)height - 1; y >= 0; y--)
-		{
-			for (UINT32 x = 0; x < width; x++)
-				colorData[idx++] = srcPixels->getColorAt(x, y).getAsBGRA();
-		}
-
-		// Write AND mask
-		UINT32 colorDataSize = width * height * sizeof(UINT32);
-		UINT8* maskData = iconPixels + colorDataSize;
-
-		UINT32 numPackedPixels = width / 8; // One per bit in byte
-
-		for (INT32 y = (INT32)height - 1; y >= 0; y--)
-		{
-			UINT8 mask = 0;
-			for (UINT32 packedX = 0; packedX < numPackedPixels; packedX++)
-			{
-				for (UINT32 pixelIdx = 0; pixelIdx < 8; pixelIdx++)
-				{
-					UINT32 x = packedX * 8 + pixelIdx;
-					Color color = srcPixels->getColorAt(x, y);
-					if (color.a < 0.25f)
-						mask |= 1 << (7 - pixelIdx);
-				}
-
-				*maskData = mask;
-				maskData++;
-			}
-		}
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsIconUtility.h"
+#include "BsPixelData.h"
+#include "BsColor.h"
+#include "BsException.h"
+
+#define MSDOS_SIGNATURE 0x5A4D
+#define PE_SIGNATURE 0x00004550
+#define PE_32BIT_SIGNATURE 0x10B
+#define PE_64BIT_SIGNATURE 0x20B
+#define PE_NUM_DIRECTORY_ENTRIES 16
+#define PE_SECTION_UNINITIALIZED_DATA 0x00000080
+#define	PE_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define PE_IMAGE_RT_ICON 3
+
+namespace BansheeEngine
+{
+	/**	MS-DOS header found at the beggining in a PE format file. */
+	struct MSDOSHeader
+	{
+		UINT16 signature;
+		UINT16 lastSize;
+		UINT16 numBlocks;
+		UINT16 numReloc;
+		UINT16 hdrSize;
+		UINT16 minAlloc;
+		UINT16 maxAlloc;
+		UINT16 ss;
+		UINT16 sp;
+		UINT16 checksum;
+		UINT16 ip;
+		UINT16 cs;
+		UINT16 relocPos;
+		UINT16 numOverlay;
+		UINT16 reserved1[4];
+		UINT16 oemId;
+		UINT16 oemInfo;
+		UINT16 reserved2[10];
+		UINT32 lfanew;
+	};
+
+	/**	COFF header found in a PE format file. */
+	struct COFFHeader
+	{
+		UINT16 machine;
+		UINT16 numSections;
+		UINT32 timeDateStamp;
+		UINT32 ptrSymbolTable;
+		UINT32 numSymbols;
+		UINT16 sizeOptHeader;
+		UINT16 characteristics;
+	};
+
+	/**	Contains address and size of data areas in a PE image. */
+	struct PEDataDirectory
+	{
+		UINT32 virtualAddress;
+		UINT32 size;
+	};
+
+	/**	Optional header in a 32-bit PE format file. */
+	struct PEOptionalHeader32
+	{
+		UINT16 signature;
+		UINT8 majorLinkerVersion;
+		UINT8 minorLinkerVersion;
+		UINT32 sizeCode;
+		UINT32 sizeInitializedData;
+		UINT32 sizeUninitializedData;
+		UINT32 addressEntryPoint;
+		UINT32 baseCode;
+		UINT32 baseData;
+		UINT32 baseImage;
+		UINT32 alignmentSection;
+		UINT32 alignmentFile;
+		UINT16 majorOSVersion;
+		UINT16 minorOSVersion;
+		UINT16 majorImageVersion;
+		UINT16 minorImageVersion;
+		UINT16 majorSubsystemVersion;
+		UINT16 minorSubsystemVersion;
+		UINT32 reserved;
+		UINT32 sizeImage;
+		UINT32 sizeHeaders;
+		UINT32 checksum;
+		UINT16 subsystem;
+		UINT16 characteristics;
+		UINT32 sizeStackReserve;
+		UINT32 sizeStackCommit;
+		UINT32 sizeHeapReserve;
+		UINT32 sizeHeapCommit;
+		UINT32 loaderFlags;
+		UINT32 NumRvaAndSizes;
+		PEDataDirectory dataDirectory[16];
+	};
+
+	/**	Optional header in a 64-bit PE format file. */
+	struct PEOptionalHeader64
+	{
+		UINT16 signature;
+		UINT8 majorLinkerVersion;
+		UINT8 minorLinkerVersion;
+		UINT32 sizeCode;
+		UINT32 sizeInitializedData;
+		UINT32 sizeUninitializedData;
+		UINT32 addressEntryPoint;
+		UINT32 baseCode;
+		UINT64 baseImage;
+		UINT32 alignmentSection;
+		UINT32 alignmentFile;
+		UINT16 majorOSVersion;
+		UINT16 minorOSVersion;
+		UINT16 majorImageVersion;
+		UINT16 minorImageVersion;
+		UINT16 majorSubsystemVersion;
+		UINT16 minorSubsystemVersion;
+		UINT32 reserved;
+		UINT32 sizeImage;
+		UINT32 sizeHeaders;
+		UINT32 checksum;
+		UINT16 subsystem;
+		UINT16 characteristics;
+		UINT64 sizeStackReserve;
+		UINT64 sizeStackCommit;
+		UINT64 sizeHeapReserve;
+		UINT64 sizeHeapCommit;
+		UINT32 loaderFlags;
+		UINT32 NumRvaAndSizes;
+		PEDataDirectory dataDirectory[16];
+	};
+
+	/**	A section header in a PE format file. */
+	struct PESectionHeader
+	{
+		char name[8];
+		UINT32 virtualSize;
+		UINT32 relativeVirtualAddress;
+		UINT32 physicalSize;
+		UINT32 physicalAddress;
+		UINT8 deprecated[12];
+		UINT32 flags;
+	};
+
+	/**	A resource table header within a .rsrc section in a PE format file. */
+	struct PEImageResourceDirectory
+	{
+		UINT32 flags;
+		UINT32 timeDateStamp;
+		UINT16 majorVersion;
+		UINT16 minorVersion;
+		UINT16 numNamedEntries;
+		UINT16 numIdEntries;
+	};
+
+	/**	A single entry in a resource table within a .rsrc section in a PE format file. */
+	struct PEImageResourceEntry
+	{
+		UINT32 type;
+		UINT32 offsetDirectory : 31;
+		UINT32 isDirectory : 1;
+	};
+
+	/** An entry in a resource table referencing resource data. Found within a .rsrc section in a PE format file. */
+	struct PEImageResourceEntryData
+	{
+		UINT32 offsetData;
+		UINT32 size;
+		UINT32 codePage;
+		UINT32 resourceHandle;
+	};
+
+	/**	Header used in icon file format. */
+	struct IconHeader
+	{
+		UINT32 size;
+		INT32 width;
+		INT32 height;
+		UINT16 planes;
+		UINT16 bitCount;
+		UINT32 compression;
+		UINT32 sizeImage;
+		INT32 xPelsPerMeter;
+		INT32 yPelsPerMeter;
+		UINT32 clrUsed;
+		UINT32 clrImportant;
+	};
+
+	void IconUtility::updateIconExe(const Path& path, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
+	{
+		// A PE file is structured as such:
+		//  - MSDOS Header
+		//  - PE Signature
+		//  - COFF Header
+		//  - PE Optional Header
+		//  - One or multiple sections
+		//   - .code
+		//   - .data
+		//   - ...
+		//   - .rsrc
+		//    - icon/cursor/etc data
+
+		std::fstream stream;
+		stream.open(path.toString().c_str(), std::ios::in | std::ios::out | std::ios::binary);
+
+		// First check magic number to ensure file is even an executable
+		UINT16 magicNum;
+		stream.read((char*)&magicNum, sizeof(magicNum));
+		if (magicNum != MSDOS_SIGNATURE)
+			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
+
+		// Read the MSDOS header and skip over it
+		stream.seekg(0);
+
+		MSDOSHeader msdosHeader;
+		stream.read((char*)&msdosHeader, sizeof(MSDOSHeader));
+
+		// Read PE signature
+		stream.seekg(msdosHeader.lfanew);
+
+		UINT32 peSignature;
+		stream.read((char*)&peSignature, sizeof(peSignature));
+
+		if (peSignature != PE_SIGNATURE)
+			BS_EXCEPT(InvalidStateException, "Provided file is not in PE format.");
+
+		// Read COFF header
+		COFFHeader coffHeader;
+		stream.read((char*)&coffHeader, sizeof(COFFHeader));
+
+		if (coffHeader.sizeOptHeader == 0) // .exe files always have an optional header
+			BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable.");
+
+		UINT32 numSectionHeaders = coffHeader.numSections;
+
+		// Read optional header
+		auto optionalHeaderPos = stream.tellg();
+
+		UINT16 optionalHeaderSignature;
+		stream.read((char*)&optionalHeaderSignature, sizeof(optionalHeaderSignature));
+
+		PEDataDirectory* dataDirectory = nullptr;
+		stream.seekg(optionalHeaderPos);
+		if (optionalHeaderSignature == PE_32BIT_SIGNATURE)
+		{
+			PEOptionalHeader32 optionalHeader;
+			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
+
+			dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE;
+		}
+		else if (optionalHeaderSignature == PE_64BIT_SIGNATURE)
+		{
+			PEOptionalHeader64 optionalHeader;
+			stream.read((char*)&optionalHeader, sizeof(optionalHeader));
+
+			dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE;
+		}
+		else
+			BS_EXCEPT(InvalidStateException, "Unrecognized PE format.");
+
+		// Read section headers
+		auto sectionHeaderPos = optionalHeaderPos + (std::ifstream::pos_type)coffHeader.sizeOptHeader;
+		stream.seekg(sectionHeaderPos);
+
+		PESectionHeader* sectionHeaders = bs_stack_alloc<PESectionHeader>(numSectionHeaders);
+		stream.read((char*)sectionHeaders, sizeof(PESectionHeader) * numSectionHeaders);
+
+		// Look for .rsrc section header
+		std::function<void(PEImageResourceDirectory*, PEImageResourceDirectory*, UINT8*, UINT32)> setIconData =
+			[&](PEImageResourceDirectory* base, PEImageResourceDirectory* current, UINT8* imageData, UINT32 sectionAddress)
+		{
+			UINT32 numEntries = current->numIdEntries; // Not supporting name entries
+			PEImageResourceEntry* entries = (PEImageResourceEntry*)(current + 1);
+
+			for (UINT32 i = 0; i < numEntries; i++)
+			{
+				// Only at root does the type identify resource type
+				if (base == current && entries[i].type != PE_IMAGE_RT_ICON)
+					continue;
+
+				if (entries[i].isDirectory)
+				{
+					PEImageResourceDirectory* child = (PEImageResourceDirectory*)(((UINT8*)base) + entries[i].offsetDirectory);
+					setIconData(base, child, imageData, sectionAddress);
+				}
+				else
+				{
+					PEImageResourceEntryData* data = (PEImageResourceEntryData*)(((UINT8*)base) + entries[i].offsetDirectory);
+
+					UINT8* iconData = imageData + (data->offsetData - sectionAddress);
+					updateIconData(iconData, pixelsPerSize);
+				}
+			}
+		};
+
+		for (UINT32 i = 0; i < numSectionHeaders; i++)
+		{
+			if (sectionHeaders[i].flags & PE_SECTION_UNINITIALIZED_DATA)
+				continue;
+
+			if (strcmp(sectionHeaders[i].name, ".rsrc") == 0)
+			{
+				UINT32 imageSize = sectionHeaders[i].physicalSize;
+				UINT8* imageData = (UINT8*)bs_stack_alloc(imageSize);
+
+				stream.seekg(sectionHeaders[i].physicalAddress);
+				stream.read((char*)imageData, imageSize);
+
+				UINT32 resourceDirOffset = dataDirectory->virtualAddress - sectionHeaders[i].relativeVirtualAddress;
+				PEImageResourceDirectory* resourceDirectory = (PEImageResourceDirectory*)&imageData[resourceDirOffset];
+
+				setIconData(resourceDirectory, resourceDirectory, imageData, sectionHeaders[i].relativeVirtualAddress);
+				stream.seekp(sectionHeaders[i].physicalAddress);
+				stream.write((char*)imageData, imageSize);
+
+				bs_stack_free(imageData);
+			}
+		}
+
+		bs_stack_free(sectionHeaders);
+		stream.close();
+	}
+
+	void IconUtility::updateIconData(UINT8* iconData, const Map<UINT32, PixelDataPtr>& pixelsPerSize)
+	{
+		IconHeader* iconHeader = (IconHeader*)iconData;
+
+		if (iconHeader->size != sizeof(IconHeader) || iconHeader->compression != 0
+			|| iconHeader->planes != 1 || iconHeader->bitCount != 32)
+		{
+			// Unsupported format
+			return;
+		}
+
+		UINT8* iconPixels = iconData + sizeof(IconHeader);
+		UINT32 width = iconHeader->width;
+		UINT32 height = iconHeader->height / 2;
+
+		auto iterFind = pixelsPerSize.find(width);
+		if (iterFind == pixelsPerSize.end() || iterFind->second->getWidth() != width
+			|| iterFind->second->getHeight() != height)
+		{
+			// No icon of this size provided
+			return;
+		}
+
+		// Write colors
+		PixelDataPtr srcPixels = iterFind->second;
+		UINT32* colorData = (UINT32*)iconPixels;
+
+		UINT32 idx = 0;
+		for (INT32 y = (INT32)height - 1; y >= 0; y--)
+		{
+			for (UINT32 x = 0; x < width; x++)
+				colorData[idx++] = srcPixels->getColorAt(x, y).getAsBGRA();
+		}
+
+		// Write AND mask
+		UINT32 colorDataSize = width * height * sizeof(UINT32);
+		UINT8* maskData = iconPixels + colorDataSize;
+
+		UINT32 numPackedPixels = width / 8; // One per bit in byte
+
+		for (INT32 y = (INT32)height - 1; y >= 0; y--)
+		{
+			UINT8 mask = 0;
+			for (UINT32 packedX = 0; packedX < numPackedPixels; packedX++)
+			{
+				for (UINT32 pixelIdx = 0; pixelIdx < 8; pixelIdx++)
+				{
+					UINT32 x = packedX * 8 + pixelIdx;
+					Color color = srcPixels->getColorAt(x, y);
+					if (color.a < 0.25f)
+						mask |= 1 << (7 - pixelIdx);
+				}
+
+				*maskData = mask;
+				maskData++;
+			}
+		}
+	}
 }

+ 184 - 186
Source/BansheeCore/Source/BsPass.cpp

@@ -1,187 +1,185 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPass.h"
-#include "BsRasterizerState.h"
-#include "BsBlendState.h"
-#include "BsDepthStencilState.h"
-#include "BsPassRTTI.h"
-#include "BsMaterial.h"
-#include "BsGpuParams.h"
-#include "BsFrameAlloc.h"
-#include "BsGpuProgram.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Converts a sim thread pass descriptor to a core thread one.
-	 */
-	void convertPassDesc(const PASS_DESC& input, PASS_DESC_CORE& output)
-	{
-		output.blendState = input.blendState != nullptr ? input.blendState->getCore() : nullptr;
-		output.rasterizerState = input.rasterizerState != nullptr ? input.rasterizerState->getCore() : nullptr;
-		output.depthStencilState = input.depthStencilState != nullptr ? input.depthStencilState->getCore() : nullptr;
-		output.stencilRefValue = input.stencilRefValue;
-		output.vertexProgram = input.vertexProgram != nullptr ? input.vertexProgram->getCore() : nullptr;
-		output.fragmentProgram = input.fragmentProgram != nullptr ? input.fragmentProgram->getCore() : nullptr;
-		output.geometryProgram = input.geometryProgram != nullptr ? input.geometryProgram->getCore() : nullptr;
-		output.hullProgram = input.hullProgram != nullptr ? input.hullProgram->getCore() : nullptr;
-		output.domainProgram = input.domainProgram != nullptr ? input.domainProgram->getCore() : nullptr;
-		output.hullProgram = input.hullProgram != nullptr ? input.hullProgram->getCore() : nullptr;
-	}
-
-	template<bool Core>
-	TPass<Core>::TPass()
-	{
-		mData.stencilRefValue = 0;
-	}
-
-	template<bool Core>
-	TPass<Core>::TPass(const PassDescType& data)
-		:mData(data)
-	{
-
-	}
-
-	template<bool Core>
-	bool TPass<Core>::hasBlending() const 
-	{ 
-		if (!mData.blendState)
-			return false;
-
-		bool transparent = false;
-
-		const BlendProperties& bsProps = mData.blendState->getProperties();
-		for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
-		{
-			// Transparent if destination color is taken into account
-			if (bsProps.getDstBlend(i) != BF_ZERO ||
-				bsProps.getSrcBlend(i) == BF_DEST_COLOR ||
-				bsProps.getSrcBlend(i) == BF_INV_DEST_COLOR ||
-				bsProps.getSrcBlend(i) == BF_DEST_ALPHA ||
-				bsProps.getSrcBlend(i) == BF_INV_DEST_ALPHA)
-			{
-				transparent = true;
-			}
-		}
-
-		return transparent;
-	}
-
-	template class TPass < false > ;
-	template class TPass < true >;
-
-	PassCore::PassCore(const PASS_DESC_CORE& desc)
-		:TPass(desc)
-	{ }
-
-	void PassCore::syncToCore(const CoreSyncData& data)
-	{
-		UINT8* dataPtr = data.getBuffer();
-		PASS_DESC_CORE* desc = (PASS_DESC_CORE*)dataPtr;
-
-		mData = *desc;
-		desc->~PASS_DESC_CORE();
-	}
-
-	SPtr<PassCore> PassCore::create(const PASS_DESC_CORE& desc)
-	{
-		PassCore* newPass = new (bs_alloc<PassCore>()) PassCore(desc);
-		SPtr<PassCore> newPassPtr = bs_shared_ptr<PassCore>(newPass);
-		newPassPtr->_setThisPtr(newPassPtr);
-		newPassPtr->initialize();
-
-		return newPassPtr;
-	}
-
-	Pass::Pass(const PASS_DESC& desc)
-		:TPass(desc)
-	{ }
-
-	SPtr<PassCore> Pass::getCore() const
-	{
-		return std::static_pointer_cast<PassCore>(mCoreSpecific);
-	}
-
-	SPtr<CoreObjectCore> Pass::createCore() const
-	{
-		PASS_DESC_CORE desc;
-		convertPassDesc(mData, desc);
-
-		PassCore* pass = new (bs_alloc<PassCore>()) PassCore(desc);
-		SPtr<PassCore> passPtr = bs_shared_ptr<PassCore>(pass);
-		passPtr->_setThisPtr(passPtr);
-
-		return passPtr;
-	}
-
-	CoreSyncData Pass::syncToCore(FrameAlloc* allocator)
-	{
-		UINT32 size = sizeof(PASS_DESC_CORE);
-
-		UINT8* data = allocator->alloc(size);
-		PASS_DESC_CORE* passDesc = new (data) PASS_DESC_CORE();
-		convertPassDesc(mData, *passDesc);
-
-		return CoreSyncData(data, size);
-	}
-
-	void Pass::getCoreDependencies(Vector<CoreObject*>& dependencies)
-	{
-		if (mData.blendState != nullptr)
-			dependencies.push_back(mData.blendState.get());
-
-		if (mData.rasterizerState != nullptr)
-			dependencies.push_back(mData.rasterizerState.get());
-
-		if (mData.depthStencilState != nullptr)
-			dependencies.push_back(mData.depthStencilState.get());
-
-		if (mData.vertexProgram != nullptr)
-			dependencies.push_back(mData.vertexProgram.get());
-
-		if (mData.fragmentProgram != nullptr)
-			dependencies.push_back(mData.fragmentProgram.get());
-
-		if (mData.geometryProgram != nullptr)
-			dependencies.push_back(mData.geometryProgram.get());
-
-		if (mData.hullProgram != nullptr)
-			dependencies.push_back(mData.hullProgram.get());
-
-		if (mData.domainProgram != nullptr)
-			dependencies.push_back(mData.domainProgram.get());
-
-		if (mData.computeProgram != nullptr)
-			dependencies.push_back(mData.computeProgram.get());
-	}
-
-	PassPtr Pass::create(const PASS_DESC& desc)
-	{
-		Pass* newPass = new (bs_alloc<Pass>()) Pass(desc);
-		PassPtr newPassPtr = bs_core_ptr<Pass>(newPass);
-		newPassPtr->_setThisPtr(newPassPtr);
-		newPassPtr->initialize();
-
-		return newPassPtr;
-	}
-
-	PassPtr Pass::createEmpty()
-	{
-		Pass* newPass = new (bs_alloc<Pass>()) Pass();
-		PassPtr newPassPtr = bs_core_ptr<Pass>(newPass);
-		newPassPtr->_setThisPtr(newPassPtr);
-
-		return newPassPtr;
-	}
-
-	RTTITypeBase* Pass::getRTTIStatic()
-	{
-		return PassRTTI::instance();
-	}
-
-	RTTITypeBase* Pass::getRTTI() const
-	{
-		return Pass::getRTTIStatic();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPass.h"
+#include "BsRasterizerState.h"
+#include "BsBlendState.h"
+#include "BsDepthStencilState.h"
+#include "BsPassRTTI.h"
+#include "BsMaterial.h"
+#include "BsGpuParams.h"
+#include "BsFrameAlloc.h"
+#include "BsGpuProgram.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	/** Converts a sim thread pass descriptor to a core thread one. */
+	void convertPassDesc(const PASS_DESC& input, PASS_DESC_CORE& output)
+	{
+		output.blendState = input.blendState != nullptr ? input.blendState->getCore() : nullptr;
+		output.rasterizerState = input.rasterizerState != nullptr ? input.rasterizerState->getCore() : nullptr;
+		output.depthStencilState = input.depthStencilState != nullptr ? input.depthStencilState->getCore() : nullptr;
+		output.stencilRefValue = input.stencilRefValue;
+		output.vertexProgram = input.vertexProgram != nullptr ? input.vertexProgram->getCore() : nullptr;
+		output.fragmentProgram = input.fragmentProgram != nullptr ? input.fragmentProgram->getCore() : nullptr;
+		output.geometryProgram = input.geometryProgram != nullptr ? input.geometryProgram->getCore() : nullptr;
+		output.hullProgram = input.hullProgram != nullptr ? input.hullProgram->getCore() : nullptr;
+		output.domainProgram = input.domainProgram != nullptr ? input.domainProgram->getCore() : nullptr;
+		output.hullProgram = input.hullProgram != nullptr ? input.hullProgram->getCore() : nullptr;
+	}
+
+	template<bool Core>
+	TPass<Core>::TPass()
+	{
+		mData.stencilRefValue = 0;
+	}
+
+	template<bool Core>
+	TPass<Core>::TPass(const PassDescType& data)
+		:mData(data)
+	{
+
+	}
+
+	template<bool Core>
+	bool TPass<Core>::hasBlending() const 
+	{ 
+		if (!mData.blendState)
+			return false;
+
+		bool transparent = false;
+
+		const BlendProperties& bsProps = mData.blendState->getProperties();
+		for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
+		{
+			// Transparent if destination color is taken into account
+			if (bsProps.getDstBlend(i) != BF_ZERO ||
+				bsProps.getSrcBlend(i) == BF_DEST_COLOR ||
+				bsProps.getSrcBlend(i) == BF_INV_DEST_COLOR ||
+				bsProps.getSrcBlend(i) == BF_DEST_ALPHA ||
+				bsProps.getSrcBlend(i) == BF_INV_DEST_ALPHA)
+			{
+				transparent = true;
+			}
+		}
+
+		return transparent;
+	}
+
+	template class TPass < false > ;
+	template class TPass < true >;
+
+	PassCore::PassCore(const PASS_DESC_CORE& desc)
+		:TPass(desc)
+	{ }
+
+	void PassCore::syncToCore(const CoreSyncData& data)
+	{
+		UINT8* dataPtr = data.getBuffer();
+		PASS_DESC_CORE* desc = (PASS_DESC_CORE*)dataPtr;
+
+		mData = *desc;
+		desc->~PASS_DESC_CORE();
+	}
+
+	SPtr<PassCore> PassCore::create(const PASS_DESC_CORE& desc)
+	{
+		PassCore* newPass = new (bs_alloc<PassCore>()) PassCore(desc);
+		SPtr<PassCore> newPassPtr = bs_shared_ptr<PassCore>(newPass);
+		newPassPtr->_setThisPtr(newPassPtr);
+		newPassPtr->initialize();
+
+		return newPassPtr;
+	}
+
+	Pass::Pass(const PASS_DESC& desc)
+		:TPass(desc)
+	{ }
+
+	SPtr<PassCore> Pass::getCore() const
+	{
+		return std::static_pointer_cast<PassCore>(mCoreSpecific);
+	}
+
+	SPtr<CoreObjectCore> Pass::createCore() const
+	{
+		PASS_DESC_CORE desc;
+		convertPassDesc(mData, desc);
+
+		PassCore* pass = new (bs_alloc<PassCore>()) PassCore(desc);
+		SPtr<PassCore> passPtr = bs_shared_ptr<PassCore>(pass);
+		passPtr->_setThisPtr(passPtr);
+
+		return passPtr;
+	}
+
+	CoreSyncData Pass::syncToCore(FrameAlloc* allocator)
+	{
+		UINT32 size = sizeof(PASS_DESC_CORE);
+
+		UINT8* data = allocator->alloc(size);
+		PASS_DESC_CORE* passDesc = new (data) PASS_DESC_CORE();
+		convertPassDesc(mData, *passDesc);
+
+		return CoreSyncData(data, size);
+	}
+
+	void Pass::getCoreDependencies(Vector<CoreObject*>& dependencies)
+	{
+		if (mData.blendState != nullptr)
+			dependencies.push_back(mData.blendState.get());
+
+		if (mData.rasterizerState != nullptr)
+			dependencies.push_back(mData.rasterizerState.get());
+
+		if (mData.depthStencilState != nullptr)
+			dependencies.push_back(mData.depthStencilState.get());
+
+		if (mData.vertexProgram != nullptr)
+			dependencies.push_back(mData.vertexProgram.get());
+
+		if (mData.fragmentProgram != nullptr)
+			dependencies.push_back(mData.fragmentProgram.get());
+
+		if (mData.geometryProgram != nullptr)
+			dependencies.push_back(mData.geometryProgram.get());
+
+		if (mData.hullProgram != nullptr)
+			dependencies.push_back(mData.hullProgram.get());
+
+		if (mData.domainProgram != nullptr)
+			dependencies.push_back(mData.domainProgram.get());
+
+		if (mData.computeProgram != nullptr)
+			dependencies.push_back(mData.computeProgram.get());
+	}
+
+	PassPtr Pass::create(const PASS_DESC& desc)
+	{
+		Pass* newPass = new (bs_alloc<Pass>()) Pass(desc);
+		PassPtr newPassPtr = bs_core_ptr<Pass>(newPass);
+		newPassPtr->_setThisPtr(newPassPtr);
+		newPassPtr->initialize();
+
+		return newPassPtr;
+	}
+
+	PassPtr Pass::createEmpty()
+	{
+		Pass* newPass = new (bs_alloc<Pass>()) Pass();
+		PassPtr newPassPtr = bs_core_ptr<Pass>(newPass);
+		newPassPtr->_setThisPtr(newPassPtr);
+
+		return newPassPtr;
+	}
+
+	RTTITypeBase* Pass::getRTTIStatic()
+	{
+		return PassRTTI::instance();
+	}
+
+	RTTITypeBase* Pass::getRTTI() const
+	{
+		return Pass::getRTTIStatic();
+	}
 }

+ 1777 - 1790
Source/BansheeCore/Source/BsPixelUtil.cpp

@@ -1,1790 +1,1777 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPixelUtil.h"
-#include "BsBitwise.h"
-#include "BsColor.h"
-#include "BsMath.h"
-#include "BsException.h"
-#include "nvtt/nvtt.h"
-
-namespace BansheeEngine 
-{
-	/**
-	 * @brief	Performs pixel data resampling using the point filter (nearest neighbor).
-	 *			Does not perform format conversions.
-	 *
-	 * @tparam elementSize	Size of a single pixel in bytes.
-	 */
-	template<UINT32 elementSize> struct NearestResampler 
-	{
-		static void scale(const PixelData& source, const PixelData& dest) 
-		{
-			UINT8* sourceData = source.getData();
-			UINT8* destPtr = dest.getData();
-
-			// Get steps for traversing source data in 16/48 fixed point format
-			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
-			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
-			UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
-
-			UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
-			for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ) 
-			{
-				UINT32 offsetZ = (UINT32)(curZ >> 48) * source.getSlicePitch();
-
-				UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
-				for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY) 
-				{
-					UINT32 offsetY = (UINT32)(curY >> 48) * source.getRowPitch();
-
-					UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
-					for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX) 
-					{
-						UINT32 offsetX = (UINT32)(curX >> 48);
-						UINT32 offsetBytes = elementSize*(offsetX + offsetY + offsetZ);
-
-						UINT8* curSourcePtr = sourceData + offsetBytes;
-							
-						memcpy(destPtr, curSourcePtr, elementSize);
-						destPtr += elementSize;
-					}
-
-					destPtr += elementSize*dest.getRowSkip();
-				}
-
-				destPtr += elementSize*dest.getSliceSkip();
-			}
-		}
-	};
-
-	/**
-	 * @brief	Performs pixel data resampling using the box filter (linear).
-	 *			Performs format conversions.
-	 */
-	struct LinearResampler 
-	{
-		static void scale(const PixelData& source, const PixelData& dest) 
-		{
-			UINT32 sourceElemSize = PixelUtil::getNumElemBytes(source.getFormat());
-			UINT32 destElemSize = PixelUtil::getNumElemBytes(dest.getFormat());
-
-			UINT8* sourceData = source.getData();
-			UINT8* destPtr = dest.getData();
-
-			// Get steps for traversing source data in 16/48 fixed point precision format
-			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
-			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
-			UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
-
-			// Contains 16/16 fixed point precision format. Most significant
-			// 16 bits will contain the coordinate in the source image, and the
-			// least significant 16 bits will contain the fractional part of the coordinate
-			// that will be used for determining the blend amount.
-			UINT32 temp = 0;
-
-			UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
-			for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ) 
-			{
-				temp = UINT32(curZ >> 32);
-				temp = (temp > 0x8000)? temp - 0x8000 : 0;
-				UINT32 sampleCoordZ1 = temp >> 16;
-				UINT32 sampleCoordZ2 = std::min(sampleCoordZ1 + 1, (UINT32)source.getDepth() - 1);
-				float sampleWeightZ = (temp & 0xFFFF) / 65536.0f; 
-
-				UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
-				for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY) 
-				{
-					temp = (UINT32)(curY >> 32);
-					temp = (temp > 0x8000)? temp - 0x8000 : 0;
-					UINT32 sampleCoordY1 = temp >> 16;
-					UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getHeight() - 1);
-					float sampleWeightY = (temp & 0xFFFF) / 65536.0f;
-
-					UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
-					for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX) 
-					{
-						temp = (UINT32)(curX >> 32);
-						temp = (temp > 0x8000)? temp - 0x8000 : 0;
-						UINT32 sampleCoordX1 = temp >> 16;
-						UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getWidth() - 1);
-						float sampleWeightX = (temp & 0xFFFF) / 65536.0f;
-
-						Color x1y1z1, x2y1z1, x1y2z1, x2y2z1;
-						Color x1y1z2, x2y1z2, x1y2z2, x2y2z2;
-
-#define GETSOURCEDATA(x, y, z) sourceData + sourceElemSize*((x)+(y)*source.getRowPitch() + (z)*source.getSlicePitch())
-
-						PixelUtil::unpackColor(&x1y1z1, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY1, sampleCoordZ1));
-						PixelUtil::unpackColor(&x2y1z1, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY1, sampleCoordZ1));
-						PixelUtil::unpackColor(&x1y2z1, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY2, sampleCoordZ1));
-						PixelUtil::unpackColor(&x2y2z1, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY2, sampleCoordZ1));
-						PixelUtil::unpackColor(&x1y1z2, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY1, sampleCoordZ2));
-						PixelUtil::unpackColor(&x2y1z2, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY1, sampleCoordZ2));
-						PixelUtil::unpackColor(&x1y2z2, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY2, sampleCoordZ2));
-						PixelUtil::unpackColor(&x2y2z2, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY2, sampleCoordZ2));
-#undef GETSOURCEDATA
-
-						Color accum =
-							x1y1z1 * ((1.0f - sampleWeightX)*(1.0f - sampleWeightY)*(1.0f - sampleWeightZ)) +
-							x2y1z1 * (        sampleWeightX *(1.0f - sampleWeightY)*(1.0f - sampleWeightZ)) +
-							x1y2z1 * ((1.0f - sampleWeightX)*        sampleWeightY *(1.0f - sampleWeightZ)) +
-							x2y2z1 * (        sampleWeightX *        sampleWeightY *(1.0f - sampleWeightZ)) +
-							x1y1z2 * ((1.0f - sampleWeightX)*(1.0f - sampleWeightY)*        sampleWeightZ ) +
-							x2y1z2 * (        sampleWeightX *(1.0f - sampleWeightY)*        sampleWeightZ ) +
-							x1y2z2 * ((1.0f - sampleWeightX)*        sampleWeightY *        sampleWeightZ ) +
-							x2y2z2 * (        sampleWeightX *        sampleWeightY *        sampleWeightZ );
-
-						PixelUtil::packColor(accum, dest.getFormat(), destPtr);
-
-						destPtr += destElemSize;
-					}
-
-					destPtr += destElemSize * dest.getRowSkip();
-				}
-
-				destPtr += destElemSize * dest.getSliceSkip();
-			}
-		}
-	};
-
-
-	/**
-	 * @brief	Performs pixel data resampling using the box filter (linear).
-	 *			Only handles float RGB or RGBA pixel data (32 bits per channel).
-	 */
-	struct LinearResampler_Float32 
-	{
-		static void scale(const PixelData& source, const PixelData& dest) 
-		{
-			UINT32 numSourceChannels = PixelUtil::getNumElemBytes(source.getFormat()) / sizeof(float);
-			UINT32 numDestChannels = PixelUtil::getNumElemBytes(dest.getFormat()) / sizeof(float);
-
-			float* sourceData = (float*)source.getData();
-			float* destPtr = (float*)dest.getData();
-
-			// Get steps for traversing source data in 16/48 fixed point precision format
-			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
-			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
-			UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
-
-			// Contains 16/16 fixed point precision format. Most significant
-			// 16 bits will contain the coordinate in the source image, and the
-			// least significant 16 bits will contain the fractional part of the coordinate
-			// that will be used for determining the blend amount.
-			UINT32 temp = 0;
-
-			UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
-			for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ) 
-			{
-				temp = (UINT32)(curZ >> 32);
-				temp = (temp > 0x8000)? temp - 0x8000 : 0;
-				UINT32 sampleCoordZ1 = temp >> 16;
-				UINT32 sampleCoordZ2 = std::min(sampleCoordZ1 + 1, (UINT32)source.getDepth() - 1);
-				float sampleWeightZ = (temp & 0xFFFF) / 65536.0f;
-
-				UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
-				for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY) 
-				{
-					temp = (UINT32)(curY >> 32);
-					temp = (temp > 0x8000)? temp - 0x8000 : 0;
-					UINT32 sampleCoordY1 = temp >> 16;
-					UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getHeight() - 1);
-					float sampleWeightY = (temp & 0xFFFF) / 65536.0f;
-
-					UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
-					for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX) 
-					{
-						temp = (UINT32)(curX >> 32);
-						temp = (temp > 0x8000)? temp - 0x8000 : 0;
-						UINT32 sampleCoordX1 = temp >> 16;
-						UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getWidth() - 1);
-						float sampleWeightX = (temp & 0xFFFF) / 65536.0f;
-
-						// process R,G,B,A simultaneously for cache coherence?
-						float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
-
-
-#define ACCUM3(x,y,z,factor) \
-						{ float f = factor; \
-						UINT32 offset = (x + y*source.getRowPitch() + z*source.getSlicePitch())*numSourceChannels; \
-						accum[0] += sourceData[offset + 0] * f; accum[1] += sourceData[offset + 1] * f; \
-						accum[2] += sourceData[offset + 2] * f; }
-
-#define ACCUM4(x,y,z,factor) \
-						{ float f = factor; \
-						UINT32 offset = (x + y*source.getRowPitch() + z*source.getSlicePitch())*numSourceChannels; \
-						accum[0] += sourceData[offset + 0] * f; accum[1] += sourceData[offset + 1] * f; \
-						accum[2] += sourceData[offset + 2] * f; accum[3] += sourceData[offset + 3] * f; }
-
-						if (numSourceChannels == 3 || numDestChannels == 3)
-						{
-							// RGB
-							ACCUM3(sampleCoordX1, sampleCoordY1, sampleCoordZ1, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
-							ACCUM3(sampleCoordX2, sampleCoordY1, sampleCoordZ1, sampleWeightX		   * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
-							ACCUM3(sampleCoordX1, sampleCoordY2, sampleCoordZ1, (1.0f - sampleWeightX) * sampleWeightY			* (1.0f - sampleWeightZ));
-							ACCUM3(sampleCoordX2, sampleCoordY2, sampleCoordZ1, sampleWeightX		   * sampleWeightY		    * (1.0f - sampleWeightZ));
-							ACCUM3(sampleCoordX1, sampleCoordY1, sampleCoordZ2, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * sampleWeightZ);
-							ACCUM3(sampleCoordX2, sampleCoordY1, sampleCoordZ2, sampleWeightX		   * (1.0f - sampleWeightY) * sampleWeightZ);
-							ACCUM3(sampleCoordX1, sampleCoordY2, sampleCoordZ2, (1.0f - sampleWeightX) * sampleWeightY			* sampleWeightZ);
-							ACCUM3(sampleCoordX2, sampleCoordY2, sampleCoordZ2, sampleWeightX		   * sampleWeightY			* sampleWeightZ);
-							accum[3] = 1.0f;
-						}
-						else 
-						{
-							// RGBA
-							ACCUM4(sampleCoordX1, sampleCoordY1, sampleCoordZ1, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
-							ACCUM4(sampleCoordX2, sampleCoordY1, sampleCoordZ1, sampleWeightX		   * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
-							ACCUM4(sampleCoordX1, sampleCoordY2, sampleCoordZ1, (1.0f - sampleWeightX) * sampleWeightY			* (1.0f - sampleWeightZ));
-							ACCUM4(sampleCoordX2, sampleCoordY2, sampleCoordZ1, sampleWeightX		   * sampleWeightY			* (1.0f - sampleWeightZ));
-							ACCUM4(sampleCoordX1, sampleCoordY1, sampleCoordZ2, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * sampleWeightZ);
-							ACCUM4(sampleCoordX2, sampleCoordY1, sampleCoordZ2, sampleWeightX		   * (1.0f - sampleWeightY) * sampleWeightZ);
-							ACCUM4(sampleCoordX1, sampleCoordY2, sampleCoordZ2, (1.0f - sampleWeightX) * sampleWeightY			* sampleWeightZ);
-							ACCUM4(sampleCoordX2, sampleCoordY2, sampleCoordZ2, sampleWeightX		   * sampleWeightY			* sampleWeightZ);
-						}
-
-						memcpy(destPtr, accum, sizeof(float)*numDestChannels);
-
-#undef ACCUM3
-#undef ACCUM4
-
-						destPtr += numDestChannels;
-					}
-
-					destPtr += numDestChannels*dest.getRowSkip();
-				}
-
-				destPtr += numDestChannels*dest.getSliceSkip();
-			}
-		}
-	};
-
-
-
-	// byte linear resampler, does not do any format conversions.
-	// only handles pixel formats that use 1 byte per color channel.
-	// 2D only; punts 3D pixelboxes to default LinearResampler (slow).
-	// templated on bytes-per-pixel to allow compiler optimizations, such
-	// as unrolling loops and replacing multiplies with bitshifts
-
-	/**
-	 * @brief	Performs pixel data resampling using the box filter (linear).
-	 *			Only handles pixel formats with one byte per channel. Does
-	 *			not perform format conversion.
-	 *
-	 * @tparam	channels	Number of channels in the pixel format.
-	 */
-	template<UINT32 channels> struct LinearResampler_Byte 
-	{
-		static void scale(const PixelData& source, const PixelData& dest) 
-		{
-			// Only optimized for 2D
-			if (source.getDepth() > 1 || dest.getDepth() > 1) 
-			{
-				LinearResampler::scale(source, dest);
-				return;
-			}
-
-			UINT8* sourceData = (UINT8*)source.getData();
-			UINT8* destPtr = (UINT8*)dest.getData();
-
-			// Get steps for traversing source data in 16/48 fixed point precision format
-			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
-			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
-
-			// Contains 16/16 fixed point precision format. Most significant
-			// 16 bits will contain the coordinate in the source image, and the
-			// least significant 16 bits will contain the fractional part of the coordinate
-			// that will be used for determining the blend amount.
-			UINT32 temp;
-
-			UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
-			for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY)
-			{
-				temp = (UINT32)(curY >> 36);
-				temp = (temp > 0x800)? temp - 0x800: 0;
-				UINT32 sampleWeightY = temp & 0xFFF;
-				UINT32 sampleCoordY1 = temp >> 12;
-				UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getBottom() - source.getTop() - 1);
-
-				UINT32 sampleY1Offset = sampleCoordY1 * source.getRowPitch();
-				UINT32 sampleY2Offset = sampleCoordY2 * source.getRowPitch();
-
-				UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
-				for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX)
-				{
-					temp = (UINT32)(curX >> 36);
-					temp = (temp > 0x800)? temp - 0x800 : 0;
-					UINT32 sampleWeightX = temp & 0xFFF;
-					UINT32 sampleCoordX1 = temp >> 12;
-					UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getRight() - source.getLeft() - 1);
-
-					UINT32 sxfsyf = sampleWeightX*sampleWeightY;
-					for (UINT32 k = 0; k < channels; k++) 
-					{
-						UINT32 accum =
-							sourceData[(sampleCoordX1 + sampleY1Offset)*channels+k]*(0x1000000-(sampleWeightX<<12)-(sampleWeightY<<12)+sxfsyf) +
-							sourceData[(sampleCoordX2 + sampleY1Offset)*channels+k]*((sampleWeightX<<12)-sxfsyf) +
-							sourceData[(sampleCoordX1 + sampleY2Offset)*channels+k]*((sampleWeightY<<12)-sxfsyf) +
-							sourceData[(sampleCoordX2 + sampleY2Offset)*channels+k]*sxfsyf;
-
-						// Round up to byte size
-						*destPtr = (UINT8)((accum + 0x800000) >> 24);
-						destPtr++;
-					}
-				}
-				destPtr += channels*dest.getRowSkip();
-			}
-		}
-	};
-
-	/**
-	 * @brief	Data describing a pixel format.
-	 */
-    struct PixelFormatDescription 
-	{
-		const char* name; /**< Name of the format. */
-		UINT8 elemBytes; /**< Number of bytes one element (color value) uses. */
-		UINT32 flags; /**< PixelFormatFlags set by the pixel format. */
-        PixelComponentType componentType; /**< Data type of a single element of the format. */
-		UINT8 componentCount; /**< Number of elements in the format. */
-
-		UINT8 rbits, gbits, bbits, abits; /**< Number of bits per element in the format. */
-
-        UINT32 rmask, gmask, bmask, amask; /**< Masks used by packers/unpackers. */
-		UINT8 rshift, gshift, bshift, ashift; /**< Shifts used by packers/unpackers. */
-    };
-
-	/**
-	 * @brief	A list of all available pixel formats.
-	 */
-    PixelFormatDescription _pixelFormats[PF_COUNT] = {
-        {"PF_UNKNOWN",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        0,
-        /* Component type and count */
-        PCT_BYTE, 0,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-		//-----------------------------------------------------------------------
-		{"PF_R8",
-		/* Bytes per element */
-		1,
-		/* Flags */
-		0,
-		/* Component type and count */
-		PCT_BYTE, 1,
-		/* rbits, gbits, bbits, abits */
-		8, 0, 0, 0,
-		/* Masks and shifts */
-		0x000000FF, 0, 0, 0, 
-		0, 0, 0, 0
-		},
-		//-----------------------------------------------------------------------
-		{"PF_R8G8",
-		/* Bytes per element */
-		2,
-		/* Flags */
-		0,
-		/* Component type and count */
-		PCT_BYTE, 2,
-		/* rbits, gbits, bbits, abits */
-		8, 8, 0, 0,
-		/* Masks and shifts */
-		0x000000FF, 0x0000FF00, 0, 0, 
-		0, 8, 0, 0
-		},
-	//-----------------------------------------------------------------------
-        {"PF_R8G8B8",
-        /* Bytes per element */
-        3,  // 24 bit integer -- special
-        /* Flags */
-        PFF_NATIVEENDIAN,
-        /* Component type and count */
-        PCT_BYTE, 3,
-        /* rbits, gbits, bbits, abits */
-        8, 8, 8, 0,
-        /* Masks and shifts */
-        0x000000FF, 0x0000FF00, 0x00FF0000, 0,
-        0, 8, 16, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_B8G8R8",
-        /* Bytes per element */
-        3,  // 24 bit integer -- special
-        /* Flags */
-        PFF_NATIVEENDIAN,
-        /* Component type and count */
-        PCT_BYTE, 3,
-        /* rbits, gbits, bbits, abits */
-        8, 8, 8, 0,
-        /* Masks and shifts */
-        0x00FF0000, 0x0000FF00, 0x000000FF, 0,
-        16, 8, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_A8R8G8B8",
-        /* Bytes per element */
-        4,
-        /* Flags */
-        PFF_HASALPHA | PFF_NATIVEENDIAN,
-        /* Component type and count */
-        PCT_BYTE, 4,
-        /* rbits, gbits, bbits, abits */
-        8, 8, 8, 8,
-        /* Masks and shifts */
-        0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
-        8, 16, 24, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_A8B8G8R8",
-        /* Bytes per element */
-        4,
-        /* Flags */
-        PFF_HASALPHA | PFF_NATIVEENDIAN,
-        /* Component type and count */
-        PCT_BYTE, 4,
-        /* rbits, gbits, bbits, abits */
-        8, 8, 8, 8,
-        /* Masks and shifts */
-        0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
-        24, 16, 8, 0,
-        },
-	//-----------------------------------------------------------------------
-        {"PF_B8G8R8A8",
-        /* Bytes per element */
-        4,
-        /* Flags */
-        PFF_HASALPHA | PFF_NATIVEENDIAN,
-        /* Component type and count */
-        PCT_BYTE, 4,
-        /* rbits, gbits, bbits, abits */
-        8, 8, 8, 8,
-        /* Masks and shifts */
-        0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
-        16, 8, 0, 24
-        },
-	//-----------------------------------------------------------------------
-		{"PF_R8G8B8A8",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_HASALPHA | PFF_NATIVEENDIAN,
-		/* Component type and count */
-		PCT_BYTE, 4,
-		/* rbits, gbits, bbits, abits */
-		8, 8, 8, 8,
-		/* Masks and shifts */
-		0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
-		0, 8, 16, 24
-		},
-	//-----------------------------------------------------------------------
-		{"PF_X8R8G8B8",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_NATIVEENDIAN,
-		/* Component type and count */
-		PCT_BYTE, 3,
-		/* rbits, gbits, bbits, abits */
-		8, 8, 8, 0,
-		/* Masks and shifts */
-		0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
-		8, 16, 24, 0
-		},
-	//-----------------------------------------------------------------------
-		{"PF_X8B8G8R8",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_NATIVEENDIAN,
-		/* Component type and count */
-		PCT_BYTE, 3,
-		/* rbits, gbits, bbits, abits */
-		8, 8, 8, 0,
-		/* Masks and shifts */
-		0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
-		24, 16, 8, 0
-		},
-	//-----------------------------------------------------------------------
-		{"PF_R8G8B8X8",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_HASALPHA | PFF_NATIVEENDIAN,
-		/* Component type and count */
-		PCT_BYTE, 3,
-		/* rbits, gbits, bbits, abits */
-		8, 8, 8, 0,
-		/* Masks and shifts */
-		0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
-		0, 8, 16, 0
-		},
-	//-----------------------------------------------------------------------
-		{"PF_B8G8R8X8",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_HASALPHA | PFF_NATIVEENDIAN,
-		/* Component type and count */
-		PCT_BYTE, 3,
-		/* rbits, gbits, bbits, abits */
-		8, 8, 8, 0,
-		/* Masks and shifts */
-		0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
-		16, 8, 0, 0
-		},
-	//-----------------------------------------------------------------------
-        {"PF_BC1",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_BYTE, 3, // No alpha
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC1a",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED,
-        /* Component type and count */
-        PCT_BYTE, 3,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC2",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_BYTE, 4,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC3",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_BYTE, 4,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC4",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED,
-        /* Component type and count */
-        PCT_BYTE, 1,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC5",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED,
-        /* Component type and count */
-        PCT_BYTE, 2,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC6H",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED,
-        /* Component type and count */
-        PCT_FLOAT16, 3,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_BC7",
-        /* Bytes per element */
-        0,
-        /* Flags */
-        PFF_COMPRESSED | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_BYTE, 4,
-        /* rbits, gbits, bbits, abits */
-        0, 0, 0, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-		{"PF_FLOAT16_R",
-		/* Bytes per element */
-		2,
-		/* Flags */
-		PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT16, 1,
-		/* rbits, gbits, bbits, abits */
-		16, 0, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		},
-	//-----------------------------------------------------------------------
-		{"PF_FLOAT16_RG",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT16, 2,
-		/* rbits, gbits, bbits, abits */
-		16, 16, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		},
-	//-----------------------------------------------------------------------
-        {"PF_FLOAT16_RGB",
-        /* Bytes per element */
-        6,
-        /* Flags */
-        PFF_FLOAT,
-        /* Component type and count */
-        PCT_FLOAT16, 3,
-        /* rbits, gbits, bbits, abits */
-        16, 16, 16, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_FLOAT16_RGBA",
-        /* Bytes per element */
-        8,
-        /* Flags */
-        PFF_FLOAT | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_FLOAT16, 4,
-        /* rbits, gbits, bbits, abits */
-        16, 16, 16, 16,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-		{"PF_FLOAT32_R",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT32, 1,
-		/* rbits, gbits, bbits, abits */
-		32, 0, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		},
-	//-----------------------------------------------------------------------
-		{"PF_FLOAT32_RG",
-		/* Bytes per element */
-		8,
-		/* Flags */
-		PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT32, 2,
-		/* rbits, gbits, bbits, abits */
-		32, 32, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		},
-	//-----------------------------------------------------------------------
-        {"PF_FLOAT32_RGB",
-        /* Bytes per element */
-        12,
-        /* Flags */
-        PFF_FLOAT,
-        /* Component type and count */
-        PCT_FLOAT32, 3,
-        /* rbits, gbits, bbits, abits */
-        32, 32, 32, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-        {"PF_FLOAT32_RGBA",
-        /* Bytes per element */
-        16,
-        /* Flags */
-        PFF_FLOAT | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_FLOAT32, 4,
-        /* rbits, gbits, bbits, abits */
-        32, 32, 32, 32,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
-	//-----------------------------------------------------------------------
-		{"PF_D32_S8X24",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_DEPTH | PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT32, 1,
-		/* rbits, gbits, bbits, abits */
-		0, 0, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		}, 
-	//-----------------------------------------------------------------------
-		{"PF_D24_S8",
-		/* Bytes per element */
-		8,
-		/* Flags */
-		PFF_DEPTH | PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT32, 2,
-		/* rbits, gbits, bbits, abits */
-		0, 0, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		}, 
-	//-----------------------------------------------------------------------
-		{"PF_D32",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_DEPTH | PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT32, 1,
-		/* rbits, gbits, bbits, abits */
-		0, 0, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		}, 
-	//-----------------------------------------------------------------------
-		{"PF_D16",
-		/* Bytes per element */
-		2,
-		/* Flags */
-		PFF_DEPTH | PFF_FLOAT,
-		/* Component type and count */
-		PCT_FLOAT16, 1,
-		/* rbits, gbits, bbits, abits */
-		0, 0, 0, 0,
-		/* Masks and shifts */
-		0, 0, 0, 0, 0, 0, 0, 0
-		}, 
-	//-----------------------------------------------------------------------
-		{ "PF_FLOAT_R11G11B10",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_FLOAT,
-		/* Component type and count */
-		PCT_PACKED_R11G11B10, 1,
-		/* rbits, gbits, bbits, abits */
-		11, 11, 10, 0,
-		/* Masks and shifts */
-		0x000007FF, 0x003FF800, 0xFFC00000, 0,
-		0, 11, 22, 0
-		},
-	//-----------------------------------------------------------------------
-		{ "PF_UNORM_R10G10B10A2",
-		/* Bytes per element */
-		4,
-		/* Flags */
-		PFF_FLOAT | PFF_HASALPHA,
-		/* Component type and count */
-		PCT_PACKED_R10G10B10A2, 1,
-		/* rbits, gbits, bbits, abits */
-		10, 10, 10, 2,
-		/* Masks and shifts */
-		0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000,
-		0, 10, 20, 30
-		},
-    };
-
-    static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
-    {
-        const int ord = (int)fmt;
-        assert(ord>=0 && ord<PF_COUNT);
-
-        return _pixelFormats[ord];
-    }
-
-	/**
-	 * @brief	Handles compression output from NVTT library for a single image.
-	 */
-	struct NVTTCompressOutputHandler : public nvtt::OutputHandler
-	{
-		NVTTCompressOutputHandler(UINT8* buffer, UINT32 sizeBytes)
-			:buffer(buffer), bufferWritePos(buffer), bufferEnd(buffer + sizeBytes)
-		{ }
-
-		virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override
-		{ }
-
-		virtual bool writeData(const void* data, int size) override
-		{
-			assert((bufferWritePos + size) <= bufferEnd);
-			memcpy(bufferWritePos, data, size);
-			bufferWritePos += size;
-
-			return true;
-		}
-
-		UINT8* buffer;
-		UINT8* bufferWritePos;
-		UINT8* bufferEnd;
-	};
-
-	/**
-	 * @brief	Handles output from NVTT library for a mip-map chain.
-	 */
-	struct NVTTMipmapOutputHandler : public nvtt::OutputHandler
-	{
-		NVTTMipmapOutputHandler(const Vector<PixelDataPtr>& buffers)
-			:buffers(buffers), bufferWritePos(nullptr), bufferEnd(nullptr)
-		{ }
-
-		virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
-		{ 
-			assert(miplevel >= 0 && miplevel < (int)buffers.size());
-			assert(size == buffers[miplevel]->getConsecutiveSize());
-
-			activeBuffer = buffers[miplevel];
-
-			bufferWritePos = activeBuffer->getData();
-			bufferEnd = bufferWritePos + activeBuffer->getConsecutiveSize();
-		}
-
-		virtual bool writeData(const void* data, int size)
-		{
-			assert((bufferWritePos + size) <= bufferEnd);
-			memcpy(bufferWritePos, data, size);
-			bufferWritePos += size;
-
-			return true;
-		}
-
-		Vector<PixelDataPtr> buffers;
-		PixelDataPtr activeBuffer;
-
-		UINT8* bufferWritePos;
-		UINT8* bufferEnd;
-	};
-
-	nvtt::Format toNVTTFormat(PixelFormat format)
-	{
-		switch (format)
-		{
-		case PF_BC1:
-			return nvtt::Format_BC1;
-		case PF_BC1a:
-			return nvtt::Format_BC1a;
-		case PF_BC2:
-			return nvtt::Format_BC2;
-		case PF_BC3:
-			return nvtt::Format_BC3;
-		case PF_BC4:
-			return nvtt::Format_BC4;
-		case PF_BC5:
-			return nvtt::Format_BC5;
-		}
-
-		// Unsupported format
-		return nvtt::Format_BC3;
-	}
-
-	nvtt::Quality toNVTTQuality(CompressionQuality quality)
-	{
-		switch (quality)
-		{
-		case CompressionQuality::Fastest:
-			return nvtt::Quality_Fastest;
-		case CompressionQuality::Highest:
-			return nvtt::Quality_Highest;
-		case CompressionQuality::Normal:
-			return nvtt::Quality_Normal;
-		case CompressionQuality::Production:
-			return nvtt::Quality_Normal;
-		}
-
-		// Unknown quality level
-		return nvtt::Quality_Normal;
-	}
-
-	nvtt::AlphaMode toNVTTAlphaMode(AlphaMode alphaMode)
-	{
-		switch (alphaMode)
-		{
-		case AlphaMode::None:
-			return nvtt::AlphaMode_None;
-		case AlphaMode::Premultiplied:
-			return nvtt::AlphaMode_Premultiplied;
-		case AlphaMode::Transparency:
-			return nvtt::AlphaMode_Transparency;
-		}
-
-		// Unknown alpha mode
-		return nvtt::AlphaMode_None;
-	}
-
-	nvtt::WrapMode toNVTTWrapMode(MipMapWrapMode wrapMode)
-	{
-		switch (wrapMode)
-		{
-		case MipMapWrapMode::Clamp:
-			return nvtt::WrapMode_Clamp;
-		case MipMapWrapMode::Mirror:
-			return nvtt::WrapMode_Mirror;
-		case MipMapWrapMode::Repeat:
-			return nvtt::WrapMode_Repeat;
-		}
-
-		// Unknown alpha mode
-		return nvtt::WrapMode_Mirror;
-	}
-
-    UINT32 PixelUtil::getNumElemBytes(PixelFormat format)
-    {
-        return getDescriptionFor(format).elemBytes;
-    }
-
-	UINT32 PixelUtil::getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
-	{
-		if(isCompressed(format))
-		{
-			switch(format)
-			{
-				// BC formats work by dividing the image into 4x4 blocks, then encoding each
-				// 4x4 block with a certain number of bytes. 
-				case PF_BC1:
-				case PF_BC1a:
-				case PF_BC4:
-					return ((width+3)/4)*((height+3)/4)*8 * depth;
-				case PF_BC2:
-				case PF_BC3:
-				case PF_BC5:
-				case PF_BC6H:
-				case PF_BC7:
-					return ((width+3)/4)*((height+3)/4)*16 * depth;
-
-				default:
-					BS_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
-			}
-		}
-		else
-		{
-			return width*height*depth*getNumElemBytes(format);
-		}
-
-		return 0;
-	}
-
-	void PixelUtil::getSizeForMipLevel(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevel,
-		UINT32& mipWidth, UINT32& mipHeight, UINT32& mipDepth)
-	{
-		mipWidth = width;
-		mipHeight = height;
-		mipDepth = depth;
-
-		for (UINT32 i = 0; i < mipLevel; i++)
-		{
-			if (mipWidth != 1) mipWidth /= 2;
-			if (mipHeight != 1) mipHeight /= 2;
-			if (mipDepth != 1) mipDepth /= 2;
-		}
-	}
-
-    UINT32 PixelUtil::getNumElemBits(PixelFormat format)
-    {
-        return getDescriptionFor(format).elemBytes * 8;
-    }
-
-    UINT32 PixelUtil::getFlags(PixelFormat format)
-    {
-        return getDescriptionFor(format).flags;
-    }
-
-    bool PixelUtil::hasAlpha(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
-    }
-
-    bool PixelUtil::isFloatingPoint(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
-    }
-
-    bool PixelUtil::isCompressed(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
-    }
-
-    bool PixelUtil::isDepth(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
-    }
-
-    bool PixelUtil::isNativeEndian(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
-    }
-
-	bool PixelUtil::isValidExtent(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
-	{
-		if(isCompressed(format))
-		{
-			switch(format)
-			{
-				case PF_BC1:
-				case PF_BC2:
-				case PF_BC1a:
-				case PF_BC3:
-				case PF_BC4:
-				case PF_BC5:
-				case PF_BC6H:
-				case PF_BC7:
-					return ((width & 3) == 0 && (height & 3) == 0 && depth == 1);
-				default:
-					return true;
-			}
-		}
-		else
-		{
-			return true;
-		}
-	}
-
-    void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
-    {
-        const PixelFormatDescription& des = getDescriptionFor(format);
-        rgba[0] = des.rbits;
-        rgba[1] = des.gbits;
-        rgba[2] = des.bbits;
-        rgba[3] = des.abits;
-    }
-
-	void PixelUtil::getBitMasks(PixelFormat format, UINT32 rgba[4])
-    {
-        const PixelFormatDescription& des = getDescriptionFor(format);
-        rgba[0] = des.rmask;
-        rgba[1] = des.gmask;
-        rgba[2] = des.bmask;
-        rgba[3] = des.amask;
-    }
-
-	void PixelUtil::getBitShifts(PixelFormat format, UINT8 rgba[4])
-	{
-		const PixelFormatDescription& des = getDescriptionFor(format);
-		rgba[0] = des.rshift;
-		rgba[1] = des.gshift;
-		rgba[2] = des.bshift;
-		rgba[3] = des.ashift;
-	}
-
-    String PixelUtil::getFormatName(PixelFormat srcformat)
-    {
-        return getDescriptionFor(srcformat).name;
-    }
-
-    bool PixelUtil::isAccessible(PixelFormat srcformat)
-    {
-        if (srcformat == PF_UNKNOWN)
-            return false;
-
-        UINT32 flags = getFlags(srcformat);
-        return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
-    }
-
-    PixelComponentType PixelUtil::getElementType(PixelFormat format)
-    {
-		const PixelFormatDescription& des = getDescriptionFor(format);
-        return des.componentType;
-    }
-
-	UINT32 PixelUtil::getNumElements(PixelFormat format)
-    {
-		const PixelFormatDescription& des = getDescriptionFor(format);
-        return des.componentCount;
-    }
-
-	UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
-	{
-		UINT32 count = 0;
-        if((width > 0) && (height > 0))
-        {
-            do {
-                if(width>1)		width = width/2;
-                if(height>1)	height = height/2;
-                if(depth>1)		depth = depth/2;
-                    
-                count ++;
-            } while(!(width == 1 && height == 1 && depth == 1));
-        }
-
-		return count;
-	}
-
-    void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
-    {
-        packColor(color.r, color.g, color.b, color.a, format, dest);
-    }
-
-    void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format,  void* dest)
-    {
-        const PixelFormatDescription &des = getDescriptionFor(format);
-
-        if(des.flags & PFF_NATIVEENDIAN) 
-		{
-            // Shortcut for integer formats packing
-            UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
-                ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
-                ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
-                ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
-
-            // And write to memory
-            Bitwise::intWrite(dest, des.elemBytes, value);
-        } 
-		else 
-		{
-            // Convert to float
-            packColor((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, format, dest);
-        }
-    }
-
-    void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
-    {
-        const PixelFormatDescription& des = getDescriptionFor(format);
-
-        if(des.flags & PFF_NATIVEENDIAN) 
-		{
-            // Do the packing
-            const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
-                ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
-                ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
-                ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
-
-            // And write to memory
-            Bitwise::intWrite(dest, des.elemBytes, value);
-        }
-		else 
-		{
-            switch(format)
-            {
-            case PF_FLOAT32_R:
-                ((float*)dest)[0] = r;
-                break;
-			case PF_FLOAT32_RG:
-				((float*)dest)[0] = r;
-				((float*)dest)[1] = g;
-				break;
-            case PF_FLOAT32_RGB:
-                ((float*)dest)[0] = r;
-                ((float*)dest)[1] = g;
-                ((float*)dest)[2] = b;
-                break;
-            case PF_FLOAT32_RGBA:
-                ((float*)dest)[0] = r;
-                ((float*)dest)[1] = g;
-                ((float*)dest)[2] = b;
-                ((float*)dest)[3] = a;
-                break;
-            case PF_FLOAT16_R:
-                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-                break;
-			case PF_FLOAT16_RG:
-				((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-				((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
-				break;
-            case PF_FLOAT16_RGB:
-                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-                ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
-                ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
-                break;
-            case PF_FLOAT16_RGBA:
-                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-                ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
-                ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
-                ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
-                break;
-			case PF_R8G8:
-				((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
-                ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
-				break;
-			case PF_R8:
-				((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
-				break;
-            default:
-                BS_EXCEPT(NotImplementedException, "Pack to " + getFormatName(format) + " not implemented");
-                break;
-            }
-        }
-    }
-    void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
-    {
-		unpackColor(&color->r, &color->g, &color->b, &color->a, format, src);
-    }
-
-    void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
-    {
-        const PixelFormatDescription &des = getDescriptionFor(format);
-
-        if(des.flags & PFF_NATIVEENDIAN) 
-		{
-            // Shortcut for integer formats unpacking
-            const UINT32 value = Bitwise::intRead(src, des.elemBytes);
-
-            *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
-            *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
-            *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
-
-            if(des.flags & PFF_HASALPHA)
-            {
-                *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
-            }
-            else
-            {
-                *a = 255; // No alpha, default a component to full
-            }
-        } 
-		else 
-		{
-            // Do the operation with the more generic floating point
-            float rr, gg, bb, aa;
-            unpackColor(&rr,&gg,&bb,&aa, format, src);
-
-            *r = (UINT8)Bitwise::floatToFixed(rr, 8);
-            *g = (UINT8)Bitwise::floatToFixed(gg, 8);
-            *b = (UINT8)Bitwise::floatToFixed(bb, 8);
-            *a = (UINT8)Bitwise::floatToFixed(aa, 8);
-        }
-    }
-
-    void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
-    {
-        const PixelFormatDescription &des = getDescriptionFor(format);
-
-        if(des.flags & PFF_NATIVEENDIAN) 
-		{
-            // Shortcut for integer formats unpacking
-            const unsigned int value = Bitwise::intRead(src, des.elemBytes);
-
-			*r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
-			*g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
-			*b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
-
-            if(des.flags & PFF_HASALPHA)
-            {
-                *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
-            }
-            else
-            {
-                *a = 1.0f; // No alpha, default a component to full
-            }
-        } 
-		else 
-		{
-            switch(format)
-            {
-            case PF_FLOAT32_R:
-                *r = *g = *b = ((float*)src)[0];
-                *a = 1.0f;
-                break;
-			case PF_FLOAT32_RG:
-				*r = ((float*)src)[0];
-				*g = *b = ((float*)src)[1];
-				*a = 1.0f;
-				break;
-            case PF_FLOAT32_RGB:
-                *r = ((float*)src)[0];
-                *g = ((float*)src)[1];
-                *b = ((float*)src)[2];
-                *a = 1.0f;
-                break;
-            case PF_FLOAT32_RGBA:
-                *r = ((float*)src)[0];
-                *g = ((float*)src)[1];
-                *b = ((float*)src)[2];
-                *a = ((float*)src)[3];
-                break;
-            case PF_FLOAT16_R:
-                *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
-                *a = 1.0f;
-                break;
-			case PF_FLOAT16_RG:
-				*r = Bitwise::halfToFloat(((UINT16*)src)[0]);
-				*g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
-				*a = 1.0f;
-				break;
-            case PF_FLOAT16_RGB:
-                *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
-                *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
-                *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
-                *a = 1.0f;
-                break;
-            case PF_FLOAT16_RGBA:
-                *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
-                *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
-                *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
-                *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
-                break;
-			case PF_R8G8:
-				*r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
-				*g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
-				*b = 0.0f;
-				*a = 1.0f;
-				break;
-			case PF_R8:
-				*r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
-				*g = 0.0f;
-				*b = 0.0f;
-				*a = 1.0f;
-				break;
-            default:
-                BS_EXCEPT(NotImplementedException, "Unpack from " + getFormatName(format) + " not implemented");
-                break;
-            }
-        }
-    }
-
-    void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
-    {
-        assert(src.getWidth() == dst.getWidth() &&
-			   src.getHeight() == dst.getHeight() &&
-			   src.getDepth() == dst.getDepth());
-
-		// Check for compressed formats, we don't support decompression
-		if(PixelUtil::isCompressed(src.getFormat()))
-		{
-			if(src.getFormat() == dst.getFormat())
-			{
-				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
-				return;
-			}
-			else
-			{
-				BS_EXCEPT(NotImplementedException, "This method can not be used to compress or decompress images");
-			}
-		}
-
-		// Check for compression
-		if (PixelUtil::isCompressed(dst.getFormat()))
-		{
-			if (src.getFormat() == dst.getFormat())
-			{
-				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
-				return;
-			}
-			else
-			{
-				CompressionOptions co;
-				co.format = dst.getFormat();
-				compress(src, dst, co);
-
-				return;
-			}
-		}
-
-        // The easy case
-        if(src.getFormat() == dst.getFormat()) 
-		{
-            // Everything consecutive?
-            if(src.isConsecutive() && dst.isConsecutive())
-            {
-				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
-                return;
-            }
-
-			const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
-			const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
-            UINT8 *srcptr = static_cast<UINT8*>(src.getData())
-                + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
-            UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
-				+ (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
-
-            // Calculate pitches+skips in bytes
-			const UINT32 srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
-			const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
-
-			const UINT32 dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
-			const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
-
-            // Otherwise, copy per row
-			const UINT32 rowSize = src.getWidth()*srcPixelSize;
-			for (UINT32 z = src.getFront(); z < src.getBack(); z++)
-            {
-                for(UINT32 y = src.getTop(); y < src.getBottom(); y++)
-                {
-					memcpy(dstptr, srcptr, rowSize);
-
-                    srcptr += srcRowPitchBytes;
-                    dstptr += dstRowPitchBytes;
-                }
-
-                srcptr += srcSliceSkipBytes;
-                dstptr += dstSliceSkipBytes;
-            }
-
-            return;
-        }
-
-		// Converting to PF_X8R8G8B8 is exactly the same as converting to
-		// PF_A8R8G8B8. (same with PF_X8B8G8R8 and PF_A8B8G8R8)
-		if(dst.getFormat() == PF_X8R8G8B8 || dst.getFormat() == PF_X8B8G8R8)
-		{
-			// Do the same conversion, with PF_A8R8G8B8, which has a lot of
-			// optimized conversions
-			PixelFormat tempFormat = dst.getFormat() == PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
-			PixelData tempdst(dst.getWidth(), dst.getHeight(), dst.getDepth(), tempFormat);
-			bulkPixelConversion(src, tempdst);
-			return;
-		}
-
-		// Converting from PF_X8R8G8B8 is exactly the same as converting from
-		// PF_A8R8G8B8, given that the destination format does not have alpha.
-		if((src.getFormat() == PF_X8R8G8B8 || src.getFormat() == PF_X8B8G8R8) && !hasAlpha(dst.getFormat()))
-		{
-			// Do the same conversion, with PF_A8R8G8B8, which has a lot of
-			// optimized conversions
-			PixelFormat tempFormat = src.getFormat()==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
-			PixelData tempsrc(src.getWidth(), src.getHeight(), src.getDepth(), tempFormat);
-			tempsrc.setExternalBuffer(src.getData());
-			bulkPixelConversion(tempsrc, dst);
-			return;
-		}
-
-		const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
-		const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
-        UINT8 *srcptr = static_cast<UINT8*>(src.getData())
-            + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
-        UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
-            + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
-		
-        // Calculate pitches+skips in bytes
-		const UINT32 srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
-		const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
-		const UINT32 dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
-		const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
-
-        // The brute force fallback
-        float r,g,b,a;
-		for (UINT32 z = src.getFront(); z<src.getBack(); z++)
-		{
-			for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
-            {
-				for (UINT32 x = src.getLeft(); x<src.getRight(); x++)
-                {
-                    unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
-                    packColor(r, g, b, a, dst.getFormat(), dstptr);
-
-                    srcptr += srcPixelSize;
-                    dstptr += dstPixelSize;
-                }
-
-                srcptr += srcRowSkipBytes;
-                dstptr += dstRowSkipBytes;
-            }
-
-            srcptr += srcSliceSkipBytes;
-            dstptr += dstSliceSkipBytes;
-        }
-    }
-
-	void PixelUtil::scale(const PixelData& src, PixelData& scaled, Filter filter)
-	{
-		assert(PixelUtil::isAccessible(src.getFormat()));
-		assert(PixelUtil::isAccessible(scaled.getFormat()));
-
-		PixelData temp;
-		switch (filter) 
-		{
-		default:
-		case FILTER_NEAREST:
-			if(src.getFormat() == scaled.getFormat()) 
-			{
-				// No intermediate buffer needed
-				temp = scaled;
-			}
-			else
-			{
-				// Allocate temporary buffer of destination size in source format 
-				temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
-				temp.allocateInternalBuffer();
-			}
-
-			// No conversion
-			switch (PixelUtil::getNumElemBytes(src.getFormat())) 
-			{
-			case 1: NearestResampler<1>::scale(src, temp); break;
-			case 2: NearestResampler<2>::scale(src, temp); break;
-			case 3: NearestResampler<3>::scale(src, temp); break;
-			case 4: NearestResampler<4>::scale(src, temp); break;
-			case 6: NearestResampler<6>::scale(src, temp); break;
-			case 8: NearestResampler<8>::scale(src, temp); break;
-			case 12: NearestResampler<12>::scale(src, temp); break;
-			case 16: NearestResampler<16>::scale(src, temp); break;
-			default:
-				// Never reached
-				assert(false);
-			}
-
-			if(temp.getData() != scaled.getData())
-			{
-				// Blit temp buffer
-				PixelUtil::bulkPixelConversion(temp, scaled);
-
-				temp.freeInternalBuffer();
-			}
-
-			break;
-
-		case FILTER_LINEAR:
-			switch (src.getFormat()) 
-			{
-			case PF_R8G8:
-			case PF_R8G8B8: case PF_B8G8R8:
-			case PF_R8G8B8A8: case PF_B8G8R8A8:
-			case PF_A8B8G8R8: case PF_A8R8G8B8:
-			case PF_X8B8G8R8: case PF_X8R8G8B8:
-				if(src.getFormat() == scaled.getFormat()) 
-				{
-					// No intermediate buffer needed
-					temp = scaled;
-				}
-				else
-				{
-					// Allocate temp buffer of destination size in source format 
-					temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
-					temp.allocateInternalBuffer();
-				}
-
-				// No conversion
-				switch (PixelUtil::getNumElemBytes(src.getFormat())) 
-				{
-				case 1: LinearResampler_Byte<1>::scale(src, temp); break;
-				case 2: LinearResampler_Byte<2>::scale(src, temp); break;
-				case 3: LinearResampler_Byte<3>::scale(src, temp); break;
-				case 4: LinearResampler_Byte<4>::scale(src, temp); break;
-				default:
-					// Never reached
-					assert(false);
-				}
-
-				if(temp.getData() != scaled.getData())
-				{
-					// Blit temp buffer
-					PixelUtil::bulkPixelConversion(temp, scaled);
-					temp.freeInternalBuffer();
-				}
-
-				break;
-			case PF_FLOAT32_RGB:
-			case PF_FLOAT32_RGBA:
-				if (scaled.getFormat() == PF_FLOAT32_RGB || scaled.getFormat() == PF_FLOAT32_RGBA)
-				{
-					// float32 to float32, avoid unpack/repack overhead
-					LinearResampler_Float32::scale(src, scaled);
-					break;
-				}
-				// Else, fall through
-			default:
-				// Fallback case, slow but works
-				LinearResampler::scale(src, scaled);
-			}
-			break;
-		}
-	}
-
-	void PixelUtil::applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp)
-	{
-		if(gamma == 1.0f)
-			return;
-
-		UINT32 stride = bpp >> 3;
-
-		for(size_t i = 0, j = size / stride; i < j; i++, buffer += stride)
-		{
-			float r = (float)buffer[0];
-			float g = (float)buffer[1];
-			float b = (float)buffer[2];
-
-			r = r * gamma;
-			g = g * gamma;
-			b = b * gamma;
-
-			float scale = 1.0f;
-			float tmp = 0.0f;
-
-			if(r > 255.0f && (tmp=(255.0f/r)) < scale)
-				scale = tmp;
-
-			if(g > 255.0f && (tmp=(255.0f/g)) < scale)
-				scale = tmp;
-
-			if(b > 255.0f && (tmp=(255.0f/b)) < scale)
-				scale = tmp;
-
-			r *= scale; 
-			g *= scale; 
-			b *= scale;
-
-			buffer[0] = (UINT8)r;
-			buffer[1] = (UINT8)g;
-			buffer[2] = (UINT8)b;
-		}
-	}
-
-	void PixelUtil::compress(const PixelData& src, PixelData& dst, const CompressionOptions& options)
-	{
-		if (!isCompressed(options.format))
-			BS_EXCEPT(InvalidParametersException, "Wanted format is not a compressed format.");
-
-		// Note: NVTT site has implementations for these two formats for when I decide to add them
-		if (options.format == PF_BC6H || options.format == PF_BC7)
-			BS_EXCEPT(InvalidParametersException, "Specified formats are not yet supported.");
-
-		if (src.getDepth() != 1)
-			BS_EXCEPT(InvalidParametersException, "3D textures are not supported.");
-
-		PixelFormat pf = options.format;
-
-		if (isCompressed(src.getFormat()))
-			BS_EXCEPT(InvalidParametersException, "Source data cannot be compressed.");
-
-		PixelData bgraData(src.getWidth(), src.getHeight(), 1, PF_B8G8R8A8);
-		bgraData.allocateInternalBuffer();
-		bulkPixelConversion(src, bgraData);
-
-		nvtt::InputOptions io;
-		io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
-		io.setMipmapData(bgraData.getData(), src.getWidth(), src.getHeight());
-		io.setMipmapGeneration(false);
-		io.setAlphaMode(toNVTTAlphaMode(options.alphaMode));
-		io.setNormalMap(options.isNormalMap);
-
-		if (options.isSRGB)
-			io.setGamma(2.2f, 2.2f);
-		else
-			io.setGamma(1.0f, 1.0f);
-
-		nvtt::CompressionOptions co;
-		co.setFormat(toNVTTFormat(options.format));
-		co.setQuality(toNVTTQuality(options.quality));
-		
-		NVTTCompressOutputHandler outputHandler(dst.getData(), dst.getConsecutiveSize());
-
-		nvtt::OutputOptions oo;
-		oo.setOutputHeader(false);
-		oo.setOutputHandler(&outputHandler);
-		
-		nvtt::Compressor compressor;
-		if (!compressor.process(io, co, oo))
-			BS_EXCEPT(InternalErrorException, "Compressing failed.");
-	}
-
-	Vector<PixelDataPtr> PixelUtil::genMipmaps(const PixelData& src, const MipMapGenOptions& options)
-	{
-		if (src.getDepth() != 1)
-			BS_EXCEPT(InvalidParametersException, "3D textures are not supported.");
-
-		// Note: Add support for floating point mips, no reason they shouldn't be supported other than
-		// nvtt doesn't support them natively
-		if (isCompressed(src.getFormat()) || isFloatingPoint(src.getFormat()))
-			BS_EXCEPT(InvalidParametersException, "Source data cannot be compressed or in floating point format.");
-
-		if (!Math::isPow2(src.getWidth()) || !Math::isPow2(src.getHeight()))
-			BS_EXCEPT(InvalidParametersException, "Texture width & height must be powers of 2.");
-
-		PixelData argbData(src.getWidth(), src.getHeight(), 1, PF_A8R8G8B8);
-		argbData.allocateInternalBuffer();
-		bulkPixelConversion(src, argbData);
-
-		nvtt::InputOptions io;
-		io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
-		io.setMipmapData(argbData.getData(), src.getWidth(), src.getHeight());
-		io.setMipmapGeneration(true);
-		io.setNormalMap(options.isNormalMap);
-		io.setNormalizeMipmaps(options.normalizeMipmaps);
-		io.setWrapMode(toNVTTWrapMode(options.wrapMode));
-
-		nvtt::CompressionOptions co;
-		co.setFormat(nvtt::Format_RGBA);
-		
-		UINT32 numMips = getMaxMipmaps(src.getWidth(), src.getHeight(), 1, src.getFormat());
-
-		Vector<PixelDataPtr> argbMipBuffers;
-
-		// Note: This can be done more effectively without creating so many temp buffers
-		// and working with the original formats directly, but it would complicate the code
-		// too much at the moment.
-		UINT32 curWidth = src.getWidth();
-		UINT32 curHeight = src.getHeight();
-		for (UINT32 i = 0; i < numMips; i++)
-		{
-			argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
-			argbMipBuffers.back()->allocateInternalBuffer();
-
-			if (curWidth > 1) 
-				curWidth = curWidth / 2;
-
-			if (curHeight > 1)
-				curHeight = curHeight / 2;
-		}
-
-		argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
-		argbMipBuffers.back()->allocateInternalBuffer();
-
-		NVTTMipmapOutputHandler outputHandler(argbMipBuffers);
-
-		nvtt::OutputOptions oo;
-		oo.setOutputHeader(false);
-		oo.setOutputHandler(&outputHandler);
-
-		nvtt::Compressor compressor;
-		if (!compressor.process(io, co, oo))
-			BS_EXCEPT(InternalErrorException, "Mipmap generation failed.");
-
-		argbData.freeInternalBuffer();
-
-		Vector<PixelDataPtr> outputMipBuffers;
-		for (UINT32 i = 0; i < (UINT32)argbMipBuffers.size(); i++)
-		{
-			PixelDataPtr argbBuffer = argbMipBuffers[i];
-			PixelDataPtr outputBuffer = bs_shared_ptr_new<PixelData>(argbBuffer->getWidth(), argbBuffer->getHeight(), 1, src.getFormat());
-			outputBuffer->allocateInternalBuffer();
-
-			bulkPixelConversion(*argbBuffer, *outputBuffer);
-			argbBuffer->freeInternalBuffer();
-
-			outputMipBuffers.push_back(outputBuffer);
-		}
-
-		return outputMipBuffers;
-	}
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPixelUtil.h"
+#include "BsBitwise.h"
+#include "BsColor.h"
+#include "BsMath.h"
+#include "BsException.h"
+#include "nvtt/nvtt.h"
+
+namespace BansheeEngine 
+{
+	/**
+	 * Performs pixel data resampling using the point filter (nearest neighbor). Does not perform format conversions.
+	 *
+	 * @tparam elementSize	Size of a single pixel in bytes.
+	 */
+	template<UINT32 elementSize> struct NearestResampler 
+	{
+		static void scale(const PixelData& source, const PixelData& dest) 
+		{
+			UINT8* sourceData = source.getData();
+			UINT8* destPtr = dest.getData();
+
+			// Get steps for traversing source data in 16/48 fixed point format
+			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
+			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
+			UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
+
+			UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
+			for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ) 
+			{
+				UINT32 offsetZ = (UINT32)(curZ >> 48) * source.getSlicePitch();
+
+				UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
+				for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY) 
+				{
+					UINT32 offsetY = (UINT32)(curY >> 48) * source.getRowPitch();
+
+					UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
+					for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX) 
+					{
+						UINT32 offsetX = (UINT32)(curX >> 48);
+						UINT32 offsetBytes = elementSize*(offsetX + offsetY + offsetZ);
+
+						UINT8* curSourcePtr = sourceData + offsetBytes;
+							
+						memcpy(destPtr, curSourcePtr, elementSize);
+						destPtr += elementSize;
+					}
+
+					destPtr += elementSize*dest.getRowSkip();
+				}
+
+				destPtr += elementSize*dest.getSliceSkip();
+			}
+		}
+	};
+
+	/** Performs pixel data resampling using the box filter (linear). Performs format conversions. */
+	struct LinearResampler 
+	{
+		static void scale(const PixelData& source, const PixelData& dest) 
+		{
+			UINT32 sourceElemSize = PixelUtil::getNumElemBytes(source.getFormat());
+			UINT32 destElemSize = PixelUtil::getNumElemBytes(dest.getFormat());
+
+			UINT8* sourceData = source.getData();
+			UINT8* destPtr = dest.getData();
+
+			// Get steps for traversing source data in 16/48 fixed point precision format
+			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
+			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
+			UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
+
+			// Contains 16/16 fixed point precision format. Most significant
+			// 16 bits will contain the coordinate in the source image, and the
+			// least significant 16 bits will contain the fractional part of the coordinate
+			// that will be used for determining the blend amount.
+			UINT32 temp = 0;
+
+			UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
+			for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ) 
+			{
+				temp = UINT32(curZ >> 32);
+				temp = (temp > 0x8000)? temp - 0x8000 : 0;
+				UINT32 sampleCoordZ1 = temp >> 16;
+				UINT32 sampleCoordZ2 = std::min(sampleCoordZ1 + 1, (UINT32)source.getDepth() - 1);
+				float sampleWeightZ = (temp & 0xFFFF) / 65536.0f; 
+
+				UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
+				for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY) 
+				{
+					temp = (UINT32)(curY >> 32);
+					temp = (temp > 0x8000)? temp - 0x8000 : 0;
+					UINT32 sampleCoordY1 = temp >> 16;
+					UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getHeight() - 1);
+					float sampleWeightY = (temp & 0xFFFF) / 65536.0f;
+
+					UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
+					for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX) 
+					{
+						temp = (UINT32)(curX >> 32);
+						temp = (temp > 0x8000)? temp - 0x8000 : 0;
+						UINT32 sampleCoordX1 = temp >> 16;
+						UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getWidth() - 1);
+						float sampleWeightX = (temp & 0xFFFF) / 65536.0f;
+
+						Color x1y1z1, x2y1z1, x1y2z1, x2y2z1;
+						Color x1y1z2, x2y1z2, x1y2z2, x2y2z2;
+
+#define GETSOURCEDATA(x, y, z) sourceData + sourceElemSize*((x)+(y)*source.getRowPitch() + (z)*source.getSlicePitch())
+
+						PixelUtil::unpackColor(&x1y1z1, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY1, sampleCoordZ1));
+						PixelUtil::unpackColor(&x2y1z1, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY1, sampleCoordZ1));
+						PixelUtil::unpackColor(&x1y2z1, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY2, sampleCoordZ1));
+						PixelUtil::unpackColor(&x2y2z1, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY2, sampleCoordZ1));
+						PixelUtil::unpackColor(&x1y1z2, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY1, sampleCoordZ2));
+						PixelUtil::unpackColor(&x2y1z2, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY1, sampleCoordZ2));
+						PixelUtil::unpackColor(&x1y2z2, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY2, sampleCoordZ2));
+						PixelUtil::unpackColor(&x2y2z2, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY2, sampleCoordZ2));
+#undef GETSOURCEDATA
+
+						Color accum =
+							x1y1z1 * ((1.0f - sampleWeightX)*(1.0f - sampleWeightY)*(1.0f - sampleWeightZ)) +
+							x2y1z1 * (        sampleWeightX *(1.0f - sampleWeightY)*(1.0f - sampleWeightZ)) +
+							x1y2z1 * ((1.0f - sampleWeightX)*        sampleWeightY *(1.0f - sampleWeightZ)) +
+							x2y2z1 * (        sampleWeightX *        sampleWeightY *(1.0f - sampleWeightZ)) +
+							x1y1z2 * ((1.0f - sampleWeightX)*(1.0f - sampleWeightY)*        sampleWeightZ ) +
+							x2y1z2 * (        sampleWeightX *(1.0f - sampleWeightY)*        sampleWeightZ ) +
+							x1y2z2 * ((1.0f - sampleWeightX)*        sampleWeightY *        sampleWeightZ ) +
+							x2y2z2 * (        sampleWeightX *        sampleWeightY *        sampleWeightZ );
+
+						PixelUtil::packColor(accum, dest.getFormat(), destPtr);
+
+						destPtr += destElemSize;
+					}
+
+					destPtr += destElemSize * dest.getRowSkip();
+				}
+
+				destPtr += destElemSize * dest.getSliceSkip();
+			}
+		}
+	};
+
+
+	/** 
+	 * Performs pixel data resampling using the box filter (linear). Only handles float RGB or RGBA pixel data (32 bits per
+	 * channel).
+	 */
+	struct LinearResampler_Float32 
+	{
+		static void scale(const PixelData& source, const PixelData& dest) 
+		{
+			UINT32 numSourceChannels = PixelUtil::getNumElemBytes(source.getFormat()) / sizeof(float);
+			UINT32 numDestChannels = PixelUtil::getNumElemBytes(dest.getFormat()) / sizeof(float);
+
+			float* sourceData = (float*)source.getData();
+			float* destPtr = (float*)dest.getData();
+
+			// Get steps for traversing source data in 16/48 fixed point precision format
+			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
+			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
+			UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
+
+			// Contains 16/16 fixed point precision format. Most significant
+			// 16 bits will contain the coordinate in the source image, and the
+			// least significant 16 bits will contain the fractional part of the coordinate
+			// that will be used for determining the blend amount.
+			UINT32 temp = 0;
+
+			UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
+			for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ) 
+			{
+				temp = (UINT32)(curZ >> 32);
+				temp = (temp > 0x8000)? temp - 0x8000 : 0;
+				UINT32 sampleCoordZ1 = temp >> 16;
+				UINT32 sampleCoordZ2 = std::min(sampleCoordZ1 + 1, (UINT32)source.getDepth() - 1);
+				float sampleWeightZ = (temp & 0xFFFF) / 65536.0f;
+
+				UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
+				for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY) 
+				{
+					temp = (UINT32)(curY >> 32);
+					temp = (temp > 0x8000)? temp - 0x8000 : 0;
+					UINT32 sampleCoordY1 = temp >> 16;
+					UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getHeight() - 1);
+					float sampleWeightY = (temp & 0xFFFF) / 65536.0f;
+
+					UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
+					for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX) 
+					{
+						temp = (UINT32)(curX >> 32);
+						temp = (temp > 0x8000)? temp - 0x8000 : 0;
+						UINT32 sampleCoordX1 = temp >> 16;
+						UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getWidth() - 1);
+						float sampleWeightX = (temp & 0xFFFF) / 65536.0f;
+
+						// process R,G,B,A simultaneously for cache coherence?
+						float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+
+
+#define ACCUM3(x,y,z,factor) \
+						{ float f = factor; \
+						UINT32 offset = (x + y*source.getRowPitch() + z*source.getSlicePitch())*numSourceChannels; \
+						accum[0] += sourceData[offset + 0] * f; accum[1] += sourceData[offset + 1] * f; \
+						accum[2] += sourceData[offset + 2] * f; }
+
+#define ACCUM4(x,y,z,factor) \
+						{ float f = factor; \
+						UINT32 offset = (x + y*source.getRowPitch() + z*source.getSlicePitch())*numSourceChannels; \
+						accum[0] += sourceData[offset + 0] * f; accum[1] += sourceData[offset + 1] * f; \
+						accum[2] += sourceData[offset + 2] * f; accum[3] += sourceData[offset + 3] * f; }
+
+						if (numSourceChannels == 3 || numDestChannels == 3)
+						{
+							// RGB
+							ACCUM3(sampleCoordX1, sampleCoordY1, sampleCoordZ1, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
+							ACCUM3(sampleCoordX2, sampleCoordY1, sampleCoordZ1, sampleWeightX		   * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
+							ACCUM3(sampleCoordX1, sampleCoordY2, sampleCoordZ1, (1.0f - sampleWeightX) * sampleWeightY			* (1.0f - sampleWeightZ));
+							ACCUM3(sampleCoordX2, sampleCoordY2, sampleCoordZ1, sampleWeightX		   * sampleWeightY		    * (1.0f - sampleWeightZ));
+							ACCUM3(sampleCoordX1, sampleCoordY1, sampleCoordZ2, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * sampleWeightZ);
+							ACCUM3(sampleCoordX2, sampleCoordY1, sampleCoordZ2, sampleWeightX		   * (1.0f - sampleWeightY) * sampleWeightZ);
+							ACCUM3(sampleCoordX1, sampleCoordY2, sampleCoordZ2, (1.0f - sampleWeightX) * sampleWeightY			* sampleWeightZ);
+							ACCUM3(sampleCoordX2, sampleCoordY2, sampleCoordZ2, sampleWeightX		   * sampleWeightY			* sampleWeightZ);
+							accum[3] = 1.0f;
+						}
+						else 
+						{
+							// RGBA
+							ACCUM4(sampleCoordX1, sampleCoordY1, sampleCoordZ1, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
+							ACCUM4(sampleCoordX2, sampleCoordY1, sampleCoordZ1, sampleWeightX		   * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
+							ACCUM4(sampleCoordX1, sampleCoordY2, sampleCoordZ1, (1.0f - sampleWeightX) * sampleWeightY			* (1.0f - sampleWeightZ));
+							ACCUM4(sampleCoordX2, sampleCoordY2, sampleCoordZ1, sampleWeightX		   * sampleWeightY			* (1.0f - sampleWeightZ));
+							ACCUM4(sampleCoordX1, sampleCoordY1, sampleCoordZ2, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * sampleWeightZ);
+							ACCUM4(sampleCoordX2, sampleCoordY1, sampleCoordZ2, sampleWeightX		   * (1.0f - sampleWeightY) * sampleWeightZ);
+							ACCUM4(sampleCoordX1, sampleCoordY2, sampleCoordZ2, (1.0f - sampleWeightX) * sampleWeightY			* sampleWeightZ);
+							ACCUM4(sampleCoordX2, sampleCoordY2, sampleCoordZ2, sampleWeightX		   * sampleWeightY			* sampleWeightZ);
+						}
+
+						memcpy(destPtr, accum, sizeof(float)*numDestChannels);
+
+#undef ACCUM3
+#undef ACCUM4
+
+						destPtr += numDestChannels;
+					}
+
+					destPtr += numDestChannels*dest.getRowSkip();
+				}
+
+				destPtr += numDestChannels*dest.getSliceSkip();
+			}
+		}
+	};
+
+
+
+	// byte linear resampler, does not do any format conversions.
+	// only handles pixel formats that use 1 byte per color channel.
+	// 2D only; punts 3D pixelboxes to default LinearResampler (slow).
+	// templated on bytes-per-pixel to allow compiler optimizations, such
+	// as unrolling loops and replacing multiplies with bitshifts
+
+	/**
+	 * Performs pixel data resampling using the box filter (linear). Only handles pixel formats with one byte per channel. 
+	 * Does not perform format conversion.
+	 *
+	 * @tparam	channels	Number of channels in the pixel format.
+	 */
+	template<UINT32 channels> struct LinearResampler_Byte 
+	{
+		static void scale(const PixelData& source, const PixelData& dest) 
+		{
+			// Only optimized for 2D
+			if (source.getDepth() > 1 || dest.getDepth() > 1) 
+			{
+				LinearResampler::scale(source, dest);
+				return;
+			}
+
+			UINT8* sourceData = (UINT8*)source.getData();
+			UINT8* destPtr = (UINT8*)dest.getData();
+
+			// Get steps for traversing source data in 16/48 fixed point precision format
+			UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
+			UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
+
+			// Contains 16/16 fixed point precision format. Most significant
+			// 16 bits will contain the coordinate in the source image, and the
+			// least significant 16 bits will contain the fractional part of the coordinate
+			// that will be used for determining the blend amount.
+			UINT32 temp;
+
+			UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
+			for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY)
+			{
+				temp = (UINT32)(curY >> 36);
+				temp = (temp > 0x800)? temp - 0x800: 0;
+				UINT32 sampleWeightY = temp & 0xFFF;
+				UINT32 sampleCoordY1 = temp >> 12;
+				UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getBottom() - source.getTop() - 1);
+
+				UINT32 sampleY1Offset = sampleCoordY1 * source.getRowPitch();
+				UINT32 sampleY2Offset = sampleCoordY2 * source.getRowPitch();
+
+				UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
+				for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX)
+				{
+					temp = (UINT32)(curX >> 36);
+					temp = (temp > 0x800)? temp - 0x800 : 0;
+					UINT32 sampleWeightX = temp & 0xFFF;
+					UINT32 sampleCoordX1 = temp >> 12;
+					UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getRight() - source.getLeft() - 1);
+
+					UINT32 sxfsyf = sampleWeightX*sampleWeightY;
+					for (UINT32 k = 0; k < channels; k++) 
+					{
+						UINT32 accum =
+							sourceData[(sampleCoordX1 + sampleY1Offset)*channels+k]*(0x1000000-(sampleWeightX<<12)-(sampleWeightY<<12)+sxfsyf) +
+							sourceData[(sampleCoordX2 + sampleY1Offset)*channels+k]*((sampleWeightX<<12)-sxfsyf) +
+							sourceData[(sampleCoordX1 + sampleY2Offset)*channels+k]*((sampleWeightY<<12)-sxfsyf) +
+							sourceData[(sampleCoordX2 + sampleY2Offset)*channels+k]*sxfsyf;
+
+						// Round up to byte size
+						*destPtr = (UINT8)((accum + 0x800000) >> 24);
+						destPtr++;
+					}
+				}
+				destPtr += channels*dest.getRowSkip();
+			}
+		}
+	};
+
+	/**	Data describing a pixel format. */
+    struct PixelFormatDescription 
+	{
+		const char* name; /**< Name of the format. */
+		UINT8 elemBytes; /**< Number of bytes one element (color value) uses. */
+		UINT32 flags; /**< PixelFormatFlags set by the pixel format. */
+        PixelComponentType componentType; /**< Data type of a single element of the format. */
+		UINT8 componentCount; /**< Number of elements in the format. */
+
+		UINT8 rbits, gbits, bbits, abits; /**< Number of bits per element in the format. */
+
+        UINT32 rmask, gmask, bmask, amask; /**< Masks used by packers/unpackers. */
+		UINT8 rshift, gshift, bshift, ashift; /**< Shifts used by packers/unpackers. */
+    };
+
+	/**	A list of all available pixel formats. */
+    PixelFormatDescription _pixelFormats[PF_COUNT] = {
+        {"PF_UNKNOWN",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        0,
+        /* Component type and count */
+        PCT_BYTE, 0,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+		//-----------------------------------------------------------------------
+		{"PF_R8",
+		/* Bytes per element */
+		1,
+		/* Flags */
+		0,
+		/* Component type and count */
+		PCT_BYTE, 1,
+		/* rbits, gbits, bbits, abits */
+		8, 0, 0, 0,
+		/* Masks and shifts */
+		0x000000FF, 0, 0, 0, 
+		0, 0, 0, 0
+		},
+		//-----------------------------------------------------------------------
+		{"PF_R8G8",
+		/* Bytes per element */
+		2,
+		/* Flags */
+		0,
+		/* Component type and count */
+		PCT_BYTE, 2,
+		/* rbits, gbits, bbits, abits */
+		8, 8, 0, 0,
+		/* Masks and shifts */
+		0x000000FF, 0x0000FF00, 0, 0, 
+		0, 8, 0, 0
+		},
+	//-----------------------------------------------------------------------
+        {"PF_R8G8B8",
+        /* Bytes per element */
+        3,  // 24 bit integer -- special
+        /* Flags */
+        PFF_NATIVEENDIAN,
+        /* Component type and count */
+        PCT_BYTE, 3,
+        /* rbits, gbits, bbits, abits */
+        8, 8, 8, 0,
+        /* Masks and shifts */
+        0x000000FF, 0x0000FF00, 0x00FF0000, 0,
+        0, 8, 16, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_B8G8R8",
+        /* Bytes per element */
+        3,  // 24 bit integer -- special
+        /* Flags */
+        PFF_NATIVEENDIAN,
+        /* Component type and count */
+        PCT_BYTE, 3,
+        /* rbits, gbits, bbits, abits */
+        8, 8, 8, 0,
+        /* Masks and shifts */
+        0x00FF0000, 0x0000FF00, 0x000000FF, 0,
+        16, 8, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_A8R8G8B8",
+        /* Bytes per element */
+        4,
+        /* Flags */
+        PFF_HASALPHA | PFF_NATIVEENDIAN,
+        /* Component type and count */
+        PCT_BYTE, 4,
+        /* rbits, gbits, bbits, abits */
+        8, 8, 8, 8,
+        /* Masks and shifts */
+        0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
+        8, 16, 24, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_A8B8G8R8",
+        /* Bytes per element */
+        4,
+        /* Flags */
+        PFF_HASALPHA | PFF_NATIVEENDIAN,
+        /* Component type and count */
+        PCT_BYTE, 4,
+        /* rbits, gbits, bbits, abits */
+        8, 8, 8, 8,
+        /* Masks and shifts */
+        0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
+        24, 16, 8, 0,
+        },
+	//-----------------------------------------------------------------------
+        {"PF_B8G8R8A8",
+        /* Bytes per element */
+        4,
+        /* Flags */
+        PFF_HASALPHA | PFF_NATIVEENDIAN,
+        /* Component type and count */
+        PCT_BYTE, 4,
+        /* rbits, gbits, bbits, abits */
+        8, 8, 8, 8,
+        /* Masks and shifts */
+        0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
+        16, 8, 0, 24
+        },
+	//-----------------------------------------------------------------------
+		{"PF_R8G8B8A8",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_HASALPHA | PFF_NATIVEENDIAN,
+		/* Component type and count */
+		PCT_BYTE, 4,
+		/* rbits, gbits, bbits, abits */
+		8, 8, 8, 8,
+		/* Masks and shifts */
+		0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
+		0, 8, 16, 24
+		},
+	//-----------------------------------------------------------------------
+		{"PF_X8R8G8B8",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_NATIVEENDIAN,
+		/* Component type and count */
+		PCT_BYTE, 3,
+		/* rbits, gbits, bbits, abits */
+		8, 8, 8, 0,
+		/* Masks and shifts */
+		0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
+		8, 16, 24, 0
+		},
+	//-----------------------------------------------------------------------
+		{"PF_X8B8G8R8",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_NATIVEENDIAN,
+		/* Component type and count */
+		PCT_BYTE, 3,
+		/* rbits, gbits, bbits, abits */
+		8, 8, 8, 0,
+		/* Masks and shifts */
+		0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
+		24, 16, 8, 0
+		},
+	//-----------------------------------------------------------------------
+		{"PF_R8G8B8X8",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_HASALPHA | PFF_NATIVEENDIAN,
+		/* Component type and count */
+		PCT_BYTE, 3,
+		/* rbits, gbits, bbits, abits */
+		8, 8, 8, 0,
+		/* Masks and shifts */
+		0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
+		0, 8, 16, 0
+		},
+	//-----------------------------------------------------------------------
+		{"PF_B8G8R8X8",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_HASALPHA | PFF_NATIVEENDIAN,
+		/* Component type and count */
+		PCT_BYTE, 3,
+		/* rbits, gbits, bbits, abits */
+		8, 8, 8, 0,
+		/* Masks and shifts */
+		0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
+		16, 8, 0, 0
+		},
+	//-----------------------------------------------------------------------
+        {"PF_BC1",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED | PFF_HASALPHA,
+        /* Component type and count */
+        PCT_BYTE, 3, // No alpha
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC1a",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED,
+        /* Component type and count */
+        PCT_BYTE, 3,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC2",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED | PFF_HASALPHA,
+        /* Component type and count */
+        PCT_BYTE, 4,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC3",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED | PFF_HASALPHA,
+        /* Component type and count */
+        PCT_BYTE, 4,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC4",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED,
+        /* Component type and count */
+        PCT_BYTE, 1,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC5",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED,
+        /* Component type and count */
+        PCT_BYTE, 2,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC6H",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED,
+        /* Component type and count */
+        PCT_FLOAT16, 3,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_BC7",
+        /* Bytes per element */
+        0,
+        /* Flags */
+        PFF_COMPRESSED | PFF_HASALPHA,
+        /* Component type and count */
+        PCT_BYTE, 4,
+        /* rbits, gbits, bbits, abits */
+        0, 0, 0, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+		{"PF_FLOAT16_R",
+		/* Bytes per element */
+		2,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT16, 1,
+		/* rbits, gbits, bbits, abits */
+		16, 0, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
+	//-----------------------------------------------------------------------
+		{"PF_FLOAT16_RG",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT16, 2,
+		/* rbits, gbits, bbits, abits */
+		16, 16, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
+	//-----------------------------------------------------------------------
+        {"PF_FLOAT16_RGB",
+        /* Bytes per element */
+        6,
+        /* Flags */
+        PFF_FLOAT,
+        /* Component type and count */
+        PCT_FLOAT16, 3,
+        /* rbits, gbits, bbits, abits */
+        16, 16, 16, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_FLOAT16_RGBA",
+        /* Bytes per element */
+        8,
+        /* Flags */
+        PFF_FLOAT | PFF_HASALPHA,
+        /* Component type and count */
+        PCT_FLOAT16, 4,
+        /* rbits, gbits, bbits, abits */
+        16, 16, 16, 16,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+		{"PF_FLOAT32_R",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT32, 1,
+		/* rbits, gbits, bbits, abits */
+		32, 0, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
+	//-----------------------------------------------------------------------
+		{"PF_FLOAT32_RG",
+		/* Bytes per element */
+		8,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT32, 2,
+		/* rbits, gbits, bbits, abits */
+		32, 32, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
+	//-----------------------------------------------------------------------
+        {"PF_FLOAT32_RGB",
+        /* Bytes per element */
+        12,
+        /* Flags */
+        PFF_FLOAT,
+        /* Component type and count */
+        PCT_FLOAT32, 3,
+        /* rbits, gbits, bbits, abits */
+        32, 32, 32, 0,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+        {"PF_FLOAT32_RGBA",
+        /* Bytes per element */
+        16,
+        /* Flags */
+        PFF_FLOAT | PFF_HASALPHA,
+        /* Component type and count */
+        PCT_FLOAT32, 4,
+        /* rbits, gbits, bbits, abits */
+        32, 32, 32, 32,
+        /* Masks and shifts */
+        0, 0, 0, 0, 0, 0, 0, 0
+        },
+	//-----------------------------------------------------------------------
+		{"PF_D32_S8X24",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_DEPTH | PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT32, 1,
+		/* rbits, gbits, bbits, abits */
+		0, 0, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		}, 
+	//-----------------------------------------------------------------------
+		{"PF_D24_S8",
+		/* Bytes per element */
+		8,
+		/* Flags */
+		PFF_DEPTH | PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT32, 2,
+		/* rbits, gbits, bbits, abits */
+		0, 0, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		}, 
+	//-----------------------------------------------------------------------
+		{"PF_D32",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_DEPTH | PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT32, 1,
+		/* rbits, gbits, bbits, abits */
+		0, 0, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		}, 
+	//-----------------------------------------------------------------------
+		{"PF_D16",
+		/* Bytes per element */
+		2,
+		/* Flags */
+		PFF_DEPTH | PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT16, 1,
+		/* rbits, gbits, bbits, abits */
+		0, 0, 0, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		}, 
+	//-----------------------------------------------------------------------
+		{ "PF_FLOAT_R11G11B10",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_PACKED_R11G11B10, 1,
+		/* rbits, gbits, bbits, abits */
+		11, 11, 10, 0,
+		/* Masks and shifts */
+		0x000007FF, 0x003FF800, 0xFFC00000, 0,
+		0, 11, 22, 0
+		},
+	//-----------------------------------------------------------------------
+		{ "PF_UNORM_R10G10B10A2",
+		/* Bytes per element */
+		4,
+		/* Flags */
+		PFF_FLOAT | PFF_HASALPHA,
+		/* Component type and count */
+		PCT_PACKED_R10G10B10A2, 1,
+		/* rbits, gbits, bbits, abits */
+		10, 10, 10, 2,
+		/* Masks and shifts */
+		0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000,
+		0, 10, 20, 30
+		},
+    };
+
+    static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
+    {
+        const int ord = (int)fmt;
+        assert(ord>=0 && ord<PF_COUNT);
+
+        return _pixelFormats[ord];
+    }
+
+	/**	Handles compression output from NVTT library for a single image. */
+	struct NVTTCompressOutputHandler : public nvtt::OutputHandler
+	{
+		NVTTCompressOutputHandler(UINT8* buffer, UINT32 sizeBytes)
+			:buffer(buffer), bufferWritePos(buffer), bufferEnd(buffer + sizeBytes)
+		{ }
+
+		virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override
+		{ }
+
+		virtual bool writeData(const void* data, int size) override
+		{
+			assert((bufferWritePos + size) <= bufferEnd);
+			memcpy(bufferWritePos, data, size);
+			bufferWritePos += size;
+
+			return true;
+		}
+
+		UINT8* buffer;
+		UINT8* bufferWritePos;
+		UINT8* bufferEnd;
+	};
+
+	/**	Handles output from NVTT library for a mip-map chain. */
+	struct NVTTMipmapOutputHandler : public nvtt::OutputHandler
+	{
+		NVTTMipmapOutputHandler(const Vector<PixelDataPtr>& buffers)
+			:buffers(buffers), bufferWritePos(nullptr), bufferEnd(nullptr)
+		{ }
+
+		virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
+		{ 
+			assert(miplevel >= 0 && miplevel < (int)buffers.size());
+			assert(size == buffers[miplevel]->getConsecutiveSize());
+
+			activeBuffer = buffers[miplevel];
+
+			bufferWritePos = activeBuffer->getData();
+			bufferEnd = bufferWritePos + activeBuffer->getConsecutiveSize();
+		}
+
+		virtual bool writeData(const void* data, int size)
+		{
+			assert((bufferWritePos + size) <= bufferEnd);
+			memcpy(bufferWritePos, data, size);
+			bufferWritePos += size;
+
+			return true;
+		}
+
+		Vector<PixelDataPtr> buffers;
+		PixelDataPtr activeBuffer;
+
+		UINT8* bufferWritePos;
+		UINT8* bufferEnd;
+	};
+
+	nvtt::Format toNVTTFormat(PixelFormat format)
+	{
+		switch (format)
+		{
+		case PF_BC1:
+			return nvtt::Format_BC1;
+		case PF_BC1a:
+			return nvtt::Format_BC1a;
+		case PF_BC2:
+			return nvtt::Format_BC2;
+		case PF_BC3:
+			return nvtt::Format_BC3;
+		case PF_BC4:
+			return nvtt::Format_BC4;
+		case PF_BC5:
+			return nvtt::Format_BC5;
+		}
+
+		// Unsupported format
+		return nvtt::Format_BC3;
+	}
+
+	nvtt::Quality toNVTTQuality(CompressionQuality quality)
+	{
+		switch (quality)
+		{
+		case CompressionQuality::Fastest:
+			return nvtt::Quality_Fastest;
+		case CompressionQuality::Highest:
+			return nvtt::Quality_Highest;
+		case CompressionQuality::Normal:
+			return nvtt::Quality_Normal;
+		case CompressionQuality::Production:
+			return nvtt::Quality_Normal;
+		}
+
+		// Unknown quality level
+		return nvtt::Quality_Normal;
+	}
+
+	nvtt::AlphaMode toNVTTAlphaMode(AlphaMode alphaMode)
+	{
+		switch (alphaMode)
+		{
+		case AlphaMode::None:
+			return nvtt::AlphaMode_None;
+		case AlphaMode::Premultiplied:
+			return nvtt::AlphaMode_Premultiplied;
+		case AlphaMode::Transparency:
+			return nvtt::AlphaMode_Transparency;
+		}
+
+		// Unknown alpha mode
+		return nvtt::AlphaMode_None;
+	}
+
+	nvtt::WrapMode toNVTTWrapMode(MipMapWrapMode wrapMode)
+	{
+		switch (wrapMode)
+		{
+		case MipMapWrapMode::Clamp:
+			return nvtt::WrapMode_Clamp;
+		case MipMapWrapMode::Mirror:
+			return nvtt::WrapMode_Mirror;
+		case MipMapWrapMode::Repeat:
+			return nvtt::WrapMode_Repeat;
+		}
+
+		// Unknown alpha mode
+		return nvtt::WrapMode_Mirror;
+	}
+
+    UINT32 PixelUtil::getNumElemBytes(PixelFormat format)
+    {
+        return getDescriptionFor(format).elemBytes;
+    }
+
+	UINT32 PixelUtil::getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
+	{
+		if(isCompressed(format))
+		{
+			switch(format)
+			{
+				// BC formats work by dividing the image into 4x4 blocks, then encoding each
+				// 4x4 block with a certain number of bytes. 
+				case PF_BC1:
+				case PF_BC1a:
+				case PF_BC4:
+					return ((width+3)/4)*((height+3)/4)*8 * depth;
+				case PF_BC2:
+				case PF_BC3:
+				case PF_BC5:
+				case PF_BC6H:
+				case PF_BC7:
+					return ((width+3)/4)*((height+3)/4)*16 * depth;
+
+				default:
+					BS_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
+			}
+		}
+		else
+		{
+			return width*height*depth*getNumElemBytes(format);
+		}
+
+		return 0;
+	}
+
+	void PixelUtil::getSizeForMipLevel(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevel,
+		UINT32& mipWidth, UINT32& mipHeight, UINT32& mipDepth)
+	{
+		mipWidth = width;
+		mipHeight = height;
+		mipDepth = depth;
+
+		for (UINT32 i = 0; i < mipLevel; i++)
+		{
+			if (mipWidth != 1) mipWidth /= 2;
+			if (mipHeight != 1) mipHeight /= 2;
+			if (mipDepth != 1) mipDepth /= 2;
+		}
+	}
+
+    UINT32 PixelUtil::getNumElemBits(PixelFormat format)
+    {
+        return getDescriptionFor(format).elemBytes * 8;
+    }
+
+    UINT32 PixelUtil::getFlags(PixelFormat format)
+    {
+        return getDescriptionFor(format).flags;
+    }
+
+    bool PixelUtil::hasAlpha(PixelFormat format)
+    {
+        return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
+    }
+
+    bool PixelUtil::isFloatingPoint(PixelFormat format)
+    {
+        return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
+    }
+
+    bool PixelUtil::isCompressed(PixelFormat format)
+    {
+        return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
+    }
+
+    bool PixelUtil::isDepth(PixelFormat format)
+    {
+        return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
+    }
+
+    bool PixelUtil::isNativeEndian(PixelFormat format)
+    {
+        return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
+    }
+
+	bool PixelUtil::isValidExtent(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
+	{
+		if(isCompressed(format))
+		{
+			switch(format)
+			{
+				case PF_BC1:
+				case PF_BC2:
+				case PF_BC1a:
+				case PF_BC3:
+				case PF_BC4:
+				case PF_BC5:
+				case PF_BC6H:
+				case PF_BC7:
+					return ((width & 3) == 0 && (height & 3) == 0 && depth == 1);
+				default:
+					return true;
+			}
+		}
+		else
+		{
+			return true;
+		}
+	}
+
+    void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
+    {
+        const PixelFormatDescription& des = getDescriptionFor(format);
+        rgba[0] = des.rbits;
+        rgba[1] = des.gbits;
+        rgba[2] = des.bbits;
+        rgba[3] = des.abits;
+    }
+
+	void PixelUtil::getBitMasks(PixelFormat format, UINT32 rgba[4])
+    {
+        const PixelFormatDescription& des = getDescriptionFor(format);
+        rgba[0] = des.rmask;
+        rgba[1] = des.gmask;
+        rgba[2] = des.bmask;
+        rgba[3] = des.amask;
+    }
+
+	void PixelUtil::getBitShifts(PixelFormat format, UINT8 rgba[4])
+	{
+		const PixelFormatDescription& des = getDescriptionFor(format);
+		rgba[0] = des.rshift;
+		rgba[1] = des.gshift;
+		rgba[2] = des.bshift;
+		rgba[3] = des.ashift;
+	}
+
+    String PixelUtil::getFormatName(PixelFormat srcformat)
+    {
+        return getDescriptionFor(srcformat).name;
+    }
+
+    bool PixelUtil::isAccessible(PixelFormat srcformat)
+    {
+        if (srcformat == PF_UNKNOWN)
+            return false;
+
+        UINT32 flags = getFlags(srcformat);
+        return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
+    }
+
+    PixelComponentType PixelUtil::getElementType(PixelFormat format)
+    {
+		const PixelFormatDescription& des = getDescriptionFor(format);
+        return des.componentType;
+    }
+
+	UINT32 PixelUtil::getNumElements(PixelFormat format)
+    {
+		const PixelFormatDescription& des = getDescriptionFor(format);
+        return des.componentCount;
+    }
+
+	UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
+	{
+		UINT32 count = 0;
+        if((width > 0) && (height > 0))
+        {
+            do {
+                if(width>1)		width = width/2;
+                if(height>1)	height = height/2;
+                if(depth>1)		depth = depth/2;
+                    
+                count ++;
+            } while(!(width == 1 && height == 1 && depth == 1));
+        }
+
+		return count;
+	}
+
+    void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
+    {
+        packColor(color.r, color.g, color.b, color.a, format, dest);
+    }
+
+    void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format,  void* dest)
+    {
+        const PixelFormatDescription &des = getDescriptionFor(format);
+
+        if(des.flags & PFF_NATIVEENDIAN) 
+		{
+            // Shortcut for integer formats packing
+            UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
+                ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
+                ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
+                ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
+
+            // And write to memory
+            Bitwise::intWrite(dest, des.elemBytes, value);
+        } 
+		else 
+		{
+            // Convert to float
+            packColor((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, format, dest);
+        }
+    }
+
+    void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
+    {
+        const PixelFormatDescription& des = getDescriptionFor(format);
+
+        if(des.flags & PFF_NATIVEENDIAN) 
+		{
+            // Do the packing
+            const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
+                ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
+                ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
+                ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
+
+            // And write to memory
+            Bitwise::intWrite(dest, des.elemBytes, value);
+        }
+		else 
+		{
+            switch(format)
+            {
+            case PF_FLOAT32_R:
+                ((float*)dest)[0] = r;
+                break;
+			case PF_FLOAT32_RG:
+				((float*)dest)[0] = r;
+				((float*)dest)[1] = g;
+				break;
+            case PF_FLOAT32_RGB:
+                ((float*)dest)[0] = r;
+                ((float*)dest)[1] = g;
+                ((float*)dest)[2] = b;
+                break;
+            case PF_FLOAT32_RGBA:
+                ((float*)dest)[0] = r;
+                ((float*)dest)[1] = g;
+                ((float*)dest)[2] = b;
+                ((float*)dest)[3] = a;
+                break;
+            case PF_FLOAT16_R:
+                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+                break;
+			case PF_FLOAT16_RG:
+				((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+				((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
+				break;
+            case PF_FLOAT16_RGB:
+                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+                ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
+                ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
+                break;
+            case PF_FLOAT16_RGBA:
+                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+                ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
+                ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
+                ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
+                break;
+			case PF_R8G8:
+				((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
+                ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
+				break;
+			case PF_R8:
+				((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
+				break;
+            default:
+                BS_EXCEPT(NotImplementedException, "Pack to " + getFormatName(format) + " not implemented");
+                break;
+            }
+        }
+    }
+    void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
+    {
+		unpackColor(&color->r, &color->g, &color->b, &color->a, format, src);
+    }
+
+    void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
+    {
+        const PixelFormatDescription &des = getDescriptionFor(format);
+
+        if(des.flags & PFF_NATIVEENDIAN) 
+		{
+            // Shortcut for integer formats unpacking
+            const UINT32 value = Bitwise::intRead(src, des.elemBytes);
+
+            *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
+            *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
+            *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
+
+            if(des.flags & PFF_HASALPHA)
+            {
+                *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
+            }
+            else
+            {
+                *a = 255; // No alpha, default a component to full
+            }
+        } 
+		else 
+		{
+            // Do the operation with the more generic floating point
+            float rr, gg, bb, aa;
+            unpackColor(&rr,&gg,&bb,&aa, format, src);
+
+            *r = (UINT8)Bitwise::floatToFixed(rr, 8);
+            *g = (UINT8)Bitwise::floatToFixed(gg, 8);
+            *b = (UINT8)Bitwise::floatToFixed(bb, 8);
+            *a = (UINT8)Bitwise::floatToFixed(aa, 8);
+        }
+    }
+
+    void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
+    {
+        const PixelFormatDescription &des = getDescriptionFor(format);
+
+        if(des.flags & PFF_NATIVEENDIAN) 
+		{
+            // Shortcut for integer formats unpacking
+            const unsigned int value = Bitwise::intRead(src, des.elemBytes);
+
+			*r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
+			*g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
+			*b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
+
+            if(des.flags & PFF_HASALPHA)
+            {
+                *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
+            }
+            else
+            {
+                *a = 1.0f; // No alpha, default a component to full
+            }
+        } 
+		else 
+		{
+            switch(format)
+            {
+            case PF_FLOAT32_R:
+                *r = *g = *b = ((float*)src)[0];
+                *a = 1.0f;
+                break;
+			case PF_FLOAT32_RG:
+				*r = ((float*)src)[0];
+				*g = *b = ((float*)src)[1];
+				*a = 1.0f;
+				break;
+            case PF_FLOAT32_RGB:
+                *r = ((float*)src)[0];
+                *g = ((float*)src)[1];
+                *b = ((float*)src)[2];
+                *a = 1.0f;
+                break;
+            case PF_FLOAT32_RGBA:
+                *r = ((float*)src)[0];
+                *g = ((float*)src)[1];
+                *b = ((float*)src)[2];
+                *a = ((float*)src)[3];
+                break;
+            case PF_FLOAT16_R:
+                *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
+                *a = 1.0f;
+                break;
+			case PF_FLOAT16_RG:
+				*r = Bitwise::halfToFloat(((UINT16*)src)[0]);
+				*g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
+				*a = 1.0f;
+				break;
+            case PF_FLOAT16_RGB:
+                *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
+                *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
+                *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
+                *a = 1.0f;
+                break;
+            case PF_FLOAT16_RGBA:
+                *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
+                *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
+                *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
+                *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
+                break;
+			case PF_R8G8:
+				*r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
+				*g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
+				*b = 0.0f;
+				*a = 1.0f;
+				break;
+			case PF_R8:
+				*r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
+				*g = 0.0f;
+				*b = 0.0f;
+				*a = 1.0f;
+				break;
+            default:
+                BS_EXCEPT(NotImplementedException, "Unpack from " + getFormatName(format) + " not implemented");
+                break;
+            }
+        }
+    }
+
+    void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
+    {
+        assert(src.getWidth() == dst.getWidth() &&
+			   src.getHeight() == dst.getHeight() &&
+			   src.getDepth() == dst.getDepth());
+
+		// Check for compressed formats, we don't support decompression
+		if(PixelUtil::isCompressed(src.getFormat()))
+		{
+			if(src.getFormat() == dst.getFormat())
+			{
+				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
+				return;
+			}
+			else
+			{
+				BS_EXCEPT(NotImplementedException, "This method can not be used to compress or decompress images");
+			}
+		}
+
+		// Check for compression
+		if (PixelUtil::isCompressed(dst.getFormat()))
+		{
+			if (src.getFormat() == dst.getFormat())
+			{
+				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
+				return;
+			}
+			else
+			{
+				CompressionOptions co;
+				co.format = dst.getFormat();
+				compress(src, dst, co);
+
+				return;
+			}
+		}
+
+        // The easy case
+        if(src.getFormat() == dst.getFormat()) 
+		{
+            // Everything consecutive?
+            if(src.isConsecutive() && dst.isConsecutive())
+            {
+				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
+                return;
+            }
+
+			const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
+			const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
+            UINT8 *srcptr = static_cast<UINT8*>(src.getData())
+                + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
+            UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
+				+ (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
+
+            // Calculate pitches+skips in bytes
+			const UINT32 srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
+			const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
+
+			const UINT32 dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
+			const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
+
+            // Otherwise, copy per row
+			const UINT32 rowSize = src.getWidth()*srcPixelSize;
+			for (UINT32 z = src.getFront(); z < src.getBack(); z++)
+            {
+                for(UINT32 y = src.getTop(); y < src.getBottom(); y++)
+                {
+					memcpy(dstptr, srcptr, rowSize);
+
+                    srcptr += srcRowPitchBytes;
+                    dstptr += dstRowPitchBytes;
+                }
+
+                srcptr += srcSliceSkipBytes;
+                dstptr += dstSliceSkipBytes;
+            }
+
+            return;
+        }
+
+		// Converting to PF_X8R8G8B8 is exactly the same as converting to
+		// PF_A8R8G8B8. (same with PF_X8B8G8R8 and PF_A8B8G8R8)
+		if(dst.getFormat() == PF_X8R8G8B8 || dst.getFormat() == PF_X8B8G8R8)
+		{
+			// Do the same conversion, with PF_A8R8G8B8, which has a lot of
+			// optimized conversions
+			PixelFormat tempFormat = dst.getFormat() == PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
+			PixelData tempdst(dst.getWidth(), dst.getHeight(), dst.getDepth(), tempFormat);
+			bulkPixelConversion(src, tempdst);
+			return;
+		}
+
+		// Converting from PF_X8R8G8B8 is exactly the same as converting from
+		// PF_A8R8G8B8, given that the destination format does not have alpha.
+		if((src.getFormat() == PF_X8R8G8B8 || src.getFormat() == PF_X8B8G8R8) && !hasAlpha(dst.getFormat()))
+		{
+			// Do the same conversion, with PF_A8R8G8B8, which has a lot of
+			// optimized conversions
+			PixelFormat tempFormat = src.getFormat()==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
+			PixelData tempsrc(src.getWidth(), src.getHeight(), src.getDepth(), tempFormat);
+			tempsrc.setExternalBuffer(src.getData());
+			bulkPixelConversion(tempsrc, dst);
+			return;
+		}
+
+		const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
+		const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
+        UINT8 *srcptr = static_cast<UINT8*>(src.getData())
+            + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
+        UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
+            + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
+		
+        // Calculate pitches+skips in bytes
+		const UINT32 srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
+		const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
+		const UINT32 dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
+		const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
+
+        // The brute force fallback
+        float r,g,b,a;
+		for (UINT32 z = src.getFront(); z<src.getBack(); z++)
+		{
+			for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
+            {
+				for (UINT32 x = src.getLeft(); x<src.getRight(); x++)
+                {
+                    unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
+                    packColor(r, g, b, a, dst.getFormat(), dstptr);
+
+                    srcptr += srcPixelSize;
+                    dstptr += dstPixelSize;
+                }
+
+                srcptr += srcRowSkipBytes;
+                dstptr += dstRowSkipBytes;
+            }
+
+            srcptr += srcSliceSkipBytes;
+            dstptr += dstSliceSkipBytes;
+        }
+    }
+
+	void PixelUtil::scale(const PixelData& src, PixelData& scaled, Filter filter)
+	{
+		assert(PixelUtil::isAccessible(src.getFormat()));
+		assert(PixelUtil::isAccessible(scaled.getFormat()));
+
+		PixelData temp;
+		switch (filter) 
+		{
+		default:
+		case FILTER_NEAREST:
+			if(src.getFormat() == scaled.getFormat()) 
+			{
+				// No intermediate buffer needed
+				temp = scaled;
+			}
+			else
+			{
+				// Allocate temporary buffer of destination size in source format 
+				temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
+				temp.allocateInternalBuffer();
+			}
+
+			// No conversion
+			switch (PixelUtil::getNumElemBytes(src.getFormat())) 
+			{
+			case 1: NearestResampler<1>::scale(src, temp); break;
+			case 2: NearestResampler<2>::scale(src, temp); break;
+			case 3: NearestResampler<3>::scale(src, temp); break;
+			case 4: NearestResampler<4>::scale(src, temp); break;
+			case 6: NearestResampler<6>::scale(src, temp); break;
+			case 8: NearestResampler<8>::scale(src, temp); break;
+			case 12: NearestResampler<12>::scale(src, temp); break;
+			case 16: NearestResampler<16>::scale(src, temp); break;
+			default:
+				// Never reached
+				assert(false);
+			}
+
+			if(temp.getData() != scaled.getData())
+			{
+				// Blit temp buffer
+				PixelUtil::bulkPixelConversion(temp, scaled);
+
+				temp.freeInternalBuffer();
+			}
+
+			break;
+
+		case FILTER_LINEAR:
+			switch (src.getFormat()) 
+			{
+			case PF_R8G8:
+			case PF_R8G8B8: case PF_B8G8R8:
+			case PF_R8G8B8A8: case PF_B8G8R8A8:
+			case PF_A8B8G8R8: case PF_A8R8G8B8:
+			case PF_X8B8G8R8: case PF_X8R8G8B8:
+				if(src.getFormat() == scaled.getFormat()) 
+				{
+					// No intermediate buffer needed
+					temp = scaled;
+				}
+				else
+				{
+					// Allocate temp buffer of destination size in source format 
+					temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
+					temp.allocateInternalBuffer();
+				}
+
+				// No conversion
+				switch (PixelUtil::getNumElemBytes(src.getFormat())) 
+				{
+				case 1: LinearResampler_Byte<1>::scale(src, temp); break;
+				case 2: LinearResampler_Byte<2>::scale(src, temp); break;
+				case 3: LinearResampler_Byte<3>::scale(src, temp); break;
+				case 4: LinearResampler_Byte<4>::scale(src, temp); break;
+				default:
+					// Never reached
+					assert(false);
+				}
+
+				if(temp.getData() != scaled.getData())
+				{
+					// Blit temp buffer
+					PixelUtil::bulkPixelConversion(temp, scaled);
+					temp.freeInternalBuffer();
+				}
+
+				break;
+			case PF_FLOAT32_RGB:
+			case PF_FLOAT32_RGBA:
+				if (scaled.getFormat() == PF_FLOAT32_RGB || scaled.getFormat() == PF_FLOAT32_RGBA)
+				{
+					// float32 to float32, avoid unpack/repack overhead
+					LinearResampler_Float32::scale(src, scaled);
+					break;
+				}
+				// Else, fall through
+			default:
+				// Fallback case, slow but works
+				LinearResampler::scale(src, scaled);
+			}
+			break;
+		}
+	}
+
+	void PixelUtil::applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp)
+	{
+		if(gamma == 1.0f)
+			return;
+
+		UINT32 stride = bpp >> 3;
+
+		for(size_t i = 0, j = size / stride; i < j; i++, buffer += stride)
+		{
+			float r = (float)buffer[0];
+			float g = (float)buffer[1];
+			float b = (float)buffer[2];
+
+			r = r * gamma;
+			g = g * gamma;
+			b = b * gamma;
+
+			float scale = 1.0f;
+			float tmp = 0.0f;
+
+			if(r > 255.0f && (tmp=(255.0f/r)) < scale)
+				scale = tmp;
+
+			if(g > 255.0f && (tmp=(255.0f/g)) < scale)
+				scale = tmp;
+
+			if(b > 255.0f && (tmp=(255.0f/b)) < scale)
+				scale = tmp;
+
+			r *= scale; 
+			g *= scale; 
+			b *= scale;
+
+			buffer[0] = (UINT8)r;
+			buffer[1] = (UINT8)g;
+			buffer[2] = (UINT8)b;
+		}
+	}
+
+	void PixelUtil::compress(const PixelData& src, PixelData& dst, const CompressionOptions& options)
+	{
+		if (!isCompressed(options.format))
+			BS_EXCEPT(InvalidParametersException, "Wanted format is not a compressed format.");
+
+		// Note: NVTT site has implementations for these two formats for when I decide to add them
+		if (options.format == PF_BC6H || options.format == PF_BC7)
+			BS_EXCEPT(InvalidParametersException, "Specified formats are not yet supported.");
+
+		if (src.getDepth() != 1)
+			BS_EXCEPT(InvalidParametersException, "3D textures are not supported.");
+
+		PixelFormat pf = options.format;
+
+		if (isCompressed(src.getFormat()))
+			BS_EXCEPT(InvalidParametersException, "Source data cannot be compressed.");
+
+		PixelData bgraData(src.getWidth(), src.getHeight(), 1, PF_B8G8R8A8);
+		bgraData.allocateInternalBuffer();
+		bulkPixelConversion(src, bgraData);
+
+		nvtt::InputOptions io;
+		io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
+		io.setMipmapData(bgraData.getData(), src.getWidth(), src.getHeight());
+		io.setMipmapGeneration(false);
+		io.setAlphaMode(toNVTTAlphaMode(options.alphaMode));
+		io.setNormalMap(options.isNormalMap);
+
+		if (options.isSRGB)
+			io.setGamma(2.2f, 2.2f);
+		else
+			io.setGamma(1.0f, 1.0f);
+
+		nvtt::CompressionOptions co;
+		co.setFormat(toNVTTFormat(options.format));
+		co.setQuality(toNVTTQuality(options.quality));
+		
+		NVTTCompressOutputHandler outputHandler(dst.getData(), dst.getConsecutiveSize());
+
+		nvtt::OutputOptions oo;
+		oo.setOutputHeader(false);
+		oo.setOutputHandler(&outputHandler);
+		
+		nvtt::Compressor compressor;
+		if (!compressor.process(io, co, oo))
+			BS_EXCEPT(InternalErrorException, "Compressing failed.");
+	}
+
+	Vector<PixelDataPtr> PixelUtil::genMipmaps(const PixelData& src, const MipMapGenOptions& options)
+	{
+		if (src.getDepth() != 1)
+			BS_EXCEPT(InvalidParametersException, "3D textures are not supported.");
+
+		// Note: Add support for floating point mips, no reason they shouldn't be supported other than
+		// nvtt doesn't support them natively
+		if (isCompressed(src.getFormat()) || isFloatingPoint(src.getFormat()))
+			BS_EXCEPT(InvalidParametersException, "Source data cannot be compressed or in floating point format.");
+
+		if (!Math::isPow2(src.getWidth()) || !Math::isPow2(src.getHeight()))
+			BS_EXCEPT(InvalidParametersException, "Texture width & height must be powers of 2.");
+
+		PixelData argbData(src.getWidth(), src.getHeight(), 1, PF_A8R8G8B8);
+		argbData.allocateInternalBuffer();
+		bulkPixelConversion(src, argbData);
+
+		nvtt::InputOptions io;
+		io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
+		io.setMipmapData(argbData.getData(), src.getWidth(), src.getHeight());
+		io.setMipmapGeneration(true);
+		io.setNormalMap(options.isNormalMap);
+		io.setNormalizeMipmaps(options.normalizeMipmaps);
+		io.setWrapMode(toNVTTWrapMode(options.wrapMode));
+
+		nvtt::CompressionOptions co;
+		co.setFormat(nvtt::Format_RGBA);
+		
+		UINT32 numMips = getMaxMipmaps(src.getWidth(), src.getHeight(), 1, src.getFormat());
+
+		Vector<PixelDataPtr> argbMipBuffers;
+
+		// Note: This can be done more effectively without creating so many temp buffers
+		// and working with the original formats directly, but it would complicate the code
+		// too much at the moment.
+		UINT32 curWidth = src.getWidth();
+		UINT32 curHeight = src.getHeight();
+		for (UINT32 i = 0; i < numMips; i++)
+		{
+			argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
+			argbMipBuffers.back()->allocateInternalBuffer();
+
+			if (curWidth > 1) 
+				curWidth = curWidth / 2;
+
+			if (curHeight > 1)
+				curHeight = curHeight / 2;
+		}
+
+		argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
+		argbMipBuffers.back()->allocateInternalBuffer();
+
+		NVTTMipmapOutputHandler outputHandler(argbMipBuffers);
+
+		nvtt::OutputOptions oo;
+		oo.setOutputHeader(false);
+		oo.setOutputHandler(&outputHandler);
+
+		nvtt::Compressor compressor;
+		if (!compressor.process(io, co, oo))
+			BS_EXCEPT(InternalErrorException, "Mipmap generation failed.");
+
+		argbData.freeInternalBuffer();
+
+		Vector<PixelDataPtr> outputMipBuffers;
+		for (UINT32 i = 0; i < (UINT32)argbMipBuffers.size(); i++)
+		{
+			PixelDataPtr argbBuffer = argbMipBuffers[i];
+			PixelDataPtr outputBuffer = bs_shared_ptr_new<PixelData>(argbBuffer->getWidth(), argbBuffer->getHeight(), 1, src.getFormat());
+			outputBuffer->allocateInternalBuffer();
+
+			bulkPixelConversion(*argbBuffer, *outputBuffer);
+			argbBuffer->freeInternalBuffer();
+
+			outputMipBuffers.push_back(outputBuffer);
+		}
+
+		return outputMipBuffers;
+	}
+}

+ 1 - 3
Source/BansheeD3D9RenderAPI/Include/BsD3D9VideoModeInfo.h

@@ -27,9 +27,7 @@ namespace BansheeEngine
 	public:
 		D3D9VideoOutputInfo(IDirect3D9* d3d9device, UINT32 adapterIdx);
 
-		/**
-		 * @brief	Gets a Win32 handle to the monitor referenced by this object.
-		 */
+		/**	Gets a Win32 handle to the monitor referenced by this object. */
 		HMONITOR getMonitorHandle() const { return mMonitorHandle; }
 
 	private:

+ 4 - 4
Source/BansheeEditor/Include/BsGizmoManager.h

@@ -209,11 +209,11 @@ namespace BansheeEngine
 		void update(const CameraPtr& camera);
 
 		/**
-		 * @brief	Queues all gizmos to be rendered for picking. Each gizmo is draw with a separate
-		 *			color so we can identify them later.
+		 * Queues all gizmos to be rendered for picking. Each gizmo is draw with a separate color so we can identify them
+		 * later.
 		 *
-		 * @param	camera				Camera to draw the gizmos on.
-		 * @param	idxToColorCallback	Callback that assigns a unique color to each gizmo index.
+		 * @param[in]	camera				Camera to draw the gizmos on.
+		 * @param[in]	idxToColorCallback	Callback that assigns a unique color to each gizmo index.
 		 *
 		 * @note	Internal method.
 		 */

+ 654 - 679
Source/BansheeEditor/Source/Win32/BsVSCodeEditor.cpp

@@ -1,680 +1,655 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "Win32/BsVSCodeEditor.h"
-#include <windows.h>
-#include <atlbase.h>
-#include "BsFileSystem.h"
-#include "BsDataStream.h"
-
-// Import EnvDTE
-#pragma warning(disable: 4278)
-#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
-#pragma warning(default: 4278)
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Reads a string value from the specified key in the registry.
-	 * 
-	 * @param	key				Registry key to read from.
-	 * @param	name			Identifier of the value to read from.
-	 * @param	value			Output value read from the key.
-	 * @param	defaultValue	Default value to return if the key or identifier doesn't exist.
-	 */
-	LONG getRegistryStringValue(HKEY hKey, const WString& name, WString& value, const WString& defaultValue)
-	{
-		value = defaultValue;
-
-		wchar_t strBuffer[512];
-		DWORD strBufferSize = sizeof(strBuffer);
-		ULONG result = RegQueryValueExW(hKey, name.c_str(), 0, nullptr, (LPBYTE)strBuffer, &strBufferSize);
-		if (result == ERROR_SUCCESS)
-			value = strBuffer;
-
-		return result;
-	}
-
-	/**
-	 * @brief	Contains data about a Visual Studio project.
-	 */
-	struct VSProjectInfo
-	{
-		WString GUID;
-		WString name;
-		Path path;
-	};
-
-	/**
-	 * @brief	Handles retrying of calls that fail to access Visual Studio. This is due to the weird nature of VS
-	 * 			when calling its methods from external code. If this message filter isn't registered some calls will
-	 * 			just fail silently.
-	 */
-	class VSMessageFilter : public IMessageFilter
-	{
-		DWORD __stdcall HandleInComingCall(DWORD dwCallType, HTASK htaskCaller, DWORD dwTickCount, LPINTERFACEINFO lpInterfaceInfo) override
-		{
-			return SERVERCALL_ISHANDLED;
-		}
-
-		DWORD __stdcall RetryRejectedCall(HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType) override
-		{
-			if (dwRejectType == SERVERCALL_RETRYLATER)
-			{
-				// Retry immediatey
-				return 99;
-			}
-			// Cancel the call
-			return -1;
-		}
-
-		DWORD __stdcall MessagePending(HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType) override
-		{
-			return PENDINGMSG_WAITDEFPROCESS;
-		}
-
-		/**
-		 * @brief	COM requirement. Returns instance of an interface of
-		 * 			provided type.
-		 */
-		HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObject) override
-		{
-			if(iid == IID_IDropTarget || iid == IID_IUnknown)
-			{
-				AddRef();
-				*ppvObject = this;
-				return S_OK;
-			}
-			else
-			{
-				*ppvObject = nullptr;
-				return E_NOINTERFACE;
-			}
-		}
-
-		/**
-		 * @brief	COM requirement. Increments objects
-		 * 			reference count.
-		 */
-		ULONG __stdcall AddRef() override
-		{
-			return InterlockedIncrement(&mRefCount);
-		} 
-
-		/**
-		 * @brief	COM requirement. Decreases the objects 
-		 * 			reference count and deletes the object
-		 * 			if its zero.
-		 */
-		ULONG __stdcall Release() override
-		{
-			LONG count = InterlockedDecrement(&mRefCount);
-
-			if(count == 0)
-			{
-				bs_delete(this);
-				return 0;
-			}
-			else
-			{
-				return count;
-			}
-		} 
-
-	private:
-		LONG mRefCount;
-	};
-
-	/**
-	 * @brief	Contains various helper classes for interacting with a Visual Studio instance
-	 *			running on this machine.
-	 */
-	class VisualStudio
-	{
-	private:
-		static const String SLN_TEMPLATE; /**< Template text used for a solution file. */
-		static const String PROJ_ENTRY_TEMPLATE; /**< Template text used for a project entry in a solution file. */
-		static const String PROJ_PLATFORM_TEMPLATE; /**< Template text used for platform specific information for a project entry in a solution file. */
-
-		static const String PROJ_TEMPLATE; /**< Template XML used for a project file. */
-		static const String REFERENCE_ENTRY_TEMPLATE; /**< Template XML used for a reference to another assembly entry by name. */
-		static const String REFERENCE_PROJECT_ENTRY_TEMPLATE; /**< Template XML used for a reference to another project entry. */
-		static const String REFERENCE_PATH_ENTRY_TEMPLATE; /**< Template XML used for a reference to another assembly entry by name and path. */
-		static const String CODE_ENTRY_TEMPLATE; /**< Template XML used for a single code file entry in a project. */
-		static const String NON_CODE_ENTRY_TEMPLATE; /**< Template XML used for a single non-code file entry in a project. */
-
-	public:
-		/**
-		 * @brief	Scans the running processes to find a running Visual Studio instance with the specified
-		 *			version and open solution.
-		 *
-		 * @param	clsID			Class ID of the specific Visual Studio version we are looking for.
-		 * @param	solutionPath	Path to the solution the instance needs to have open.
-		 *
-		 * @returns	DTE object that may be used to interact with the Visual Studio instance, or null if
-		 *			not found.
-		 */
-		static CComPtr<EnvDTE::_DTE> findRunningInstance(const CLSID& clsID, const Path& solutionPath)
-		{
-			CComPtr<IRunningObjectTable> runningObjectTable = nullptr;
-			if (FAILED(GetRunningObjectTable(0, &runningObjectTable)))
-				return nullptr;
-
-			CComPtr<IEnumMoniker> enumMoniker = nullptr;
-			if (FAILED(runningObjectTable->EnumRunning(&enumMoniker)))
-				return nullptr;
-
-			CComPtr<IMoniker> dteMoniker = nullptr;
-			if (FAILED(CreateClassMoniker(clsID, &dteMoniker)))
-				return nullptr;
-
-			CComBSTR bstrSolution(solutionPath.toWString(Path::PathType::Windows).c_str());
-			CComPtr<IMoniker> moniker;
-			ULONG count = 0;
-			while (enumMoniker->Next(1, &moniker, &count) == S_OK)
-			{
-				if (moniker->IsEqual(dteMoniker))
-				{
-					CComPtr<IUnknown> curObject = nullptr;
-					HRESULT result = runningObjectTable->GetObject(moniker, &curObject);
-					moniker = nullptr;
-
-					if (result != S_OK)
-						continue;
-
-					CComPtr<EnvDTE::_DTE> dte;
-					curObject->QueryInterface(__uuidof(EnvDTE::_DTE), (void**)&dte);
-
-					if (dte == nullptr)
-						continue;
-
-					CComPtr<EnvDTE::_Solution> solution;
-					if (FAILED(dte->get_Solution(&solution)))
-						continue;
-
-					CComBSTR fullName;
-					if (FAILED(solution->get_FullName(&fullName)))
-						continue;
-
-					if (fullName == bstrSolution)
-						return dte;
-				}
-			}
-
-			return nullptr;
-		}
-
-		/**
-		 * @brief	Opens a new Visual Studio instance of the specified version with the provided solution.
-		 *
-		 * @param	clsID			Class ID of the specific Visual Studio version to start.
-		 * @param	solutionPath	Path to the solution the instance needs to open.
-		 */
-		static CComPtr<EnvDTE::_DTE> openInstance(const CLSID& clsid, const Path& solutionPath)
-		{
-			CComPtr<IUnknown> newInstance = nullptr;
-			if (FAILED(::CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER, EnvDTE::IID__DTE, (LPVOID*)&newInstance)))
-				return nullptr;
-
-			CComPtr<EnvDTE::_DTE> dte;
-			newInstance->QueryInterface(__uuidof(EnvDTE::_DTE), (void**)&dte);
-
-			if (dte == nullptr)
-				return nullptr;
-
-			dte->put_UserControl(TRUE);
-
-			CComPtr<EnvDTE::_Solution> solution;
-			if (FAILED(dte->get_Solution(&solution)))
-				return nullptr;
-
-			CComBSTR bstrSolution(solutionPath.toWString(Path::PathType::Windows).c_str());
-			if (FAILED(solution->Open(bstrSolution)))
-				return nullptr;
-
-			// Wait until VS opens
-			UINT32 elapsed = 0;
-			while (elapsed < 10000)
-			{
-				EnvDTE::Window* window = nullptr;
-				if (SUCCEEDED(dte->get_MainWindow(&window)))
-					return dte;
-
-				Sleep(100);
-				elapsed += 100;
-			}
-
-			return nullptr;
-		}
-
-		/**
-		 * @brief	Opens a file on a specific line in a running Visual Studio instance.
-		 *
-		 * @param	dte			DTE object retrieved from "findRunningInstance" or "openInstance".
-		 * @param	filePath	Path of the file to open. File should be a part of the VS solution.
-		 * @param	line		Line on which to focus Visual Studio after the file is open.
-		 */
-		static bool openFile(CComPtr<EnvDTE::_DTE> dte, const Path& filePath, UINT32 line)
-		{
-			// Open file
-			CComPtr<EnvDTE::ItemOperations> itemOperations;
-			if (FAILED(dte->get_ItemOperations(&itemOperations)))
-				return false;
-
-			CComBSTR bstrFilePath(filePath.toWString(Path::PathType::Windows).c_str());
-			CComBSTR bstrKind(EnvDTE::vsViewKindPrimary);
-			CComPtr<EnvDTE::Window> window = nullptr;
-			if (FAILED(itemOperations->OpenFile(bstrFilePath, bstrKind, &window)))
-				return false;
-
-			// Scroll to line
-			CComPtr<EnvDTE::Document> activeDocument;
-			if (SUCCEEDED(dte->get_ActiveDocument(&activeDocument)))
-			{
-				CComPtr<IDispatch> selection;
-				if (SUCCEEDED(activeDocument->get_Selection(&selection)))
-				{
-					CComPtr<EnvDTE::TextSelection> textSelection;
-					if (SUCCEEDED(selection->QueryInterface(&textSelection)))
-					{
-						textSelection->GotoLine(line, TRUE);
-					}
-				}
-			}
-
-			// Bring the window in focus
-			window = nullptr;
-			if (SUCCEEDED(dte->get_MainWindow(&window)))
-			{
-				window->Activate();
-
-				HWND hWnd;
-				window->get_HWnd((LONG*)&hWnd);
-				SetForegroundWindow(hWnd);
-			}
-
-			return true;
-		}
-
-		/**
-		 * @brief	Generates a Visual Studio project GUID from the project name.
-		 */
-		static String getProjectGUID(const WString& projectName)
-		{
-			static const String guidTemplate = "{0}-{1}-{2}-{3}-{4}";
-			String hash = md5(projectName);
-
-			String output = StringUtil::format(guidTemplate, hash.substr(0, 8),
-				hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
-			StringUtil::toUpperCase(output);
-
-			return output;
-		}
-
-		/**
-		 * @brief	Builds the Visual Studio solution text (.sln) for the provided version, 
-		 *			using the provided solution data.
-		 *
-		 * @param	version	Visual Studio version for which we're generating the solution file.
-		 * @param	data	Data containing a list of projects and other information required to 
-		 *					build the solution text.
-		 *
-		 * @returns	Generated text of the solution file.
-		 */
-		static String writeSolution(VisualStudioVersion version, const CodeSolutionData& data)
-		{
-			struct VersionData
-			{
-				String formatVersion;
-			};
-
-			Map<VisualStudioVersion, VersionData> versionData =
-			{
-				{ VisualStudioVersion::VS2008, { "10.00" } },
-				{ VisualStudioVersion::VS2010, { "11.00" } },
-				{ VisualStudioVersion::VS2012, { "12.00" } },
-				{ VisualStudioVersion::VS2013, { "12.00" } },
-				{ VisualStudioVersion::VS2015, { "12.00" } }
-			};
-
-			StringStream projectEntriesStream;
-			StringStream projectPlatformsStream;
-			for (auto& project : data.projects)
-			{
-				String guid = getProjectGUID(project.name);
-				String projectName = toString(project.name);
-
-				projectEntriesStream << StringUtil::format(PROJ_ENTRY_TEMPLATE, projectName, projectName + ".csproj", guid);
-				projectPlatformsStream << StringUtil::format(PROJ_PLATFORM_TEMPLATE, guid);
-			}
-
-			String projectEntries = projectEntriesStream.str();
-			String projectPlatforms = projectPlatformsStream.str();
-
-			return StringUtil::format(SLN_TEMPLATE, versionData[version].formatVersion, projectEntries, projectPlatforms);
-		}
-
-		/**
-		 * @brief	Builds the Visual Studio project text (.csproj) for the provided version, 
-		 *			using the provided project data.
-		 *
-		 * @param	version		Visual Studio version for which we're generating the project file.
-		 * @param	projectData	Data containing a list of files, references and other information required to 
-		 *						build the project text.
-		 *
-		 * @returns	Generated text of the project file.
-		 */
-		static String writeProject(VisualStudioVersion version, const CodeProjectData& projectData)
-		{
-			struct VersionData
-			{
-				String toolsVersion;
-			};
-
-			Map<VisualStudioVersion, VersionData> versionData =
-			{
-				{ VisualStudioVersion::VS2008, { "3.5" } },
-				{ VisualStudioVersion::VS2010, { "4.0" } },
-				{ VisualStudioVersion::VS2012, { "4.0" } },
-				{ VisualStudioVersion::VS2013, { "12.0" } },
-				{ VisualStudioVersion::VS2015, { "13.0" } }
-			};
-
-			StringStream tempStream;
-			for (auto& codeEntry : projectData.codeFiles)
-				tempStream << StringUtil::format(CODE_ENTRY_TEMPLATE, codeEntry.toString());
-
-			String codeEntries = tempStream.str();
-			tempStream.str("");
-			tempStream.clear();
-
-			for (auto& nonCodeEntry : projectData.nonCodeFiles)
-				tempStream << StringUtil::format(NON_CODE_ENTRY_TEMPLATE, nonCodeEntry.toString());
-
-			String nonCodeEntries = tempStream.str();
-			tempStream.str("");
-			tempStream.clear();
-
-			for (auto& referenceEntry : projectData.assemblyReferences)
-			{
-				String referenceName = toString(referenceEntry.name);
-
-				if (referenceEntry.path.isEmpty())
-					tempStream << StringUtil::format(REFERENCE_ENTRY_TEMPLATE, referenceName);
-				else
-					tempStream << StringUtil::format(REFERENCE_PATH_ENTRY_TEMPLATE, referenceName, referenceEntry.path.toString());
-			}
-
-			String referenceEntries = tempStream.str();
-			tempStream.str("");
-			tempStream.clear();
-
-			for (auto& referenceEntry : projectData.projectReferences)
-			{
-				String referenceName = toString(referenceEntry.name);
-				String projectGUID = getProjectGUID(referenceEntry.name);
-
-				tempStream << StringUtil::format(REFERENCE_PROJECT_ENTRY_TEMPLATE, referenceName, projectGUID);
-			}
-
-			String projectReferenceEntries = tempStream.str();
-			tempStream.str("");
-			tempStream.clear();
-
-			tempStream << toString(projectData.defines);
-
-			String defines = tempStream.str();
-			String projectGUID = getProjectGUID(projectData.name);
-
-			return StringUtil::format(PROJ_TEMPLATE, versionData[version].toolsVersion, projectGUID, 
-				toString(projectData.name), defines, referenceEntries, projectReferenceEntries, codeEntries, nonCodeEntries);
-		}
-	};
-
-	const String VisualStudio::SLN_TEMPLATE =
-		R"(Microsoft Visual Studio Solution File, Format Version {0}
-# Visual Studio 2013
-VisualStudioVersion = 12.0.30723.0
-MinimumVisualStudioVersion = 10.0.40219.1{1}
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Release|Any CPU = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution{2}
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal
-)";
-
-	const String VisualStudio::PROJ_ENTRY_TEMPLATE =
-		R"(
-Project("\{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC\}") = "{0}", "{1}", "\{{2}\}"
-EndProject)";
-
-	const String VisualStudio::PROJ_PLATFORM_TEMPLATE =
-		R"(
-		\{{0}\}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		\{{0}\}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		\{{0}\}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		\{{0}\}.Release|Any CPU.Build.0 = Release|Any CPU)";
-
-	const String VisualStudio::PROJ_TEMPLATE =
-		R"literal(<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="{0}" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition = " '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition = " '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>\{{1}\}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace></RootNamespace>
-    <AssemblyName>{2}</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <BaseDirectory>Resources</BaseDirectory>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>Internal\\Temp\\Assemblies\\Debug\\</OutputPath>
-    <BaseIntermediateOutputPath>Internal\\Temp\\Assemblies\\</BaseIntermediateOutputPath>
-    <DefineConstants>DEBUG;TRACE;{3}</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel >
-  </PropertyGroup>
-  <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>Internal\\Temp\\Assemblies\\Release\\</OutputPath>
-	<BaseIntermediateOutputPath>Internal\\Temp\\Assemblies\\</BaseIntermediateOutputPath>
-    <DefineConstants>TRACE;{3}</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>{4}
-  </ItemGroup>
-  <ItemGroup>{5}
-  </ItemGroup>
-  <ItemGroup>{6}
-  </ItemGroup>
-  <ItemGroup>{7}
-  </ItemGroup>
-  <Import Project = "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"/>
-</Project>)literal";
-
-	const String VisualStudio::REFERENCE_ENTRY_TEMPLATE =
-		R"(
-    <Reference Include="{0}"/>)";
-
-	const String VisualStudio::REFERENCE_PATH_ENTRY_TEMPLATE =
-		R"(
-    <Reference Include="{0}">
-      <HintPath>{1}</HintPath>
-    </Reference>)";
-
-	const String VisualStudio::REFERENCE_PROJECT_ENTRY_TEMPLATE =
-		R"(
-    <ProjectReference Include="{0}.csproj">
-      <Project>\{{1}\}</Project>
-      <Name>{0}</Name>
-    </ProjectReference>)";
-
-	const String VisualStudio::CODE_ENTRY_TEMPLATE =
-		R"(
-    <Compile Include="{0}"/>)";
-
-	const String VisualStudio::NON_CODE_ENTRY_TEMPLATE =
-		R"(
-    <None Include="{0}"/>)";
-
-	VSCodeEditor::VSCodeEditor(VisualStudioVersion version, const Path& execPath, const WString& CLSID)
-		:mCLSID(CLSID), mExecPath(execPath), mVersion(version)
-	{
-		
-	}
-
-	void VSCodeEditor::openFile(const Path& solutionPath, const Path& filePath, UINT32 lineNumber) const
-	{
-		CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
-
-		CLSID clsID;
-		if (FAILED(CLSIDFromString(mCLSID.c_str(), &clsID)))
-		{
-			CoUninitialize();
-			return;
-		}
-
-		CComPtr<EnvDTE::_DTE> dte = VisualStudio::findRunningInstance(clsID, solutionPath);
-		if (dte == nullptr)
-			dte = VisualStudio::openInstance(clsID, solutionPath);
-
-		if (dte == nullptr)
-		{
-			CoUninitialize();
-			return;
-		}
-
-		VSMessageFilter* newFilter = new VSMessageFilter();
-		IMessageFilter* oldFilter;
-
-		CoRegisterMessageFilter(newFilter, &oldFilter);
-		EnvDTE::Window* window = nullptr;
-		if (SUCCEEDED(dte->get_MainWindow(&window)))
-			window->Activate();
-
-		VisualStudio::openFile(dte, filePath, lineNumber);
-		CoRegisterMessageFilter(oldFilter, nullptr);
-
-		CoUninitialize();
-	}
-
-	void VSCodeEditor::syncSolution(const CodeSolutionData& data, const Path& outputPath) const
-	{
-		String solutionString = VisualStudio::writeSolution(mVersion, data);
-		solutionString = StringUtil::replaceAll(solutionString, "\n", "\r\n");
-		Path solutionPath = outputPath;
-		solutionPath.append(data.name + L".sln");
-
-		for (auto& project : data.projects)
-		{
-			String projectString = VisualStudio::writeProject(mVersion, project);
-			projectString = StringUtil::replaceAll(projectString, "\n", "\r\n");
-
-			Path projectPath = outputPath;
-			projectPath.append(project.name + L".csproj");
-
-			DataStreamPtr projectStream = FileSystem::createAndOpenFile(projectPath);
-			projectStream->write(projectString.c_str(), projectString.size() * sizeof(String::value_type));
-			projectStream->close();
-		}
-
-		DataStreamPtr solutionStream = FileSystem::createAndOpenFile(solutionPath);
-		solutionStream->write(solutionString.c_str(), solutionString.size() * sizeof(String::value_type));
-		solutionStream->close();
-	}
-
-	VSCodeEditorFactory::VSCodeEditorFactory()
-		:mAvailableVersions(getAvailableVersions())
-	{ 
-		for (auto& version : mAvailableVersions)
-			mAvailableEditors.push_back(version.first);
-	}
-
-	Map<CodeEditorType, VSCodeEditorFactory::VSVersionInfo> VSCodeEditorFactory::getAvailableVersions() const
-	{
-#if BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64
-		bool is64bit = true;
-#else
-		bool is64bit = false;
-		IsWow64Process(GetCurrentProcess(), (PBOOL)&is64bit);
-#endif
-
-		WString registryKeyRoot;
-		if (is64bit)
-			registryKeyRoot = L"SOFTWARE\\Wow6432Node\\Microsoft"; 
-		else
-			registryKeyRoot = L"SOFTWARE\\Microsoft";
-
-		struct VersionData
-		{
-			CodeEditorType type;
-			WString registryKey;
-			WString name;
-			WString executable;
-		};
-
-		Map<VisualStudioVersion, VersionData> versionToVersionNumber =
-		{ 
-			{ VisualStudioVersion::VS2008, { CodeEditorType::VS2008, L"VisualStudio\\9.0", L"Visual Studio 2008", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2010, { CodeEditorType::VS2010, L"VisualStudio\\10.0", L"Visual Studio 2010", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2012, { CodeEditorType::VS2012, L"VisualStudio\\11.0", L"Visual Studio 2012", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2013, { CodeEditorType::VS2013, L"VisualStudio\\12.0", L"Visual Studio 2013", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2015, { CodeEditorType::VS2015, L"VisualStudio\\14.0", L"Visual Studio 2015", L"devenv.exe" } }
-		};
-
-		Map<CodeEditorType, VSVersionInfo> versionInfo;
-		for(auto version : versionToVersionNumber)
-		{
-			WString registryKey = registryKeyRoot + L"\\" + version.second.registryKey;
-
-			HKEY regKey;
-			LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey.c_str(), 0, KEY_READ, &regKey);
-			if (result != ERROR_SUCCESS)
-				continue;
-
-			WString installPath;
-			getRegistryStringValue(regKey, L"InstallDir", installPath, StringUtil::WBLANK);
-			if (installPath.empty())
-				continue;
-
-			WString clsID;
-			getRegistryStringValue(regKey, L"ThisVersionDTECLSID", clsID, StringUtil::WBLANK);
-
-			VSVersionInfo info;
-			info.name = version.second.name;
-			info.execPath = installPath.append(version.second.executable);
-			info.CLSID = clsID;
-			info.version = version.first;
-
-			versionInfo[version.second.type] = info;
-		}
-
-		return versionInfo;
-	}
-
-	CodeEditor* VSCodeEditorFactory::create(CodeEditorType type) const
-	{
-		auto findIter = mAvailableVersions.find(type);
-		if (findIter == mAvailableVersions.end())
-			return nullptr;
-
-		// TODO - Also create VSExpress and VSCommunity editors
-
-		return bs_new<VSCodeEditor>(findIter->second.version, findIter->second.execPath, findIter->second.CLSID);
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "Win32/BsVSCodeEditor.h"
+#include <windows.h>
+#include <atlbase.h>
+#include "BsFileSystem.h"
+#include "BsDataStream.h"
+
+// Import EnvDTE
+#pragma warning(disable: 4278)
+#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
+#pragma warning(default: 4278)
+
+namespace BansheeEngine
+{
+	/**
+	 * Reads a string value from the specified key in the registry.
+	 * 
+	 * @param[in]	key				Registry key to read from.
+	 * @param[in]	name			Identifier of the value to read from.
+	 * @param[in]	value			Output value read from the key.
+	 * @param[in]	defaultValue	Default value to return if the key or identifier doesn't exist.
+	 */
+	LONG getRegistryStringValue(HKEY hKey, const WString& name, WString& value, const WString& defaultValue)
+	{
+		value = defaultValue;
+
+		wchar_t strBuffer[512];
+		DWORD strBufferSize = sizeof(strBuffer);
+		ULONG result = RegQueryValueExW(hKey, name.c_str(), 0, nullptr, (LPBYTE)strBuffer, &strBufferSize);
+		if (result == ERROR_SUCCESS)
+			value = strBuffer;
+
+		return result;
+	}
+
+	/** Contains data about a Visual Studio project. */
+	struct VSProjectInfo
+	{
+		WString GUID;
+		WString name;
+		Path path;
+	};
+
+	/**
+	 * Handles retrying of calls that fail to access Visual Studio. This is due to the weird nature of VS when calling its
+	 * methods from external code. If this message filter isn't registered some calls will just fail silently.
+	 */
+	class VSMessageFilter : public IMessageFilter
+	{
+		DWORD __stdcall HandleInComingCall(DWORD dwCallType, HTASK htaskCaller, DWORD dwTickCount, LPINTERFACEINFO lpInterfaceInfo) override
+		{
+			return SERVERCALL_ISHANDLED;
+		}
+
+		DWORD __stdcall RetryRejectedCall(HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType) override
+		{
+			if (dwRejectType == SERVERCALL_RETRYLATER)
+			{
+				// Retry immediatey
+				return 99;
+			}
+			// Cancel the call
+			return -1;
+		}
+
+		DWORD __stdcall MessagePending(HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType) override
+		{
+			return PENDINGMSG_WAITDEFPROCESS;
+		}
+
+		/**	COM requirement. Returns instance of an interface of provided type. */
+		HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObject) override
+		{
+			if(iid == IID_IDropTarget || iid == IID_IUnknown)
+			{
+				AddRef();
+				*ppvObject = this;
+				return S_OK;
+			}
+			else
+			{
+				*ppvObject = nullptr;
+				return E_NOINTERFACE;
+			}
+		}
+
+		/** COM requirement. Increments objects reference count. */
+		ULONG __stdcall AddRef() override
+		{
+			return InterlockedIncrement(&mRefCount);
+		} 
+
+		/**	COM requirement. Decreases the objects reference count and deletes the object if its zero. */
+		ULONG __stdcall Release() override
+		{
+			LONG count = InterlockedDecrement(&mRefCount);
+
+			if(count == 0)
+			{
+				bs_delete(this);
+				return 0;
+			}
+			else
+			{
+				return count;
+			}
+		} 
+
+	private:
+		LONG mRefCount;
+	};
+
+	/** Contains various helper classes for interacting with a Visual Studio instance running on this machine. */
+	class VisualStudio
+	{
+	private:
+		static const String SLN_TEMPLATE; /**< Template text used for a solution file. */
+		static const String PROJ_ENTRY_TEMPLATE; /**< Template text used for a project entry in a solution file. */
+		static const String PROJ_PLATFORM_TEMPLATE; /**< Template text used for platform specific information for a project entry in a solution file. */
+
+		static const String PROJ_TEMPLATE; /**< Template XML used for a project file. */
+		static const String REFERENCE_ENTRY_TEMPLATE; /**< Template XML used for a reference to another assembly entry by name. */
+		static const String REFERENCE_PROJECT_ENTRY_TEMPLATE; /**< Template XML used for a reference to another project entry. */
+		static const String REFERENCE_PATH_ENTRY_TEMPLATE; /**< Template XML used for a reference to another assembly entry by name and path. */
+		static const String CODE_ENTRY_TEMPLATE; /**< Template XML used for a single code file entry in a project. */
+		static const String NON_CODE_ENTRY_TEMPLATE; /**< Template XML used for a single non-code file entry in a project. */
+
+	public:
+		/**
+		 * Scans the running processes to find a running Visual Studio instance with the specified version and open solution.
+		 *
+		 * @param[in]	clsID			Class ID of the specific Visual Studio version we are looking for.
+		 * @param[in]	solutionPath	Path to the solution the instance needs to have open.
+		 * @returns						DTE object that may be used to interact with the Visual Studio instance, or null if
+		 *								not found.
+		 */
+		static CComPtr<EnvDTE::_DTE> findRunningInstance(const CLSID& clsID, const Path& solutionPath)
+		{
+			CComPtr<IRunningObjectTable> runningObjectTable = nullptr;
+			if (FAILED(GetRunningObjectTable(0, &runningObjectTable)))
+				return nullptr;
+
+			CComPtr<IEnumMoniker> enumMoniker = nullptr;
+			if (FAILED(runningObjectTable->EnumRunning(&enumMoniker)))
+				return nullptr;
+
+			CComPtr<IMoniker> dteMoniker = nullptr;
+			if (FAILED(CreateClassMoniker(clsID, &dteMoniker)))
+				return nullptr;
+
+			CComBSTR bstrSolution(solutionPath.toWString(Path::PathType::Windows).c_str());
+			CComPtr<IMoniker> moniker;
+			ULONG count = 0;
+			while (enumMoniker->Next(1, &moniker, &count) == S_OK)
+			{
+				if (moniker->IsEqual(dteMoniker))
+				{
+					CComPtr<IUnknown> curObject = nullptr;
+					HRESULT result = runningObjectTable->GetObject(moniker, &curObject);
+					moniker = nullptr;
+
+					if (result != S_OK)
+						continue;
+
+					CComPtr<EnvDTE::_DTE> dte;
+					curObject->QueryInterface(__uuidof(EnvDTE::_DTE), (void**)&dte);
+
+					if (dte == nullptr)
+						continue;
+
+					CComPtr<EnvDTE::_Solution> solution;
+					if (FAILED(dte->get_Solution(&solution)))
+						continue;
+
+					CComBSTR fullName;
+					if (FAILED(solution->get_FullName(&fullName)))
+						continue;
+
+					if (fullName == bstrSolution)
+						return dte;
+				}
+			}
+
+			return nullptr;
+		}
+
+		/**
+		 * Opens a new Visual Studio instance of the specified version with the provided solution.
+		 *
+		 * @param[in]	clsID			Class ID of the specific Visual Studio version to start.
+		 * @param[in]	solutionPath	Path to the solution the instance needs to open.
+		 */
+		static CComPtr<EnvDTE::_DTE> openInstance(const CLSID& clsid, const Path& solutionPath)
+		{
+			CComPtr<IUnknown> newInstance = nullptr;
+			if (FAILED(::CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER, EnvDTE::IID__DTE, (LPVOID*)&newInstance)))
+				return nullptr;
+
+			CComPtr<EnvDTE::_DTE> dte;
+			newInstance->QueryInterface(__uuidof(EnvDTE::_DTE), (void**)&dte);
+
+			if (dte == nullptr)
+				return nullptr;
+
+			dte->put_UserControl(TRUE);
+
+			CComPtr<EnvDTE::_Solution> solution;
+			if (FAILED(dte->get_Solution(&solution)))
+				return nullptr;
+
+			CComBSTR bstrSolution(solutionPath.toWString(Path::PathType::Windows).c_str());
+			if (FAILED(solution->Open(bstrSolution)))
+				return nullptr;
+
+			// Wait until VS opens
+			UINT32 elapsed = 0;
+			while (elapsed < 10000)
+			{
+				EnvDTE::Window* window = nullptr;
+				if (SUCCEEDED(dte->get_MainWindow(&window)))
+					return dte;
+
+				Sleep(100);
+				elapsed += 100;
+			}
+
+			return nullptr;
+		}
+
+		/**
+		 * Opens a file on a specific line in a running Visual Studio instance.
+		 *
+		 * @param[in]	dte			DTE object retrieved from findRunningInstance() or openInstance().
+		 * @param[in]	filePath	Path of the file to open. File should be a part of the VS solution.
+		 * @param[in]	line		Line on which to focus Visual Studio after the file is open.
+		 */
+		static bool openFile(CComPtr<EnvDTE::_DTE> dte, const Path& filePath, UINT32 line)
+		{
+			// Open file
+			CComPtr<EnvDTE::ItemOperations> itemOperations;
+			if (FAILED(dte->get_ItemOperations(&itemOperations)))
+				return false;
+
+			CComBSTR bstrFilePath(filePath.toWString(Path::PathType::Windows).c_str());
+			CComBSTR bstrKind(EnvDTE::vsViewKindPrimary);
+			CComPtr<EnvDTE::Window> window = nullptr;
+			if (FAILED(itemOperations->OpenFile(bstrFilePath, bstrKind, &window)))
+				return false;
+
+			// Scroll to line
+			CComPtr<EnvDTE::Document> activeDocument;
+			if (SUCCEEDED(dte->get_ActiveDocument(&activeDocument)))
+			{
+				CComPtr<IDispatch> selection;
+				if (SUCCEEDED(activeDocument->get_Selection(&selection)))
+				{
+					CComPtr<EnvDTE::TextSelection> textSelection;
+					if (SUCCEEDED(selection->QueryInterface(&textSelection)))
+					{
+						textSelection->GotoLine(line, TRUE);
+					}
+				}
+			}
+
+			// Bring the window in focus
+			window = nullptr;
+			if (SUCCEEDED(dte->get_MainWindow(&window)))
+			{
+				window->Activate();
+
+				HWND hWnd;
+				window->get_HWnd((LONG*)&hWnd);
+				SetForegroundWindow(hWnd);
+			}
+
+			return true;
+		}
+
+		/**	Generates a Visual Studio project GUID from the project name. */
+		static String getProjectGUID(const WString& projectName)
+		{
+			static const String guidTemplate = "{0}-{1}-{2}-{3}-{4}";
+			String hash = md5(projectName);
+
+			String output = StringUtil::format(guidTemplate, hash.substr(0, 8),
+				hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
+			StringUtil::toUpperCase(output);
+
+			return output;
+		}
+
+		/**
+		 * Builds the Visual Studio solution text (.sln) for the provided version, using the provided solution data.
+		 *
+		 * @param[in]	version	Visual Studio version for which we're generating the solution file.
+		 * @param[in]	data	Data containing a list of projects and other information required to build the solution text.
+		 * @return				Generated text of the solution file.
+		 */
+		static String writeSolution(VisualStudioVersion version, const CodeSolutionData& data)
+		{
+			struct VersionData
+			{
+				String formatVersion;
+			};
+
+			Map<VisualStudioVersion, VersionData> versionData =
+			{
+				{ VisualStudioVersion::VS2008, { "10.00" } },
+				{ VisualStudioVersion::VS2010, { "11.00" } },
+				{ VisualStudioVersion::VS2012, { "12.00" } },
+				{ VisualStudioVersion::VS2013, { "12.00" } },
+				{ VisualStudioVersion::VS2015, { "12.00" } }
+			};
+
+			StringStream projectEntriesStream;
+			StringStream projectPlatformsStream;
+			for (auto& project : data.projects)
+			{
+				String guid = getProjectGUID(project.name);
+				String projectName = toString(project.name);
+
+				projectEntriesStream << StringUtil::format(PROJ_ENTRY_TEMPLATE, projectName, projectName + ".csproj", guid);
+				projectPlatformsStream << StringUtil::format(PROJ_PLATFORM_TEMPLATE, guid);
+			}
+
+			String projectEntries = projectEntriesStream.str();
+			String projectPlatforms = projectPlatformsStream.str();
+
+			return StringUtil::format(SLN_TEMPLATE, versionData[version].formatVersion, projectEntries, projectPlatforms);
+		}
+
+		/**
+		 * Builds the Visual Studio project text (.csproj) for the provided version, using the provided project data.
+		 *
+		 * @param[in]	version		Visual Studio version for which we're generating the project file.
+		 * @param[in]	projectData	Data containing a list of files, references and other information required to 
+		 *							build the project text.
+		 * @return					Generated text of the project file.
+		 */
+		static String writeProject(VisualStudioVersion version, const CodeProjectData& projectData)
+		{
+			struct VersionData
+			{
+				String toolsVersion;
+			};
+
+			Map<VisualStudioVersion, VersionData> versionData =
+			{
+				{ VisualStudioVersion::VS2008, { "3.5" } },
+				{ VisualStudioVersion::VS2010, { "4.0" } },
+				{ VisualStudioVersion::VS2012, { "4.0" } },
+				{ VisualStudioVersion::VS2013, { "12.0" } },
+				{ VisualStudioVersion::VS2015, { "13.0" } }
+			};
+
+			StringStream tempStream;
+			for (auto& codeEntry : projectData.codeFiles)
+				tempStream << StringUtil::format(CODE_ENTRY_TEMPLATE, codeEntry.toString());
+
+			String codeEntries = tempStream.str();
+			tempStream.str("");
+			tempStream.clear();
+
+			for (auto& nonCodeEntry : projectData.nonCodeFiles)
+				tempStream << StringUtil::format(NON_CODE_ENTRY_TEMPLATE, nonCodeEntry.toString());
+
+			String nonCodeEntries = tempStream.str();
+			tempStream.str("");
+			tempStream.clear();
+
+			for (auto& referenceEntry : projectData.assemblyReferences)
+			{
+				String referenceName = toString(referenceEntry.name);
+
+				if (referenceEntry.path.isEmpty())
+					tempStream << StringUtil::format(REFERENCE_ENTRY_TEMPLATE, referenceName);
+				else
+					tempStream << StringUtil::format(REFERENCE_PATH_ENTRY_TEMPLATE, referenceName, referenceEntry.path.toString());
+			}
+
+			String referenceEntries = tempStream.str();
+			tempStream.str("");
+			tempStream.clear();
+
+			for (auto& referenceEntry : projectData.projectReferences)
+			{
+				String referenceName = toString(referenceEntry.name);
+				String projectGUID = getProjectGUID(referenceEntry.name);
+
+				tempStream << StringUtil::format(REFERENCE_PROJECT_ENTRY_TEMPLATE, referenceName, projectGUID);
+			}
+
+			String projectReferenceEntries = tempStream.str();
+			tempStream.str("");
+			tempStream.clear();
+
+			tempStream << toString(projectData.defines);
+
+			String defines = tempStream.str();
+			String projectGUID = getProjectGUID(projectData.name);
+
+			return StringUtil::format(PROJ_TEMPLATE, versionData[version].toolsVersion, projectGUID, 
+				toString(projectData.name), defines, referenceEntries, projectReferenceEntries, codeEntries, nonCodeEntries);
+		}
+	};
+
+	const String VisualStudio::SLN_TEMPLATE =
+		R"(Microsoft Visual Studio Solution File, Format Version {0}
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1{1}
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution{2}
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
+)";
+
+	const String VisualStudio::PROJ_ENTRY_TEMPLATE =
+		R"(
+Project("\{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC\}") = "{0}", "{1}", "\{{2}\}"
+EndProject)";
+
+	const String VisualStudio::PROJ_PLATFORM_TEMPLATE =
+		R"(
+		\{{0}\}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		\{{0}\}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		\{{0}\}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		\{{0}\}.Release|Any CPU.Build.0 = Release|Any CPU)";
+
+	const String VisualStudio::PROJ_TEMPLATE =
+		R"literal(<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="{0}" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition = " '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition = " '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>\{{1}\}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace></RootNamespace>
+    <AssemblyName>{2}</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <BaseDirectory>Resources</BaseDirectory>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>Internal\\Temp\\Assemblies\\Debug\\</OutputPath>
+    <BaseIntermediateOutputPath>Internal\\Temp\\Assemblies\\</BaseIntermediateOutputPath>
+    <DefineConstants>DEBUG;TRACE;{3}</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel >
+  </PropertyGroup>
+  <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>Internal\\Temp\\Assemblies\\Release\\</OutputPath>
+	<BaseIntermediateOutputPath>Internal\\Temp\\Assemblies\\</BaseIntermediateOutputPath>
+    <DefineConstants>TRACE;{3}</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>{4}
+  </ItemGroup>
+  <ItemGroup>{5}
+  </ItemGroup>
+  <ItemGroup>{6}
+  </ItemGroup>
+  <ItemGroup>{7}
+  </ItemGroup>
+  <Import Project = "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"/>
+</Project>)literal";
+
+	const String VisualStudio::REFERENCE_ENTRY_TEMPLATE =
+		R"(
+    <Reference Include="{0}"/>)";
+
+	const String VisualStudio::REFERENCE_PATH_ENTRY_TEMPLATE =
+		R"(
+    <Reference Include="{0}">
+      <HintPath>{1}</HintPath>
+    </Reference>)";
+
+	const String VisualStudio::REFERENCE_PROJECT_ENTRY_TEMPLATE =
+		R"(
+    <ProjectReference Include="{0}.csproj">
+      <Project>\{{1}\}</Project>
+      <Name>{0}</Name>
+    </ProjectReference>)";
+
+	const String VisualStudio::CODE_ENTRY_TEMPLATE =
+		R"(
+    <Compile Include="{0}"/>)";
+
+	const String VisualStudio::NON_CODE_ENTRY_TEMPLATE =
+		R"(
+    <None Include="{0}"/>)";
+
+	VSCodeEditor::VSCodeEditor(VisualStudioVersion version, const Path& execPath, const WString& CLSID)
+		:mCLSID(CLSID), mExecPath(execPath), mVersion(version)
+	{
+		
+	}
+
+	void VSCodeEditor::openFile(const Path& solutionPath, const Path& filePath, UINT32 lineNumber) const
+	{
+		CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+
+		CLSID clsID;
+		if (FAILED(CLSIDFromString(mCLSID.c_str(), &clsID)))
+		{
+			CoUninitialize();
+			return;
+		}
+
+		CComPtr<EnvDTE::_DTE> dte = VisualStudio::findRunningInstance(clsID, solutionPath);
+		if (dte == nullptr)
+			dte = VisualStudio::openInstance(clsID, solutionPath);
+
+		if (dte == nullptr)
+		{
+			CoUninitialize();
+			return;
+		}
+
+		VSMessageFilter* newFilter = new VSMessageFilter();
+		IMessageFilter* oldFilter;
+
+		CoRegisterMessageFilter(newFilter, &oldFilter);
+		EnvDTE::Window* window = nullptr;
+		if (SUCCEEDED(dte->get_MainWindow(&window)))
+			window->Activate();
+
+		VisualStudio::openFile(dte, filePath, lineNumber);
+		CoRegisterMessageFilter(oldFilter, nullptr);
+
+		CoUninitialize();
+	}
+
+	void VSCodeEditor::syncSolution(const CodeSolutionData& data, const Path& outputPath) const
+	{
+		String solutionString = VisualStudio::writeSolution(mVersion, data);
+		solutionString = StringUtil::replaceAll(solutionString, "\n", "\r\n");
+		Path solutionPath = outputPath;
+		solutionPath.append(data.name + L".sln");
+
+		for (auto& project : data.projects)
+		{
+			String projectString = VisualStudio::writeProject(mVersion, project);
+			projectString = StringUtil::replaceAll(projectString, "\n", "\r\n");
+
+			Path projectPath = outputPath;
+			projectPath.append(project.name + L".csproj");
+
+			DataStreamPtr projectStream = FileSystem::createAndOpenFile(projectPath);
+			projectStream->write(projectString.c_str(), projectString.size() * sizeof(String::value_type));
+			projectStream->close();
+		}
+
+		DataStreamPtr solutionStream = FileSystem::createAndOpenFile(solutionPath);
+		solutionStream->write(solutionString.c_str(), solutionString.size() * sizeof(String::value_type));
+		solutionStream->close();
+	}
+
+	VSCodeEditorFactory::VSCodeEditorFactory()
+		:mAvailableVersions(getAvailableVersions())
+	{ 
+		for (auto& version : mAvailableVersions)
+			mAvailableEditors.push_back(version.first);
+	}
+
+	Map<CodeEditorType, VSCodeEditorFactory::VSVersionInfo> VSCodeEditorFactory::getAvailableVersions() const
+	{
+#if BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64
+		bool is64bit = true;
+#else
+		bool is64bit = false;
+		IsWow64Process(GetCurrentProcess(), (PBOOL)&is64bit);
+#endif
+
+		WString registryKeyRoot;
+		if (is64bit)
+			registryKeyRoot = L"SOFTWARE\\Wow6432Node\\Microsoft"; 
+		else
+			registryKeyRoot = L"SOFTWARE\\Microsoft";
+
+		struct VersionData
+		{
+			CodeEditorType type;
+			WString registryKey;
+			WString name;
+			WString executable;
+		};
+
+		Map<VisualStudioVersion, VersionData> versionToVersionNumber =
+		{ 
+			{ VisualStudioVersion::VS2008, { CodeEditorType::VS2008, L"VisualStudio\\9.0", L"Visual Studio 2008", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2010, { CodeEditorType::VS2010, L"VisualStudio\\10.0", L"Visual Studio 2010", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2012, { CodeEditorType::VS2012, L"VisualStudio\\11.0", L"Visual Studio 2012", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2013, { CodeEditorType::VS2013, L"VisualStudio\\12.0", L"Visual Studio 2013", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2015, { CodeEditorType::VS2015, L"VisualStudio\\14.0", L"Visual Studio 2015", L"devenv.exe" } }
+		};
+
+		Map<CodeEditorType, VSVersionInfo> versionInfo;
+		for(auto version : versionToVersionNumber)
+		{
+			WString registryKey = registryKeyRoot + L"\\" + version.second.registryKey;
+
+			HKEY regKey;
+			LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey.c_str(), 0, KEY_READ, &regKey);
+			if (result != ERROR_SUCCESS)
+				continue;
+
+			WString installPath;
+			getRegistryStringValue(regKey, L"InstallDir", installPath, StringUtil::WBLANK);
+			if (installPath.empty())
+				continue;
+
+			WString clsID;
+			getRegistryStringValue(regKey, L"ThisVersionDTECLSID", clsID, StringUtil::WBLANK);
+
+			VSVersionInfo info;
+			info.name = version.second.name;
+			info.execPath = installPath.append(version.second.executable);
+			info.CLSID = clsID;
+			info.version = version.first;
+
+			versionInfo[version.second.type] = info;
+		}
+
+		return versionInfo;
+	}
+
+	CodeEditor* VSCodeEditorFactory::create(CodeEditorType type) const
+	{
+		auto findIter = mAvailableVersions.find(type);
+		if (findIter == mAvailableVersions.end())
+			return nullptr;
+
+		// TODO - Also create VSExpress and VSCommunity editors
+
+		return bs_new<VSCodeEditor>(findIter->second.version, findIter->second.execPath, findIter->second.CLSID);
+	}
 }

+ 565 - 567
Source/BansheeEngine/Include/BsCamera.h

@@ -1,568 +1,566 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsIReflectable.h"
-#include "BsMatrix4.h"
-#include "BsVector3.h"
-#include "BsVector2.h"
-#include "BsVector2I.h"
-#include "BsAABox.h"
-#include "BsQuaternion.h"
-#include "BsRay.h"
-#include "BsCoreObject.h"
-#include "BsConvexVolume.h"
-
-namespace BansheeEngine 
-{
-	/** @cond INTERNAL */
-	/** @addtogroup Renderer-Engine
-	 *  @{
-	 */
-
-	/**	Projection type to use by the camera. */
-    enum ProjectionType
-    {
-		PT_ORTHOGRAPHIC, /**< Projection type where object size remains constant and parallel lines remain parallel. */
-		PT_PERSPECTIVE /**< Projection type that emulates human vision. Objects farther away appear smaller. */
-    };
-
-	/**	Clip planes that form the camera frustum (visible area). */
-    enum FrustumPlane
-    {
-        FRUSTUM_PLANE_NEAR = 0,
-        FRUSTUM_PLANE_FAR = 1,
-        FRUSTUM_PLANE_LEFT = 2,
-        FRUSTUM_PLANE_RIGHT = 3,
-        FRUSTUM_PLANE_TOP = 4,
-        FRUSTUM_PLANE_BOTTOM = 5
-    };
-
-	/**	Flags that describe a camera. */
-	enum class CameraFlags
-	{
-		/** 
-		 * This flag is a signal to the renderer that his camera will only render overlays and doesn't require depth   
-		 * buffer or multi-sampled render targets. This can improve performance and memory usage. 
-		 */
-		Overlay = 1
-	};
-
-	/** @} */
-	/** @addtogroup Implementation
-	 *  @{
-	 */
-
-	/**
-	 * Camera determines how is world geometry projected onto a 2D surface. You may position and orient it in space, set
-	 * options like aspect ratio and field or view and it outputs view and projection matrices required for rendering.
-	 */
-	class BS_EXPORT CameraBase
-    {
-    public:
-		virtual ~CameraBase() { }
-
-		/**
-		 * Sets the camera horizontal field of view. This determines how wide the camera viewing angle is along the
-		 * horizontal axis. Vertical FOV is calculated from the horizontal FOV and the aspect ratio.
-		 */
-        virtual void setHorzFOV(const Radian& fovy);
-
-		/**	Retrieves the camera horizontal field of view. */
-        virtual const Radian& getHorzFOV() const;
-
-		/**
-		 * Sets the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane will
-		 * not be rendered. Decreasing this value decreases depth buffer precision.
-		 */
-        virtual void setNearClipDistance(float nearDist);
-
-		/**
-		 * Retrieves the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane
-		 * will not be rendered. Decreasing this value decreases depth buffer precision.
-		 */
-        virtual float getNearClipDistance() const;
-
-		/**
-		 * Sets the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane will
-		 * not be rendered. Increasing this value decreases depth buffer precision.
-		 */
-        virtual void setFarClipDistance(float farDist);
-
-		/**
-		 * Retrieves the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane
-		 * will not be rendered. Increasing this value decreases depth buffer precision.
-		 */
-        virtual float getFarClipDistance() const;
-
-		/**	Sets the current viewport aspect ratio (width / height). */
-        virtual void setAspectRatio(float ratio);
-
-		/**	Returns current viewport aspect ratio (width / height). */
-        virtual float getAspectRatio() const;
-
-		/**	Sets camera world space position. */
-		virtual void setPosition(const Vector3& position);
-
-		/**	Retrieves camera world space position. */
-		virtual Vector3 getPosition() const { return mPosition; }
-
-		/**	Sets should the camera be rendered to or not. */
-		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
-		
-		/**	Gets whether the camera be rendered to or not. */
-		bool getIsActive() const { return mIsActive; }
-
-		/**
-		 * Gets the Z (forward) axis of the object, in world space.
-		 *
-		 * @return	Forward axis of the object.
-		 */
-		Vector3 getForward() const { return getRotation().rotate(-Vector3::UNIT_Z); }
-
-		/**	Sets camera world space rotation. */
-		virtual void setRotation(const Quaternion& rotation);
-
-		/**	Retrieves camera world space rotation. */
-		virtual Quaternion getRotation() const { return mRotation; }
-
-		/** Manually set the extents of the frustum that will be used when calculating the projection matrix. This will
-		 * prevents extents for being automatically calculated from aspect and near plane so it is up to the caller to keep
-		 * these values accurate.
-		 *
-		 * @param[in] left		The position where the left clip plane intersect the near clip plane, in view space.
-		 * @param[in] right		The position where the right clip plane intersect the near clip plane, in view space.
-		 * @param[in] top		The position where the top clip plane intersect the near clip plane, in view space.
-		 * @param[in] bottom	The position where the bottom clip plane intersect the near clip plane, in view space.
-		*/
-		virtual void setFrustumExtents(float left, float right, float top, float bottom);
-
-		/** 
-		 * Resets frustum extents so they are automatically derived from other values. This is only relevant if you have
-		 * previously set custom extents.
-		 */
-		virtual void resetFrustumExtents(); 
-
-		/** Returns the extents of the frustum in view space at the near plane. */
-		virtual void getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const;
-
-		/** 
-		 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. The layout
-		 * of this matrix depends on currently used render system.
-		 *
-		 * @note	
-		 * You should use this matrix when sending the matrix to the render system to make sure everything works 
-		 * consistently when other render systems are used.
-		 */
-        virtual const Matrix4& getProjectionMatrixRS() const;
-
-		/** 
-		 * Returns the inverse of the render-system specific projection matrix.
-		 *
-		 * @see		getProjectionMatrixRS
-		 */
-        virtual const Matrix4& getProjectionMatrixRSInv() const;
-
-		/** 
-		 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. Returned
-		 * matrix is standard following right-hand rules and depth range of [-1, 1]. 
-		 *
-		 * @note	
-		 * Different render systems will expect different projection matrix layouts, in which case use 
-		 * getProjectionMatrixRS().
-         */
-        virtual const Matrix4& getProjectionMatrix() const;
-
-		/** 
-		 * Returns the inverse of the projection matrix.
-		 *
-		 * @see		getProjectionMatrix
-		 */
-        virtual const Matrix4& getProjectionMatrixInv() const;
-
-		/** Gets the camera view matrix. Used for positioning/orienting the camera. */
-        virtual const Matrix4& getViewMatrix() const;
-
-		/** 
-		 * Returns the inverse of the view matrix.
-		 *
-		 * @see		getViewMatrix
-		 */
-		virtual const Matrix4& getViewMatrixInv() const;
-
-		/** 
-		 * Sets whether the camera should use the custom view matrix. When this is enabled camera will no longer calculate
-		 * its view matrix based on position/orientation and caller will be resonsible to keep the view matrix up to date.
-         */
-		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
-
-		/** Returns true if a custom view matrix is used. */
-		virtual bool isCustomViewMatrixEnabled() const { return mCustomViewMatrix; }
-		
-		/** 
-		 * Sets whether the camera should use the custom projection matrix. When this is enabled camera will no longer
-		 * calculate its projection matrix based on field of view, aspect and other parameters and caller will be resonsible
-		 * to keep the projection matrix up to date.
-         */
-		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
-
-		/** Returns true if a custom projection matrix is used. */
-		virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
-
-		/** Returns a convex volume representing the visible area of the camera, in local space. */
-        virtual const ConvexVolume& getFrustum() const;
-
-		/** Returns a convex volume representing the visible area of the camera, in world space. */
-        virtual ConvexVolume getWorldFrustum() const;
-
-		/**	Returns the bounding of the frustum. */
-        const AABox& getBoundingBox() const;
-
-		/**
-		 * Sets the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a 
-		 * 2D plane.
-		 */
-        virtual void setProjectionType(ProjectionType pt);
-
-		/**
-		 * Returns the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a
-		 * 2D plane.
-		 */
-        virtual ProjectionType getProjectionType() const;
-
-		/**
-		 * Sets the orthographic window height, for use with orthographic rendering only. 
-		 *
-		 * @param[in]	w	Width of the window in world units.
-		 * @param[in]	h	Height of the window in world units.
-		 *
-		 * @note	
-		 * Calling this method will recalculate the aspect ratio, use setOrthoWindowHeight() or setOrthoWindowWidth() alone
-		 * if you wish to preserve the aspect ratio but just fit one or other dimension to a particular size.
-		 */
-		virtual void setOrthoWindow(float w, float h);
-
-		/**
-		 * Sets the orthographic window height, for use with orthographic rendering only. 
-		 *
-		 * @param[in]	h	Height of the window in world units.
-		 *
-		 * @note	The width of the window will be calculated from the aspect ratio. 
-		 */
-		virtual void setOrthoWindowHeight(float h);
-
-		/**
-		 * Sets the orthographic window width, for use with orthographic rendering only. 
-		 *
-		 * @param[in]	w	Width of the window in world units.
-		 *
-		 * @note	The height of the window will be calculated from the aspect ratio. 
-		 */
-		virtual void setOrthoWindowWidth(float w);
-
-		/** Gets the orthographic window width in world units, for use with orthographic rendering only. */
-		virtual float getOrthoWindowHeight() const;
-
-		/**
-		 * Gets the orthographic window width in world units, for use with orthographic rendering only. 
-		 *
-		 * @note	This is calculated from the orthographic height and the aspect ratio.
-		 */
-		virtual float getOrthoWindowWidth() const;
-
-		/**
-		 * Gets a priority that determines in which orders the cameras are rendered. This only applies to cameras rendering
-		 * to the same render target. 
-		 */
-		INT32 getPriority() const { return mPriority; }
-
-		/**
-		 * Sets a priority that determines in which orders the cameras are rendered. This only applies to cameras rendering
-		 * to the same render target. 
-		 *
-		 * @param[in]	priority	The priority. Higher value means the camera will be rendered sooner.
-		 */
-		void setPriority(INT32 priority) { mPriority = priority; _markCoreDirty(); }
-
-		/**	Retrieves layer bitfield that is used when determining which object should the camera render. */
-		UINT64 getLayers() const { return mLayers; }
-
-		/**	Sets layer bitfield that is used when determining which object should the camera render. */
-		void setLayers(UINT64 layers) { mLayers = layers; _markCoreDirty(); }
-
-		/**	Retrieves flags that define the camera. */
-		CameraFlags getFlags() const { return (CameraFlags)mCameraFlags; }
-
-		/**
-		 * @brief	Sets flags that define the camera.
-		 */
-		void setFlags(const CameraFlags& flags) { mCameraFlags = (UINT32)flags; _markCoreDirty(); }
-
-		/**
-		 * Converts a point in world space to screen coordinates (in pixels corresponding to the render target attached to
-		 * the camera).
-		 */
-		Vector2I worldToScreenPoint(const Vector3& worldPoint) const;
-
-		/**	Converts a point in world space to normalized device coordinates (in [-1, 1] range). */
-		Vector2 worldToNdcPoint(const Vector3& worldPoint) const;
-
-		/** Converts a point in world space to point relative to camera's coordinate system (view space). */
-		Vector3 worldToViewPoint(const Vector3& worldPoint) const;
-
-		/**
-		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point in
-		 * world space.
-		 *
-		 * @param[in]	screenPoint	Point to transform.
-		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
-		 *							origin to the point on the near plane.
-		 */
-		Vector3 screenToWorldPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
-
-		/**
-		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point
-		 * relative to camera's coordinate system (view space).
-		 *
-		 * @param[in]	screenPoint	Point to transform.
-		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
-		 *							origin to the point on the near plane.
-		 */
-		Vector3 screenToViewPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
-
-		/**
-		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to normalized 
-		 * device coordinates (in [-1, 1] range).
-		 */
-		Vector2 screenToNdcPoint(const Vector2I& screenPoint) const;
-
-		/** Converts a point relative to camera's coordinate system (view space) into a point in world space. */
-		Vector3 viewToWorldPoint(const Vector3& viewPoint) const;
-
-		/**
-		 * Converts a point relative to camera's coordinate system (view space) into a point in screen space (pixels 
-		 * corresponding to render target attached to the camera).
-		 */
-		Vector2I viewToScreenPoint(const Vector3& viewPoint) const;
-
-		/**
-		 * Converts a point relative to camera's coordinate system (view space) into normalized device coordinates 
-		 * (in [-1, 1] range).
-		 */
-		Vector2 viewToNdcPoint(const Vector3& viewPoint) const;
-
-		/**
-		 * Converts a point in normalized device coordinates ([-1, 1] range) to a point in world space.
-		 *
-		 * @param[in]	ndcPoint	Point to transform.
-		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
-		 *							origin to the point on the near plane.
-		 */
-		Vector3 ndcToWorldPoint(const Vector2& ndcPoint, float depth = 0.5f) const;
-
-		/**
-		 * Converts a point in normalized device coordinates ([-1, 1] range) to a point relative to camera's coordinate system
-		 * (view space).
-		 *
-		 * @param[in]	ndcPoint	Point to transform.
-		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
-		 *							origin to the point on the near plane.
-		 */
-		Vector3 ndcToViewPoint(const Vector2& ndcPoint, float depth = 0.5f) const;
-
-		/**
-		 * Converts a point in normalized device coordinates ([-1, 1] range) to a point in screen space (pixels corresponding
-		 * to render target attached to the camera).
-		 */
-		Vector2I ndcToScreenPoint(const Vector2& ndcPoint) const;
-
-		/**
-		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a ray in world
-		 * space originating at the selected point on the camera near plane.
-		 */
-		Ray screenPointToRay(const Vector2I& screenPoint) const;
-
-		/**	Projects a point from view to normalized device space. */
-		Vector3 projectPoint(const Vector3& point) const;
-
-		/**	Un-projects a point in normalized device space to view space. */
-		Vector3 unprojectPoint(const Vector3& point) const;
-
-        static const float INFINITE_FAR_PLANE_ADJUST; /**< Small constant used to reduce far plane projection to avoid inaccuracies. */
-
-	protected:
-		CameraBase();
-
-		/**	Calculate projection parameters that are used when constructing the projection matrix. */
-		virtual void calcProjectionParameters(float& left, float& right, float& bottom, float& top) const;
-
-		/**	Recalculate frustum if dirty. */
-		virtual void updateFrustum() const;
-
-		/**	Recalculate frustum planes if dirty. */
-		virtual void updateFrustumPlanes() const;
-
-		/**
-		 * Update view matrix from parent position/orientation.
-		 *
-		 * @note	Does nothing when custom view matrix is set.
-		 */
-		virtual void updateView() const;
-
-		/**	Checks if the frustum requires updating. */
-		virtual bool isFrustumOutOfDate() const;
-
-		/**	Notify camera that the frustum requires to be updated. */
-		virtual void invalidateFrustum() const;
-
-		/**	Returns a rectangle that defines the viewport position and size, in pixels. */
-		virtual Rect2I getViewportRect() const = 0;
-
-		/** @copydoc CoreObject::markCoreDirty */
-		virtual void _markCoreDirty() { }
-
-    protected:
-		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
-		UINT32 mCameraFlags; /**< Flags that further determine type of camera. */
-
-		Vector3 mPosition; /**< World space position. */
-		Quaternion mRotation; /**< World space rotation. */
-		bool mIsActive; /**< Is camera being rendered to. */
-
-		ProjectionType mProjType; /**< Type of camera projection. */
-		Radian mHorzFOV; /**< Horizontal field of view represents how wide is the camera angle. */
-		float mFarDist; /**< Clip any objects further than this. Larger value decreases depth precision at smaller depths. */
-		float mNearDist; /**< Clip any objects close than this. Smaller value decreases depth precision at larger depths. */
-		float mAspect; /**< Width/height viewport ratio. */
-		float mOrthoHeight; /**< Height in world units used for orthographic cameras. */
-		INT32 mPriority; /**< Determines in what order will the camera be rendered. Higher priority means the camera will be rendered sooner. */
-
-		bool mCustomViewMatrix; /**< Is custom view matrix set. */
-		bool mCustomProjMatrix; /**< Is custom projection matrix set. */
-
-		bool mFrustumExtentsManuallySet; /**< Are frustum extents manually set. */
-
-		mutable Matrix4 mProjMatrixRS; /**< Cached render-system specific projection matrix. */
-		mutable Matrix4 mProjMatrix; /**< Cached projection matrix that determines how are 3D points projected to a 2D viewport. */
-		mutable Matrix4 mViewMatrix; /**< Cached view matrix that determines camera position/orientation. */
-		mutable Matrix4 mProjMatrixRSInv;
-		mutable Matrix4 mProjMatrixInv;
-		mutable Matrix4 mViewMatrixInv;
-
-		mutable ConvexVolume mFrustum; /**< Main clipping planes describing cameras visible area. */
-		mutable bool mRecalcFrustum; /**< Should frustum be recalculated. */
-		mutable bool mRecalcFrustumPlanes; /**< Should frustum planes be recalculated. */
-		mutable bool mRecalcView; /**< Should view matrix be recalculated. */
-		mutable float mLeft, mRight, mTop, mBottom; /**< Frustum extents. */
-		mutable AABox mBoundingBox; /**< Frustum bounding box. */
-     };
-
-	/** @} */
-	/** @addtogroup Renderer-Engine
-	 *  @{
-	 */
-
-	/** @copydoc CameraBase */
-	class BS_EXPORT CameraCore : public CoreObjectCore, public CameraBase
-	{
-	public:
-		~CameraCore();
-
-		/**	Returns the viewport used by the camera. */	
-		SPtr<ViewportCore> getViewport() const { return mViewport; }
-
-	protected:
-		friend class Camera;
-
-		CameraCore(SPtr<RenderTargetCore> target = nullptr,
-			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
-
-		CameraCore(const SPtr<ViewportCore>& viewport);
-
-		/** @copydoc CoreObjectCore::initialize */
-		void initialize() override;
-
-		/** @copydoc CameraBase */
-		virtual Rect2I getViewportRect() const override;
-
-		/** @copydoc CoreObject::syncToCore */
-		void syncToCore(const CoreSyncData& data) override;
-
-		SPtr<ViewportCore> mViewport;
-	};
-
-	/** @copydoc CameraBase */
-	class BS_EXPORT Camera : public IReflectable, public CoreObject, public CameraBase
-    {
-    public:
-		/**	Returns the viewport used by the camera. */	
-		ViewportPtr getViewport() const { return mViewport; }
-
-		/**
-		 * Determines whether this is the main application camera. Main camera controls the final render surface that is
-		 * displayed to the user.
-		 */	
-		bool isMain() const { return mMain; }
-
-		/**
-		 * Marks or unmarks this camera as the main application camera. Main camera controls the final render surface that
-		 * is displayed to the user.
-		 */	
-		void setMain(bool main) { mMain = main; }
-
-		/** Retrieves an implementation of a camera handler usable only from the core thread. */
-		SPtr<CameraCore> getCore() const;
-
-		/**	Creates a new camera that renders to the specified portion of the provided render target. */
-		static CameraPtr create(RenderTargetPtr target = nullptr,
-			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
-
-		/** @cond INTERNAL */
-
-		/**	Returns the hash value that can be used to identify if the internal data needs an update. */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
-
-		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
-
-		/** @endcond */
-
-	protected:
-		Camera(RenderTargetPtr target = nullptr,
-			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
-
-		/** @copydoc CameraBase */
-		virtual Rect2I getViewportRect() const override;
-
-		/** @copydoc CoreObject::createCore */
-		SPtr<CoreObjectCore> createCore() const override;
-
-		/** @copydoc CoreObject::markCoreDirty */
-		void _markCoreDirty() override;
-
-		/** @copydoc CoreObject::syncToCore */
-		CoreSyncData syncToCore(FrameAlloc* allocator) override;
-
-		/** @copydoc CoreObject::getCoreDependencies */
-		void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
-
-		/**	Creates a new camera without initializing it. */
-		static CameraPtr createEmpty();
-
-		ViewportPtr mViewport; /**< Viewport that describes 2D rendering surface. */
-		bool mMain;
-		UINT32 mLastUpdateHash;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class CameraRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-     };
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsIReflectable.h"
+#include "BsMatrix4.h"
+#include "BsVector3.h"
+#include "BsVector2.h"
+#include "BsVector2I.h"
+#include "BsAABox.h"
+#include "BsQuaternion.h"
+#include "BsRay.h"
+#include "BsCoreObject.h"
+#include "BsConvexVolume.h"
+
+namespace BansheeEngine 
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Renderer-Engine
+	 *  @{
+	 */
+
+	/**	Projection type to use by the camera. */
+    enum ProjectionType
+    {
+		PT_ORTHOGRAPHIC, /**< Projection type where object size remains constant and parallel lines remain parallel. */
+		PT_PERSPECTIVE /**< Projection type that emulates human vision. Objects farther away appear smaller. */
+    };
+
+	/**	Clip planes that form the camera frustum (visible area). */
+    enum FrustumPlane
+    {
+        FRUSTUM_PLANE_NEAR = 0,
+        FRUSTUM_PLANE_FAR = 1,
+        FRUSTUM_PLANE_LEFT = 2,
+        FRUSTUM_PLANE_RIGHT = 3,
+        FRUSTUM_PLANE_TOP = 4,
+        FRUSTUM_PLANE_BOTTOM = 5
+    };
+
+	/**	Flags that describe a camera. */
+	enum class CameraFlags
+	{
+		/** 
+		 * This flag is a signal to the renderer that his camera will only render overlays and doesn't require depth   
+		 * buffer or multi-sampled render targets. This can improve performance and memory usage. 
+		 */
+		Overlay = 1
+	};
+
+	/** @} */
+	/** @addtogroup Implementation
+	 *  @{
+	 */
+
+	/**
+	 * Camera determines how is world geometry projected onto a 2D surface. You may position and orient it in space, set
+	 * options like aspect ratio and field or view and it outputs view and projection matrices required for rendering.
+	 */
+	class BS_EXPORT CameraBase
+    {
+    public:
+		virtual ~CameraBase() { }
+
+		/**
+		 * Sets the camera horizontal field of view. This determines how wide the camera viewing angle is along the
+		 * horizontal axis. Vertical FOV is calculated from the horizontal FOV and the aspect ratio.
+		 */
+        virtual void setHorzFOV(const Radian& fovy);
+
+		/**	Retrieves the camera horizontal field of view. */
+        virtual const Radian& getHorzFOV() const;
+
+		/**
+		 * Sets the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane will
+		 * not be rendered. Decreasing this value decreases depth buffer precision.
+		 */
+        virtual void setNearClipDistance(float nearDist);
+
+		/**
+		 * Retrieves the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane
+		 * will not be rendered. Decreasing this value decreases depth buffer precision.
+		 */
+        virtual float getNearClipDistance() const;
+
+		/**
+		 * Sets the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane will
+		 * not be rendered. Increasing this value decreases depth buffer precision.
+		 */
+        virtual void setFarClipDistance(float farDist);
+
+		/**
+		 * Retrieves the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane
+		 * will not be rendered. Increasing this value decreases depth buffer precision.
+		 */
+        virtual float getFarClipDistance() const;
+
+		/**	Sets the current viewport aspect ratio (width / height). */
+        virtual void setAspectRatio(float ratio);
+
+		/**	Returns current viewport aspect ratio (width / height). */
+        virtual float getAspectRatio() const;
+
+		/**	Sets camera world space position. */
+		virtual void setPosition(const Vector3& position);
+
+		/**	Retrieves camera world space position. */
+		virtual Vector3 getPosition() const { return mPosition; }
+
+		/**	Sets should the camera be rendered to or not. */
+		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
+		
+		/**	Gets whether the camera be rendered to or not. */
+		bool getIsActive() const { return mIsActive; }
+
+		/**
+		 * Gets the Z (forward) axis of the object, in world space.
+		 *
+		 * @return	Forward axis of the object.
+		 */
+		Vector3 getForward() const { return getRotation().rotate(-Vector3::UNIT_Z); }
+
+		/**	Sets camera world space rotation. */
+		virtual void setRotation(const Quaternion& rotation);
+
+		/**	Retrieves camera world space rotation. */
+		virtual Quaternion getRotation() const { return mRotation; }
+
+		/** Manually set the extents of the frustum that will be used when calculating the projection matrix. This will
+		 * prevents extents for being automatically calculated from aspect and near plane so it is up to the caller to keep
+		 * these values accurate.
+		 *
+		 * @param[in] left		The position where the left clip plane intersect the near clip plane, in view space.
+		 * @param[in] right		The position where the right clip plane intersect the near clip plane, in view space.
+		 * @param[in] top		The position where the top clip plane intersect the near clip plane, in view space.
+		 * @param[in] bottom	The position where the bottom clip plane intersect the near clip plane, in view space.
+		*/
+		virtual void setFrustumExtents(float left, float right, float top, float bottom);
+
+		/** 
+		 * Resets frustum extents so they are automatically derived from other values. This is only relevant if you have
+		 * previously set custom extents.
+		 */
+		virtual void resetFrustumExtents(); 
+
+		/** Returns the extents of the frustum in view space at the near plane. */
+		virtual void getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const;
+
+		/** 
+		 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. The layout
+		 * of this matrix depends on currently used render system.
+		 *
+		 * @note	
+		 * You should use this matrix when sending the matrix to the render system to make sure everything works 
+		 * consistently when other render systems are used.
+		 */
+        virtual const Matrix4& getProjectionMatrixRS() const;
+
+		/** 
+		 * Returns the inverse of the render-system specific projection matrix.
+		 *
+		 * @see		getProjectionMatrixRS
+		 */
+        virtual const Matrix4& getProjectionMatrixRSInv() const;
+
+		/** 
+		 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. Returned
+		 * matrix is standard following right-hand rules and depth range of [-1, 1]. 
+		 *
+		 * @note	
+		 * Different render systems will expect different projection matrix layouts, in which case use 
+		 * getProjectionMatrixRS().
+         */
+        virtual const Matrix4& getProjectionMatrix() const;
+
+		/** 
+		 * Returns the inverse of the projection matrix.
+		 *
+		 * @see		getProjectionMatrix
+		 */
+        virtual const Matrix4& getProjectionMatrixInv() const;
+
+		/** Gets the camera view matrix. Used for positioning/orienting the camera. */
+        virtual const Matrix4& getViewMatrix() const;
+
+		/** 
+		 * Returns the inverse of the view matrix.
+		 *
+		 * @see		getViewMatrix
+		 */
+		virtual const Matrix4& getViewMatrixInv() const;
+
+		/** 
+		 * Sets whether the camera should use the custom view matrix. When this is enabled camera will no longer calculate
+		 * its view matrix based on position/orientation and caller will be resonsible to keep the view matrix up to date.
+         */
+		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
+
+		/** Returns true if a custom view matrix is used. */
+		virtual bool isCustomViewMatrixEnabled() const { return mCustomViewMatrix; }
+		
+		/** 
+		 * Sets whether the camera should use the custom projection matrix. When this is enabled camera will no longer
+		 * calculate its projection matrix based on field of view, aspect and other parameters and caller will be resonsible
+		 * to keep the projection matrix up to date.
+         */
+		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
+
+		/** Returns true if a custom projection matrix is used. */
+		virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
+
+		/** Returns a convex volume representing the visible area of the camera, in local space. */
+        virtual const ConvexVolume& getFrustum() const;
+
+		/** Returns a convex volume representing the visible area of the camera, in world space. */
+        virtual ConvexVolume getWorldFrustum() const;
+
+		/**	Returns the bounding of the frustum. */
+        const AABox& getBoundingBox() const;
+
+		/**
+		 * Sets the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a 
+		 * 2D plane.
+		 */
+        virtual void setProjectionType(ProjectionType pt);
+
+		/**
+		 * Returns the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a
+		 * 2D plane.
+		 */
+        virtual ProjectionType getProjectionType() const;
+
+		/**
+		 * Sets the orthographic window height, for use with orthographic rendering only. 
+		 *
+		 * @param[in]	w	Width of the window in world units.
+		 * @param[in]	h	Height of the window in world units.
+		 *
+		 * @note	
+		 * Calling this method will recalculate the aspect ratio, use setOrthoWindowHeight() or setOrthoWindowWidth() alone
+		 * if you wish to preserve the aspect ratio but just fit one or other dimension to a particular size.
+		 */
+		virtual void setOrthoWindow(float w, float h);
+
+		/**
+		 * Sets the orthographic window height, for use with orthographic rendering only. 
+		 *
+		 * @param[in]	h	Height of the window in world units.
+		 *
+		 * @note	The width of the window will be calculated from the aspect ratio. 
+		 */
+		virtual void setOrthoWindowHeight(float h);
+
+		/**
+		 * Sets the orthographic window width, for use with orthographic rendering only. 
+		 *
+		 * @param[in]	w	Width of the window in world units.
+		 *
+		 * @note	The height of the window will be calculated from the aspect ratio. 
+		 */
+		virtual void setOrthoWindowWidth(float w);
+
+		/** Gets the orthographic window width in world units, for use with orthographic rendering only. */
+		virtual float getOrthoWindowHeight() const;
+
+		/**
+		 * Gets the orthographic window width in world units, for use with orthographic rendering only. 
+		 *
+		 * @note	This is calculated from the orthographic height and the aspect ratio.
+		 */
+		virtual float getOrthoWindowWidth() const;
+
+		/**
+		 * Gets a priority that determines in which orders the cameras are rendered. This only applies to cameras rendering
+		 * to the same render target. 
+		 */
+		INT32 getPriority() const { return mPriority; }
+
+		/**
+		 * Sets a priority that determines in which orders the cameras are rendered. This only applies to cameras rendering
+		 * to the same render target. 
+		 *
+		 * @param[in]	priority	The priority. Higher value means the camera will be rendered sooner.
+		 */
+		void setPriority(INT32 priority) { mPriority = priority; _markCoreDirty(); }
+
+		/**	Retrieves layer bitfield that is used when determining which object should the camera render. */
+		UINT64 getLayers() const { return mLayers; }
+
+		/**	Sets layer bitfield that is used when determining which object should the camera render. */
+		void setLayers(UINT64 layers) { mLayers = layers; _markCoreDirty(); }
+
+		/**	Retrieves flags that define the camera. */
+		CameraFlags getFlags() const { return (CameraFlags)mCameraFlags; }
+
+		/**	Sets flags that define the camera's behaviour. */
+		void setFlags(const CameraFlags& flags) { mCameraFlags = (UINT32)flags; _markCoreDirty(); }
+
+		/**
+		 * Converts a point in world space to screen coordinates (in pixels corresponding to the render target attached to
+		 * the camera).
+		 */
+		Vector2I worldToScreenPoint(const Vector3& worldPoint) const;
+
+		/**	Converts a point in world space to normalized device coordinates (in [-1, 1] range). */
+		Vector2 worldToNdcPoint(const Vector3& worldPoint) const;
+
+		/** Converts a point in world space to point relative to camera's coordinate system (view space). */
+		Vector3 worldToViewPoint(const Vector3& worldPoint) const;
+
+		/**
+		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point in
+		 * world space.
+		 *
+		 * @param[in]	screenPoint	Point to transform.
+		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
+		 *							origin to the point on the near plane.
+		 */
+		Vector3 screenToWorldPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
+
+		/**
+		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point
+		 * relative to camera's coordinate system (view space).
+		 *
+		 * @param[in]	screenPoint	Point to transform.
+		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
+		 *							origin to the point on the near plane.
+		 */
+		Vector3 screenToViewPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
+
+		/**
+		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to normalized 
+		 * device coordinates (in [-1, 1] range).
+		 */
+		Vector2 screenToNdcPoint(const Vector2I& screenPoint) const;
+
+		/** Converts a point relative to camera's coordinate system (view space) into a point in world space. */
+		Vector3 viewToWorldPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * Converts a point relative to camera's coordinate system (view space) into a point in screen space (pixels 
+		 * corresponding to render target attached to the camera).
+		 */
+		Vector2I viewToScreenPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * Converts a point relative to camera's coordinate system (view space) into normalized device coordinates 
+		 * (in [-1, 1] range).
+		 */
+		Vector2 viewToNdcPoint(const Vector3& viewPoint) const;
+
+		/**
+		 * Converts a point in normalized device coordinates ([-1, 1] range) to a point in world space.
+		 *
+		 * @param[in]	ndcPoint	Point to transform.
+		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
+		 *							origin to the point on the near plane.
+		 */
+		Vector3 ndcToWorldPoint(const Vector2& ndcPoint, float depth = 0.5f) const;
+
+		/**
+		 * Converts a point in normalized device coordinates ([-1, 1] range) to a point relative to camera's coordinate system
+		 * (view space).
+		 *
+		 * @param[in]	ndcPoint	Point to transform.
+		 * @param[in]	depth		Depth to place the world point at. The depth is applied to the vector going from camera
+		 *							origin to the point on the near plane.
+		 */
+		Vector3 ndcToViewPoint(const Vector2& ndcPoint, float depth = 0.5f) const;
+
+		/**
+		 * Converts a point in normalized device coordinates ([-1, 1] range) to a point in screen space (pixels corresponding
+		 * to render target attached to the camera).
+		 */
+		Vector2I ndcToScreenPoint(const Vector2& ndcPoint) const;
+
+		/**
+		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a ray in world
+		 * space originating at the selected point on the camera near plane.
+		 */
+		Ray screenPointToRay(const Vector2I& screenPoint) const;
+
+		/**	Projects a point from view to normalized device space. */
+		Vector3 projectPoint(const Vector3& point) const;
+
+		/**	Un-projects a point in normalized device space to view space. */
+		Vector3 unprojectPoint(const Vector3& point) const;
+
+        static const float INFINITE_FAR_PLANE_ADJUST; /**< Small constant used to reduce far plane projection to avoid inaccuracies. */
+
+	protected:
+		CameraBase();
+
+		/**	Calculate projection parameters that are used when constructing the projection matrix. */
+		virtual void calcProjectionParameters(float& left, float& right, float& bottom, float& top) const;
+
+		/**	Recalculate frustum if dirty. */
+		virtual void updateFrustum() const;
+
+		/**	Recalculate frustum planes if dirty. */
+		virtual void updateFrustumPlanes() const;
+
+		/**
+		 * Update view matrix from parent position/orientation.
+		 *
+		 * @note	Does nothing when custom view matrix is set.
+		 */
+		virtual void updateView() const;
+
+		/**	Checks if the frustum requires updating. */
+		virtual bool isFrustumOutOfDate() const;
+
+		/**	Notify camera that the frustum requires to be updated. */
+		virtual void invalidateFrustum() const;
+
+		/**	Returns a rectangle that defines the viewport position and size, in pixels. */
+		virtual Rect2I getViewportRect() const = 0;
+
+		/** @copydoc CoreObject::markCoreDirty */
+		virtual void _markCoreDirty() { }
+
+    protected:
+		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
+		UINT32 mCameraFlags; /**< Flags that further determine type of camera. */
+
+		Vector3 mPosition; /**< World space position. */
+		Quaternion mRotation; /**< World space rotation. */
+		bool mIsActive; /**< Is camera being rendered to. */
+
+		ProjectionType mProjType; /**< Type of camera projection. */
+		Radian mHorzFOV; /**< Horizontal field of view represents how wide is the camera angle. */
+		float mFarDist; /**< Clip any objects further than this. Larger value decreases depth precision at smaller depths. */
+		float mNearDist; /**< Clip any objects close than this. Smaller value decreases depth precision at larger depths. */
+		float mAspect; /**< Width/height viewport ratio. */
+		float mOrthoHeight; /**< Height in world units used for orthographic cameras. */
+		INT32 mPriority; /**< Determines in what order will the camera be rendered. Higher priority means the camera will be rendered sooner. */
+
+		bool mCustomViewMatrix; /**< Is custom view matrix set. */
+		bool mCustomProjMatrix; /**< Is custom projection matrix set. */
+
+		bool mFrustumExtentsManuallySet; /**< Are frustum extents manually set. */
+
+		mutable Matrix4 mProjMatrixRS; /**< Cached render-system specific projection matrix. */
+		mutable Matrix4 mProjMatrix; /**< Cached projection matrix that determines how are 3D points projected to a 2D viewport. */
+		mutable Matrix4 mViewMatrix; /**< Cached view matrix that determines camera position/orientation. */
+		mutable Matrix4 mProjMatrixRSInv;
+		mutable Matrix4 mProjMatrixInv;
+		mutable Matrix4 mViewMatrixInv;
+
+		mutable ConvexVolume mFrustum; /**< Main clipping planes describing cameras visible area. */
+		mutable bool mRecalcFrustum; /**< Should frustum be recalculated. */
+		mutable bool mRecalcFrustumPlanes; /**< Should frustum planes be recalculated. */
+		mutable bool mRecalcView; /**< Should view matrix be recalculated. */
+		mutable float mLeft, mRight, mTop, mBottom; /**< Frustum extents. */
+		mutable AABox mBoundingBox; /**< Frustum bounding box. */
+     };
+
+	/** @} */
+	/** @addtogroup Renderer-Engine
+	 *  @{
+	 */
+
+	/** @copydoc CameraBase */
+	class BS_EXPORT CameraCore : public CoreObjectCore, public CameraBase
+	{
+	public:
+		~CameraCore();
+
+		/**	Returns the viewport used by the camera. */	
+		SPtr<ViewportCore> getViewport() const { return mViewport; }
+
+	protected:
+		friend class Camera;
+
+		CameraCore(SPtr<RenderTargetCore> target = nullptr,
+			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
+
+		CameraCore(const SPtr<ViewportCore>& viewport);
+
+		/** @copydoc CoreObjectCore::initialize */
+		void initialize() override;
+
+		/** @copydoc CameraBase */
+		virtual Rect2I getViewportRect() const override;
+
+		/** @copydoc CoreObject::syncToCore */
+		void syncToCore(const CoreSyncData& data) override;
+
+		SPtr<ViewportCore> mViewport;
+	};
+
+	/** @copydoc CameraBase */
+	class BS_EXPORT Camera : public IReflectable, public CoreObject, public CameraBase
+    {
+    public:
+		/**	Returns the viewport used by the camera. */	
+		ViewportPtr getViewport() const { return mViewport; }
+
+		/**
+		 * Determines whether this is the main application camera. Main camera controls the final render surface that is
+		 * displayed to the user.
+		 */	
+		bool isMain() const { return mMain; }
+
+		/**
+		 * Marks or unmarks this camera as the main application camera. Main camera controls the final render surface that
+		 * is displayed to the user.
+		 */	
+		void setMain(bool main) { mMain = main; }
+
+		/** Retrieves an implementation of a camera handler usable only from the core thread. */
+		SPtr<CameraCore> getCore() const;
+
+		/**	Creates a new camera that renders to the specified portion of the provided render target. */
+		static CameraPtr create(RenderTargetPtr target = nullptr,
+			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
+
+		/** @cond INTERNAL */
+
+		/**	Returns the hash value that can be used to identify if the internal data needs an update. */
+		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
+
+		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
+		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
+
+		/** @endcond */
+
+	protected:
+		Camera(RenderTargetPtr target = nullptr,
+			float left = 0.0f, float top = 0.0f, float width = 1.0f, float height = 1.0f);
+
+		/** @copydoc CameraBase */
+		virtual Rect2I getViewportRect() const override;
+
+		/** @copydoc CoreObject::createCore */
+		SPtr<CoreObjectCore> createCore() const override;
+
+		/** @copydoc CoreObject::markCoreDirty */
+		void _markCoreDirty() override;
+
+		/** @copydoc CoreObject::syncToCore */
+		CoreSyncData syncToCore(FrameAlloc* allocator) override;
+
+		/** @copydoc CoreObject::getCoreDependencies */
+		void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
+
+		/**	Creates a new camera without initializing it. */
+		static CameraPtr createEmpty();
+
+		ViewportPtr mViewport; /**< Viewport that describes 2D rendering surface. */
+		bool mMain;
+		UINT32 mLastUpdateHash;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class CameraRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+     };
+
+	/** @} */
+	/** @endcond */
 }

+ 126 - 126
Source/BansheeEngine/Include/BsGUIScrollBar.h

@@ -1,127 +1,127 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsGUIElement.h"
-#include "BsEvent.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Implementation
-	 *  @{
-	 */
-
-	/** GUI element representing an element with a draggable handle of a variable size. */
-	class BS_EXPORT GUIScrollBar : public GUIElement
-	{
-	public:
-		/**	Returns the position of the scroll handle in percent (ranging [0, 1]). */
-		float getScrollPos() const;
-
-		/**
-		 * Moves the handle by some amount. Amount is specified in the percentage of the entire scrollable area. Values out
-		 * of range will be clamped.
-		 */
-		void scroll(float amount);
-
-		/**	Returns the maximum size of the scroll handle, in pixels. */
-		UINT32 getMaxHandleSize() const;
-
-		/**	Returns the maximum scrollable size the handle can move within (e.g. scroll bar length). */
-		UINT32 getScrollableSize() const;
-
-		/** @copydoc GUIElement::setTint */
-		virtual void setTint(const Color& color) override;
-
-		/**
-		 * Triggered whenever the scrollbar handle is moved. Value provided is the handle position in percent 
-		 * (ranging [0, 1]).
-		 */
-		Event<void(float newPosition)> onScrollPositionChanged;
-
-	public: // ***** INTERNAL ******
-		/** @cond INTERNAL */
-
-		/**
-		 * Sets the size of the handle in pixels.
-		 *
-		 * @note	Does not trigger layout update.
-		 */
-		void _setHandleSize(UINT32 size);
-
-		/**
-		 * @brief	Sets the position of the scroll handle in percent (ranging [0, 1]).
-		 *
-		 * @note	Does not trigger layout update.
-		 */
-		void _setScrollPos(float pct);
-
-		/** @copydoc GUIElement::_getOptimalSize */
-		virtual Vector2I _getOptimalSize() const override;
-
-		/** @endcond */
-	protected:
-		/**
-		 * Constructs a new scrollbar.
-		 *
-		 * @param[in]	horizontal	If true the scroll bar will have a horizontal moving handle, otherwise it will be a
-		 *							vertical one.
-		 * @param[in]	styleName	Optional style to use for the element. Style will be retrieved from GUISkin of the
-		 *							GUIWidget the element is used on. If not specified default style is used.
-		 * @param[in]	options		Options that allow you to control how is the element positioned and sized. This will 
-		 *							override any similar options set by style.
-		 */
-		GUIScrollBar(bool horizontal, const String& styleName, const GUIDimensions& dimensions);
-		virtual ~GUIScrollBar();
-
-		/** @copydoc GUIElement::_getNumRenderElements */
-		virtual UINT32 _getNumRenderElements() const override;
-
-		/** @copydoc GUIElement::_getMaterial */
-		virtual const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx) const override;
-
-		/** @copydoc GUIElement::_getNumQuads */
-		virtual UINT32 _getNumQuads(UINT32 renderElementIdx) const override;
-
-		/** @copydoc GUIElement::_fillBuffer */
-		virtual void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
-			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
-
-		/** @copydoc GUIElement::updateRenderElementsInternal */
-		virtual void updateRenderElementsInternal() override;
-
-		/** @copydoc GUIElement::updateBounds */
-		virtual void updateClippedBounds() override;
-
-		/** @copydoc GUIElement::_getRenderElementDepth */
-		virtual UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const override;
-
-		/** @copydoc	GUIElement::_getRenderElementDepthRange */
-		virtual UINT32 _getRenderElementDepthRange() const override;
-	private:
-		/**
-		 * Triggered whenever the scroll handle moves. Provided value represents the new position of the handle in percent
-		 * (ranging [0, 1]).
-		 */
-		void handleMoved(float handlePct);
-
-		/**	Triggered when scroll up button is clicked. */
-		void upButtonClicked();
-
-		/**	Triggered when scroll down button is clicked. */
-		void downButtonClicked();
-
-		GUILayout* mLayout;
-		ImageSprite* mImageSprite;
-
-		GUIButton* mUpBtn;
-		GUIButton* mDownBtn;
-		GUISliderHandle* mHandleBtn;
-		bool mHorizontal;
-
-		static const UINT32 ButtonScrollAmount;
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElement.h"
+#include "BsEvent.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Implementation
+	 *  @{
+	 */
+
+	/** GUI element representing an element with a draggable handle of a variable size. */
+	class BS_EXPORT GUIScrollBar : public GUIElement
+	{
+	public:
+		/**	Returns the position of the scroll handle in percent (ranging [0, 1]). */
+		float getScrollPos() const;
+
+		/**
+		 * Moves the handle by some amount. Amount is specified in the percentage of the entire scrollable area. Values out
+		 * of range will be clamped.
+		 */
+		void scroll(float amount);
+
+		/**	Returns the maximum size of the scroll handle, in pixels. */
+		UINT32 getMaxHandleSize() const;
+
+		/**	Returns the maximum scrollable size the handle can move within (e.g. scroll bar length). */
+		UINT32 getScrollableSize() const;
+
+		/** @copydoc GUIElement::setTint */
+		virtual void setTint(const Color& color) override;
+
+		/**
+		 * Triggered whenever the scrollbar handle is moved. Value provided is the handle position in percent 
+		 * (ranging [0, 1]).
+		 */
+		Event<void(float newPosition)> onScrollPositionChanged;
+
+	public: // ***** INTERNAL ******
+		/** @cond INTERNAL */
+
+		/**
+		 * Sets the size of the handle in pixels.
+		 *
+		 * @note	Does not trigger layout update.
+		 */
+		void _setHandleSize(UINT32 size);
+
+		/**
+		 * Sets the position of the scroll handle in percent (ranging [0, 1]).
+		 *
+		 * @note	Does not trigger layout update.
+		 */
+		void _setScrollPos(float pct);
+
+		/** @copydoc GUIElement::_getOptimalSize */
+		virtual Vector2I _getOptimalSize() const override;
+
+		/** @endcond */
+	protected:
+		/**
+		 * Constructs a new scrollbar.
+		 *
+		 * @param[in]	horizontal	If true the scroll bar will have a horizontal moving handle, otherwise it will be a
+		 *							vertical one.
+		 * @param[in]	styleName	Optional style to use for the element. Style will be retrieved from GUISkin of the
+		 *							GUIWidget the element is used on. If not specified default style is used.
+		 * @param[in]	options		Options that allow you to control how is the element positioned and sized. This will 
+		 *							override any similar options set by style.
+		 */
+		GUIScrollBar(bool horizontal, const String& styleName, const GUIDimensions& dimensions);
+		virtual ~GUIScrollBar();
+
+		/** @copydoc GUIElement::_getNumRenderElements */
+		virtual UINT32 _getNumRenderElements() const override;
+
+		/** @copydoc GUIElement::_getMaterial */
+		virtual const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx) const override;
+
+		/** @copydoc GUIElement::_getNumQuads */
+		virtual UINT32 _getNumQuads(UINT32 renderElementIdx) const override;
+
+		/** @copydoc GUIElement::_fillBuffer */
+		virtual void _fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const override;
+
+		/** @copydoc GUIElement::updateRenderElementsInternal */
+		virtual void updateRenderElementsInternal() override;
+
+		/** @copydoc GUIElement::updateBounds */
+		virtual void updateClippedBounds() override;
+
+		/** @copydoc GUIElement::_getRenderElementDepth */
+		virtual UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const override;
+
+		/** @copydoc	GUIElement::_getRenderElementDepthRange */
+		virtual UINT32 _getRenderElementDepthRange() const override;
+	private:
+		/**
+		 * Triggered whenever the scroll handle moves. Provided value represents the new position of the handle in percent
+		 * (ranging [0, 1]).
+		 */
+		void handleMoved(float handlePct);
+
+		/**	Triggered when scroll up button is clicked. */
+		void upButtonClicked();
+
+		/**	Triggered when scroll down button is clicked. */
+		void downButtonClicked();
+
+		GUILayout* mLayout;
+		ImageSprite* mImageSprite;
+
+		GUIButton* mUpBtn;
+		GUIButton* mDownBtn;
+		GUISliderHandle* mHandleBtn;
+		bool mHorizontal;
+
+		static const UINT32 ButtonScrollAmount;
+	};
+
+	/** @} */
 }

+ 81 - 81
Source/BansheeEngine/Include/BsGUISkin.h

@@ -1,82 +1,82 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsResource.h"
-#include "BsGUIElementStyle.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup GUI
-	 *  @{
-	 */
-
-	/**
-	 * Holds a set of styles that control how are GUI element types positioned and displayed in the GUI. Each element type
-	 * can be assigned a specific style.
-	 */
-	class BS_EXPORT GUISkin : public Resource
-	{
-	public:
-		/**	Checks if the style with the specified name exists. */
-		bool hasStyle(const String& name) const;
-
-		/**
-		 * Returns a style for the specified GUI element type.
-		 *
-		 * @see		GUIElement::getGUITypeName
-		 */
-		const GUIElementStyle* getStyle(const String& guiElemType) const;
-
-		/**
-		 * Sets a style for the specified GUI element type.
-		 *
-		 * @see		GUIElement::getGUITypeName
-		 */
-		void setStyle(const String& guiElemType, const GUIElementStyle& style);
-
-		/**
-		 * Removes a style for the specified GUI element type.
-		 *
-		 * @see		GUIElement::getGUITypeName
-		 */
-		void removeStyle(const String& guiElemType);
-
-		/**	Returns names of all styles registered on this skin. */
-		Vector<String> getStyleNames() const;
-
-		/**	Creates an empty GUI skin and returns a handle to it. */
-		static HGUISkin create();
-
-		/**	Default style that may be used when no other is available. */
-		static GUIElementStyle DefaultStyle;
-
-	public: // ***** INTERNAL ******
-		/** @cond INTERNAL */
-
-		/**
-		 * @brief	Creates an empty GUI skin and returns a pointer to it.
-		 *
-		 * @note	Internal method. Use "create" returning handle for normal use.
-		 */
-		static GUISkinPtr _createPtr();
-
-		/** @encond */
-	private:
-		GUISkin();
-		GUISkin(const GUISkin& skin); // Disable copying
-
-		UnorderedMap<String, GUIElementStyle> mStyles;
-
-		/************************************************************************/
-		/* 								SERIALIZATION                      		*/
-		/************************************************************************/
-	public:
-		friend class GUISkinRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsResource.h"
+#include "BsGUIElementStyle.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup GUI
+	 *  @{
+	 */
+
+	/**
+	 * Holds a set of styles that control how are GUI element types positioned and displayed in the GUI. Each element type
+	 * can be assigned a specific style.
+	 */
+	class BS_EXPORT GUISkin : public Resource
+	{
+	public:
+		/**	Checks if the style with the specified name exists. */
+		bool hasStyle(const String& name) const;
+
+		/**
+		 * Returns a style for the specified GUI element type.
+		 *
+		 * @see		GUIElement::getGUITypeName
+		 */
+		const GUIElementStyle* getStyle(const String& guiElemType) const;
+
+		/**
+		 * Sets a style for the specified GUI element type.
+		 *
+		 * @see		GUIElement::getGUITypeName
+		 */
+		void setStyle(const String& guiElemType, const GUIElementStyle& style);
+
+		/**
+		 * Removes a style for the specified GUI element type.
+		 *
+		 * @see		GUIElement::getGUITypeName
+		 */
+		void removeStyle(const String& guiElemType);
+
+		/**	Returns names of all styles registered on this skin. */
+		Vector<String> getStyleNames() const;
+
+		/**	Creates an empty GUI skin and returns a handle to it. */
+		static HGUISkin create();
+
+		/**	Default style that may be used when no other is available. */
+		static GUIElementStyle DefaultStyle;
+
+	public: // ***** INTERNAL ******
+		/** @cond INTERNAL */
+
+		/**
+		 * Creates an empty GUI skin and returns a pointer to it.
+		 *
+		 * @note	Internal method. Use "create" returning handle for normal use.
+		 */
+		static GUISkinPtr _createPtr();
+
+		/** @encond */
+	private:
+		GUISkin();
+		GUISkin(const GUISkin& skin); // Disable copying
+
+		UnorderedMap<String, GUIElementStyle> mStyles;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class GUISkinRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** @} */
 }

+ 210 - 212
Source/BansheeEngine/Include/BsPrerequisites.h

@@ -1,213 +1,211 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-
-/** @defgroup Engine Engine
- *	Specific implementation of the BansheeCore layer. This layer provides a more focused goal than the more generic
- *  BansheeCore layer, and therefore provides specific implementations of various abstract interfaces from BansheeCore,
- *  either directly or through specific plugins.
- *  @{
- */
-
-/** @defgroup Renderer-Engine Renderer
-  *	Abstract interface and helper functionality for rendering scene objects and other geometry (e.g. GUI). Provides more
-  * specialized functionality than Renderer abstraction in BansheeCore.
-  */
-
-/** @defgroup 2D 2D
-  *	Functionality relating to two dimensional geometry like sprites.
-  */
-
-/** @defgroup Components Components
-  *	Built-in components (elements that may be attached to scene objects).
-  */
-
-/** @defgroup GUI GUI
-  *	Everything relating to the graphical user interface, including elements, styles, events and GUI manager.
-  */
-
-/** @defgroup Input-Engine Input
- *	Functionality for dealing with input (mouse, keyboard, gamepad, etc.).
- */
-
-/** @defgroup RTTI-Impl-Engine RTTI types
- *  Types containing RTTI for specific classes.
- */
-
-/** @defgroup Resources-Engine Resources
-  *	Contains engine resource types and manager for builtin resources.
-  */
-
-/** @defgroup Utility-Engine Utility
- *  Various utility methods and types used by the engine layer.
- */
-
-/** @defgroup Platform-Engine Platform
- *  Platform specific functionality.
- */
-
-/** @defgroup Script Script
- *  Functionality for dealing with scripting languages and libraries.
- */
-
-/** @defgroup Application-Engine Application
- *  Entry point into the application.
- */
-
-/** @} */
-
-#if (BS_PLATFORM == BS_PLATFORM_WIN32) && !defined(__MINGW32__)
-#	ifdef BS_EXPORTS
-#		define BS_EXPORT __declspec(dllexport)
-#	else
-#       if defined( __MINGW32__ )
-#           define BS_EXPORT
-#       else
-#    		define BS_EXPORT __declspec(dllimport)
-#       endif
-#	endif
-#elif defined ( BS_GCC_VISIBILITY )
-#    define BS_EXPORT  __attribute__ ((visibility("default")))
-#else
-#    define BS_EXPORT
-#endif
-
-#include "BsGameObject.h"
-#include "BsEnums.h"
-#include "BsHEString.h"
-#include "BsPaths.h"
-
-namespace BansheeEngine
-{
-	static const StringID RenderAPIDX9 = "D3D9RenderAPI";
-	static const StringID RenderAPIDX11 = "D3D11RenderAPI";
-	static const StringID RenderAPIOpenGL = "GLRenderAPI";
-	static const StringID RendererDefault = "RenderBeast";
-
-	class VirtualButton;
-	class VirtualInput;
-	class InputConfiguration;
-	struct DragCallbackInfo;
-	struct ShortcutKey;
-
-	// GUI
-	class CGUIWidget;
-	class GUIManager;
-	class GUIWidget;
-	class GUIElementBase;
-	class GUIElement;
-	class GUILabel;
-	class GUIButtonBase;
-	class GUIButton;
-	class GUITexture;
-	class GUIToggle;
-	class GUIInputBox;
-	class GUISliderHandle;
-	class GUIScrollBarVert;
-	class GUIScrollBarHorz;
-	class GUIScrollArea;
-	class GUISkin;
-	class GUIRenderTexture;
-	struct GUIElementStyle;
-	class GUIMouseEvent;
-	class GUITextInputEvent;
-	class GUICommandEvent;
-	class GUIVirtualButtonEvent;
-	class GUILayout;
-	class GUILayoutX;
-	class GUILayoutY;
-	class GUIPanel;
-	class GUIFixedSpace;
-	class GUIFlexibleSpace;
-	class GUIInputCaret;
-	class GUIInputSelection;
-	struct GUIDimensions;
-	class GUIOptions;
-	class GUIToggleGroup;
-	class GUIListBox;
-	class GUIDropDownDataEntry;
-	class GUIDropDownMenu;
-	class DragAndDropManager;
-	class GUIMenu;
-	class GUIMenuItem;
-	class GUIContent;
-	class GUIContextMenu;
-	class GUIDropDownHitBox;
-	class GUIDropDownContent;
-	class RenderableElement;
-	class GUISlider;
-	class GUISliderVert;
-	class GUISliderHorz;
-	class GUIProgressBar;
-
-	class RenderableHandler;
-	class ProfilerOverlay;
-	class ProfilerOverlayInternal;
-	class DrawHelper;
-	class Camera;
-	class Renderable;
-	class CameraCore;
-	class RenderableCore;
-	class PlainText;
-	class ScriptCode;
-	class ScriptCodeImportOptions;
-	class RendererMeshData;
-
-	// 2D
-	class TextSprite;
-	class ImageSprite;
-	class SpriteTexture;
-	struct SpriteMaterialInfo;
-
-	// Components
-	class CRenderable;
-	class CCamera;
-	class CLight;
-
-	typedef std::shared_ptr<TextSprite> TextSpritePtr;
-	typedef std::shared_ptr<SpriteTexture> SpriteTexturePtr;
-	typedef std::shared_ptr<CCamera> CCameraPtr;
-	typedef std::shared_ptr<CRenderable> CRenderablePtr;
-	typedef std::shared_ptr<GUIToggleGroup> GUIToggleGroupPtr;
-	typedef std::shared_ptr<Camera> CameraPtr;
-	typedef std::shared_ptr<Renderable> RenderablePtr;
-	typedef std::shared_ptr<InputConfiguration> InputConfigurationPtr;
-	typedef std::shared_ptr<PlainText> PlainTextPtr;
-	typedef std::shared_ptr<ScriptCode> ScriptCodePtr;
-	typedef std::shared_ptr<GUISkin> GUISkinPtr;
-	typedef std::shared_ptr<GUIContextMenu> GUIContextMenuPtr;
-
-	typedef GameObjectHandle<CGUIWidget> HGUIWidget;
-	typedef GameObjectHandle<CCamera> HCamera;
-	typedef GameObjectHandle<CRenderable> HRenderable;
-	typedef GameObjectHandle<ProfilerOverlay> HProfilerOverlay;
-
-	typedef ResourceHandle<SpriteTexture> HSpriteTexture;
-	typedef ResourceHandle<PlainText> HPlainText;
-	typedef ResourceHandle<ScriptCode> HScriptCode;
-	typedef ResourceHandle<GUISkin> HGUISkin;
-
-	/**
-	 * @brief	RTTI types.
-	 */
-	enum TypeID_Banshee
-	{
-		TID_CCamera = 30000,
-		TID_CRenderable = 30001,
-		TID_SpriteTexture = 30002,
-		TID_Camera = 30003,
-		TID_Renderable = 30004,
-		TID_PlainText = 30005,
-		TID_ScriptCode = 30006,
-		TID_ScriptCodeImportOptions = 30007,
-		TID_GUIElementStyle = 30008,
-		TID_GUISkin = 30009,
-		TID_GUISkinEntry = 30010,
-		TID_Light = 30011,
-		TID_CLight = 30012,
-		TID_GameSettings = 30013,
-		TID_ResourceMapping = 30014
-	};
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+
+/** @defgroup Engine Engine
+ *	Specific implementation of the BansheeCore layer. This layer provides a more focused goal than the more generic
+ *  BansheeCore layer, and therefore provides specific implementations of various abstract interfaces from BansheeCore,
+ *  either directly or through specific plugins.
+ *  @{
+ */
+
+/** @defgroup Renderer-Engine Renderer
+  *	Abstract interface and helper functionality for rendering scene objects and other geometry (e.g. GUI). Provides more
+  * specialized functionality than Renderer abstraction in BansheeCore.
+  */
+
+/** @defgroup 2D 2D
+  *	Functionality relating to two dimensional geometry like sprites.
+  */
+
+/** @defgroup Components Components
+  *	Built-in components (elements that may be attached to scene objects).
+  */
+
+/** @defgroup GUI GUI
+  *	Everything relating to the graphical user interface, including elements, styles, events and GUI manager.
+  */
+
+/** @defgroup Input-Engine Input
+ *	Functionality for dealing with input (mouse, keyboard, gamepad, etc.).
+ */
+
+/** @defgroup RTTI-Impl-Engine RTTI types
+ *  Types containing RTTI for specific classes.
+ */
+
+/** @defgroup Resources-Engine Resources
+  *	Contains engine resource types and manager for builtin resources.
+  */
+
+/** @defgroup Utility-Engine Utility
+ *  Various utility methods and types used by the engine layer.
+ */
+
+/** @defgroup Platform-Engine Platform
+ *  Platform specific functionality.
+ */
+
+/** @defgroup Script Script
+ *  Functionality for dealing with scripting languages and libraries.
+ */
+
+/** @defgroup Application-Engine Application
+ *  Entry point into the application.
+ */
+
+/** @} */
+
+#if (BS_PLATFORM == BS_PLATFORM_WIN32) && !defined(__MINGW32__)
+#	ifdef BS_EXPORTS
+#		define BS_EXPORT __declspec(dllexport)
+#	else
+#       if defined( __MINGW32__ )
+#           define BS_EXPORT
+#       else
+#    		define BS_EXPORT __declspec(dllimport)
+#       endif
+#	endif
+#elif defined ( BS_GCC_VISIBILITY )
+#    define BS_EXPORT  __attribute__ ((visibility("default")))
+#else
+#    define BS_EXPORT
+#endif
+
+#include "BsGameObject.h"
+#include "BsEnums.h"
+#include "BsHEString.h"
+#include "BsPaths.h"
+
+namespace BansheeEngine
+{
+	static const StringID RenderAPIDX9 = "D3D9RenderAPI";
+	static const StringID RenderAPIDX11 = "D3D11RenderAPI";
+	static const StringID RenderAPIOpenGL = "GLRenderAPI";
+	static const StringID RendererDefault = "RenderBeast";
+
+	class VirtualButton;
+	class VirtualInput;
+	class InputConfiguration;
+	struct DragCallbackInfo;
+	struct ShortcutKey;
+
+	// GUI
+	class CGUIWidget;
+	class GUIManager;
+	class GUIWidget;
+	class GUIElementBase;
+	class GUIElement;
+	class GUILabel;
+	class GUIButtonBase;
+	class GUIButton;
+	class GUITexture;
+	class GUIToggle;
+	class GUIInputBox;
+	class GUISliderHandle;
+	class GUIScrollBarVert;
+	class GUIScrollBarHorz;
+	class GUIScrollArea;
+	class GUISkin;
+	class GUIRenderTexture;
+	struct GUIElementStyle;
+	class GUIMouseEvent;
+	class GUITextInputEvent;
+	class GUICommandEvent;
+	class GUIVirtualButtonEvent;
+	class GUILayout;
+	class GUILayoutX;
+	class GUILayoutY;
+	class GUIPanel;
+	class GUIFixedSpace;
+	class GUIFlexibleSpace;
+	class GUIInputCaret;
+	class GUIInputSelection;
+	struct GUIDimensions;
+	class GUIOptions;
+	class GUIToggleGroup;
+	class GUIListBox;
+	class GUIDropDownDataEntry;
+	class GUIDropDownMenu;
+	class DragAndDropManager;
+	class GUIMenu;
+	class GUIMenuItem;
+	class GUIContent;
+	class GUIContextMenu;
+	class GUIDropDownHitBox;
+	class GUIDropDownContent;
+	class RenderableElement;
+	class GUISlider;
+	class GUISliderVert;
+	class GUISliderHorz;
+	class GUIProgressBar;
+
+	class RenderableHandler;
+	class ProfilerOverlay;
+	class ProfilerOverlayInternal;
+	class DrawHelper;
+	class Camera;
+	class Renderable;
+	class CameraCore;
+	class RenderableCore;
+	class PlainText;
+	class ScriptCode;
+	class ScriptCodeImportOptions;
+	class RendererMeshData;
+
+	// 2D
+	class TextSprite;
+	class ImageSprite;
+	class SpriteTexture;
+	struct SpriteMaterialInfo;
+
+	// Components
+	class CRenderable;
+	class CCamera;
+	class CLight;
+
+	typedef std::shared_ptr<TextSprite> TextSpritePtr;
+	typedef std::shared_ptr<SpriteTexture> SpriteTexturePtr;
+	typedef std::shared_ptr<CCamera> CCameraPtr;
+	typedef std::shared_ptr<CRenderable> CRenderablePtr;
+	typedef std::shared_ptr<GUIToggleGroup> GUIToggleGroupPtr;
+	typedef std::shared_ptr<Camera> CameraPtr;
+	typedef std::shared_ptr<Renderable> RenderablePtr;
+	typedef std::shared_ptr<InputConfiguration> InputConfigurationPtr;
+	typedef std::shared_ptr<PlainText> PlainTextPtr;
+	typedef std::shared_ptr<ScriptCode> ScriptCodePtr;
+	typedef std::shared_ptr<GUISkin> GUISkinPtr;
+	typedef std::shared_ptr<GUIContextMenu> GUIContextMenuPtr;
+
+	typedef GameObjectHandle<CGUIWidget> HGUIWidget;
+	typedef GameObjectHandle<CCamera> HCamera;
+	typedef GameObjectHandle<CRenderable> HRenderable;
+	typedef GameObjectHandle<ProfilerOverlay> HProfilerOverlay;
+
+	typedef ResourceHandle<SpriteTexture> HSpriteTexture;
+	typedef ResourceHandle<PlainText> HPlainText;
+	typedef ResourceHandle<ScriptCode> HScriptCode;
+	typedef ResourceHandle<GUISkin> HGUISkin;
+
+	/**	RTTI types. */
+	enum TypeID_Banshee
+	{
+		TID_CCamera = 30000,
+		TID_CRenderable = 30001,
+		TID_SpriteTexture = 30002,
+		TID_Camera = 30003,
+		TID_Renderable = 30004,
+		TID_PlainText = 30005,
+		TID_ScriptCode = 30006,
+		TID_ScriptCodeImportOptions = 30007,
+		TID_GUIElementStyle = 30008,
+		TID_GUISkin = 30009,
+		TID_GUISkinEntry = 30010,
+		TID_Light = 30011,
+		TID_CLight = 30012,
+		TID_GameSettings = 30013,
+		TID_ResourceMapping = 30014
+	};
 }

+ 85 - 87
Source/BansheeEngine/Include/BsRendererMaterial.h

@@ -1,88 +1,86 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsMaterial.h"
-#include "BsRendererMaterialManager.h"
-
-#define RMAT_DEF(path)\
-	public: \
-	static void _initMetaData() \
-	{ \
-		RendererMaterialManager::_registerMaterial(&mMetaData, path); \
-	}; \
-
-namespace BansheeEngine
-{
-	/** @cond INTERNAL */
-	/** @addtogroup Renderer-Engine
-	 *  @{
-	 */
-
-	/**	Contains data common to all render material instances of a specific type. */
-	struct RendererMaterialMetaData
-	{
-		SPtr<ShaderCore> shader;
-	};
-
-	/**	Base class for all RendererMaterial instances, containing common data and methods. */
-	class BS_EXPORT RendererMaterialBase
-	{
-	public:
-		virtual ~RendererMaterialBase() { }
-
-		/**
-		 * @brief	Returns the internal material.
-		 */
-		SPtr<MaterialCore> getMaterial() const { return mMaterial; }
-
-	protected:
-		friend class RendererMaterialManager;
-
-		SPtr<MaterialCore> mMaterial;
-	};
-
-	/**	Helper class to initialize all renderer materials as soon as the library is loaded. */
-	template <class T>
-	struct InitRendererMaterialStart
-	{
-	public:
-		InitRendererMaterialStart()
-		{
-			T::_initMetaData();
-		}
-
-		/**	Forces the compiler to not optimize out construction of this type. */
-		void instantiate() { }
-	};
-
-	/** Wrapper class around Material that allows a simple way to load and set up materials used by the renderer. */
-	template<class T>
-	class RendererMaterial : public RendererMaterialBase
-	{
-	public:
-		RendererMaterial()
-		{
-			mInitOnStart.instantiate();
-			mMaterial = MaterialCore::create(mMetaData.shader);
-		}
-
-		virtual ~RendererMaterial() { }
-
-	protected:
-		friend class RendererMaterialManager;
-
-		static RendererMaterialMetaData mMetaData;
-		static InitRendererMaterialStart<T> mInitOnStart;
-	};
-
-	template<class T>
-	InitRendererMaterialStart<T> RendererMaterial<T>::mInitOnStart;
-
-	template<class T>
-	RendererMaterialMetaData RendererMaterial<T>::mMetaData;
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsMaterial.h"
+#include "BsRendererMaterialManager.h"
+
+#define RMAT_DEF(path)\
+	public: \
+	static void _initMetaData() \
+	{ \
+		RendererMaterialManager::_registerMaterial(&mMetaData, path); \
+	}; \
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Renderer-Engine
+	 *  @{
+	 */
+
+	/**	Contains data common to all render material instances of a specific type. */
+	struct RendererMaterialMetaData
+	{
+		SPtr<ShaderCore> shader;
+	};
+
+	/**	Base class for all RendererMaterial instances, containing common data and methods. */
+	class BS_EXPORT RendererMaterialBase
+	{
+	public:
+		virtual ~RendererMaterialBase() { }
+
+		/**	Returns the internal material. */
+		SPtr<MaterialCore> getMaterial() const { return mMaterial; }
+
+	protected:
+		friend class RendererMaterialManager;
+
+		SPtr<MaterialCore> mMaterial;
+	};
+
+	/**	Helper class to initialize all renderer materials as soon as the library is loaded. */
+	template <class T>
+	struct InitRendererMaterialStart
+	{
+	public:
+		InitRendererMaterialStart()
+		{
+			T::_initMetaData();
+		}
+
+		/**	Forces the compiler to not optimize out construction of this type. */
+		void instantiate() { }
+	};
+
+	/** Wrapper class around Material that allows a simple way to load and set up materials used by the renderer. */
+	template<class T>
+	class RendererMaterial : public RendererMaterialBase
+	{
+	public:
+		RendererMaterial()
+		{
+			mInitOnStart.instantiate();
+			mMaterial = MaterialCore::create(mMetaData.shader);
+		}
+
+		virtual ~RendererMaterial() { }
+
+	protected:
+		friend class RendererMaterialManager;
+
+		static RendererMaterialMetaData mMetaData;
+		static InitRendererMaterialStart<T> mInitOnStart;
+	};
+
+	template<class T>
+	InitRendererMaterialStart<T> RendererMaterial<T>::mInitOnStart;
+
+	template<class T>
+	RendererMaterialMetaData RendererMaterial<T>::mMetaData;
+
+	/** @} */
+	/** @endcond */
 }

+ 23 - 27
Source/BansheeFBXImporter/Source/BsFBXPlugin.cpp

@@ -1,28 +1,24 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsFBXPrerequisites.h"
-#include "BsFBXImporter.h"
-#include "BsImporter.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Returns a name of the plugin.
-	 */
-	extern "C" BS_FBX_EXPORT const String& getPluginName()
-	{
-		static String pluginName = "FBXImporter";
-		return pluginName;
-	}
-
-	/**
-	 * @brief	Entry point to the plugin. Called by the engine when the plugin is loaded.
-	 */
-	extern "C" BS_FBX_EXPORT void* loadPlugin()
-	{
-		FBXImporter* importer = bs_new<FBXImporter>();
-		Importer::instance()._registerAssetImporter(importer);
-
-		return nullptr;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsFBXPrerequisites.h"
+#include "BsFBXImporter.h"
+#include "BsImporter.h"
+
+namespace BansheeEngine
+{
+	/**	Returns a name of the plugin. */
+	extern "C" BS_FBX_EXPORT const String& getPluginName()
+	{
+		static String pluginName = "FBXImporter";
+		return pluginName;
+	}
+
+	/**	Entry point to the plugin. Called by the engine when the plugin is loaded. */
+	extern "C" BS_FBX_EXPORT void* loadPlugin()
+	{
+		FBXImporter* importer = bs_new<FBXImporter>();
+		Importer::instance()._registerAssetImporter(importer);
+
+		return nullptr;
+	}
 }

+ 23 - 27
Source/BansheeFontImporter/Source/BsFontPlugin.cpp

@@ -1,28 +1,24 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsFontPrerequisites.h"
-#include "BsImporter.h"
-#include "BsFontImporter.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Returns a name of the plugin.
-	 */
-	extern "C" BS_FONT_EXPORT const String& getPluginName()
-	{
-		static String pluginName = "FontImporter";
-		return pluginName;
-	}
-
-	/**
-	 * @brief	Entry point to the plugin. Called by the engine when the plugin is loaded.
-	 */
-	extern "C" BS_FONT_EXPORT void* loadPlugin()
-	{
-		FontImporter* importer = bs_new<FontImporter>();
-		Importer::instance()._registerAssetImporter(importer);
-
-		return nullptr;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsFontPrerequisites.h"
+#include "BsImporter.h"
+#include "BsFontImporter.h"
+
+namespace BansheeEngine
+{
+	/**	Returns a name of the plugin. */
+	extern "C" BS_FONT_EXPORT const String& getPluginName()
+	{
+		static String pluginName = "FontImporter";
+		return pluginName;
+	}
+
+	/**	Entry point to the plugin. Called by the engine when the plugin is loaded. */
+	extern "C" BS_FONT_EXPORT void* loadPlugin()
+	{
+		FontImporter* importer = bs_new<FontImporter>();
+		Importer::instance()._registerAssetImporter(importer);
+
+		return nullptr;
+	}
 }

+ 1 - 3
Source/BansheeGLRenderAPI/Include/BsGLTextureManager.h

@@ -35,9 +35,7 @@ namespace BansheeEngine
         GLSupport& mGLSupport;
     };
 
-	/**
-	 * @brief	Handles creation of OpenGL textures.
-	 */
+	/** Handles creation of OpenGL textures. */
 	class BS_RSGL_EXPORT GLTextureCoreManager : public TextureCoreManager
 	{
 	public:

+ 34 - 38
Source/BansheeOISInput/Source/BsOISPlugin.cpp

@@ -1,39 +1,35 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsOISPrerequisites.h"
-#include "BsInputHandlerOIS.h"
-#include "BsRenderWindow.h"
-#include "BsInput.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Returns a name of the plugin.
-	 */
-	extern "C" BS_OIS_EXPORT const String& getPluginName()
-	{
-		static String pluginName = "OISInput";
-		return pluginName;
-	}
-
-	/**
-	 * @brief	Entry point to the plugin. Called by the engine when the plugin is loaded.
-	 */
-	extern "C" BS_OIS_EXPORT void* loadPlugin(void* primaryWindowPtr)
-	{
-		RenderWindow* primaryWindow = (RenderWindow*)primaryWindowPtr;
-
-		if (primaryWindow == nullptr)
-			assert(false && "Unable to get window handle. No active window exists!");
-
-		UINT64 windowId = 0;
-		primaryWindow->getCustomAttribute("WINDOW", &windowId);
-
-		// TODO - Window handles in Windows are 64 bits when compiled as x64, but OIS only accepts a 32bit value. Is this okay?
-		std::shared_ptr<RawInputHandler> inputHandler = bs_shared_ptr_new<InputHandlerOIS>((UINT32)windowId);
-
-		gInput()._registerRawInputHandler(inputHandler);
-
-		return nullptr;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsOISPrerequisites.h"
+#include "BsInputHandlerOIS.h"
+#include "BsRenderWindow.h"
+#include "BsInput.h"
+
+namespace BansheeEngine
+{
+	/**	Returns a name of the plugin. */
+	extern "C" BS_OIS_EXPORT const String& getPluginName()
+	{
+		static String pluginName = "OISInput";
+		return pluginName;
+	}
+
+	/**	Entry point to the plugin. Called by the engine when the plugin is loaded. */
+	extern "C" BS_OIS_EXPORT void* loadPlugin(void* primaryWindowPtr)
+	{
+		RenderWindow* primaryWindow = (RenderWindow*)primaryWindowPtr;
+
+		if (primaryWindow == nullptr)
+			assert(false && "Unable to get window handle. No active window exists!");
+
+		UINT64 windowId = 0;
+		primaryWindow->getCustomAttribute("WINDOW", &windowId);
+
+		// TODO - Window handles in Windows are 64 bits when compiled as x64, but OIS only accepts a 32bit value. Is this okay?
+		std::shared_ptr<RawInputHandler> inputHandler = bs_shared_ptr_new<InputHandlerOIS>((UINT32)windowId);
+
+		gInput()._registerRawInputHandler(inputHandler);
+
+		return nullptr;
+	}
 }

+ 22 - 26
Source/BansheeSL/Source/BsSLPlugin.cpp

@@ -1,27 +1,23 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsSLPrerequisites.h"
-#include "BsSLImporter.h"
-#include "BsImporter.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Returns a name of the plugin.
-	 */
-	extern "C" BS_SL_EXPORT const String& getPluginName()
-	{
-		return SystemName;
-	}
-
-	/**
-	 * @brief	Entry point to the plugin. Called by the engine when the plugin is loaded.
-	 */
-	extern "C" BS_SL_EXPORT void* loadPlugin()
-	{
-		SLImporter* importer = bs_new<SLImporter>();
-		Importer::instance()._registerAssetImporter(importer);
-
-		return nullptr;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsSLPrerequisites.h"
+#include "BsSLImporter.h"
+#include "BsImporter.h"
+
+namespace BansheeEngine
+{
+	/**	Returns a name of the plugin. */
+	extern "C" BS_SL_EXPORT const String& getPluginName()
+	{
+		return SystemName;
+	}
+
+	/**	Entry point to the plugin. Called by the engine when the plugin is loaded. */
+	extern "C" BS_SL_EXPORT void* loadPlugin()
+	{
+		SLImporter* importer = bs_new<SLImporter>();
+		Importer::instance()._registerAssetImporter(importer);
+
+		return nullptr;
+	}
 }

+ 105 - 106
Source/BansheeUtility/Include/BsDebug.h

@@ -1,107 +1,106 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsLog.h"
-
-namespace BansheeEngine
-{
-	class Log;
-
-	/** @addtogroup Debug
-	 *  @{
-	 */
-
-	/** Available types of channels that debug messages can be logged to. */
-	enum class DebugChannel
-	{
-		Debug, Warning, Error, CompilerWarning, CompilerError
-	};
-
-	/**
-	 * @brief	Utility class providing various debug functionality.
-	 *
-	 * @note	Thread safe.
-	 */
-	class BS_UTILITY_EXPORT Debug
-	{
-	public:
-		Debug() {}
-
-		/** Adds a log entry in the "Debug" channel. */
-		void logDebug(const String& msg);
-
-		/** Adds a log entry in the "Warning" channel. */
-		void logWarning(const String& msg);
-
-		/** Adds a log entry in the "Error" channel. */
-		void logError(const String& msg);
-
-		/** Adds a log entry in the specified channel. You may specify custom channels as needed. */
-		void log(const String& msg, UINT32 channel);
-
-		/** Retrieves the Log used by the Debug instance. */
-		Log& getLog() { return mLog; }
-
-		/** Converts raw pixels into a BMP image. See BitmapWriter for more information. */
-		void writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const Path& filePath, bool overwrite = true) const;
-
-		/**
-		 * Saves a log about the current state of the application to the specified location.
-		 * 
-		 * @param	path	Absolute path to the log filename.
-		 */
-		void saveLog(const Path& path) const;
-
-		/**
-		 * @brief	Triggered when a new entry in the log is added.
-		 * 			
-		 * @note	Sim thread only.
-		 */
-		Event<void(const LogEntry&)> onLogEntryAdded;
-
-		/**
-		 * @brief	Triggered whenever one or multiple log entries were added or removed.
-		 *			Triggers only once per frame.
-		 * 			
-		 * @note	Sim thread only.
-		 */
-		Event<void()> onLogModified;
-
-	public: // ***** INTERNAL ******
-		/** @cond INTERNAL */
-
-		/**
-		 * Triggers callbacks that notify external code that a log entry was added.
-		 * 			
-		 * @note	Internal method. Sim thread only.
-		 */
-		void _triggerCallbacks();
-
-		/** @endcond */
-	private:
-		UINT64 mLogHash = 0;
-		Log mLog;
-	};
-
-	/** A simpler way of accessing the Debug module. */
-	BS_UTILITY_EXPORT Debug& gDebug();
-
-/** Shortcut for logging a message in the debug channel. */
-#define LOGDBG(x) BansheeEngine::gDebug().logDebug((x));
-
-/** Shortcut for logging a message in the warning channel. */
-#define LOGWRN(x) BansheeEngine::gDebug().logWarning((x));
-
-/** Shortcut for logging a message in the error channel. */
-#define LOGERR(x) BansheeEngine::gDebug().logError((x));
-
-/** Shortcut for logging a verbose message in the debug channel. Verbose messages can be ignored unlike other log messages. */
-#define LOGDBG_VERBOSE(x)
-
-/** Shortcut for logging a verbose message in the warning channel. Verbose messages can be ignored unlike other log messages. */
-#define LOGWRN_VERBOSE(x)
-
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsLog.h"
+
+namespace BansheeEngine
+{
+	class Log;
+
+	/** @addtogroup Debug
+	 *  @{
+	 */
+
+	/** Available types of channels that debug messages can be logged to. */
+	enum class DebugChannel
+	{
+		Debug, Warning, Error, CompilerWarning, CompilerError
+	};
+
+	/**
+	 * Utility class providing various debug functionality.
+	 *
+	 * @note	Thread safe.
+	 */
+	class BS_UTILITY_EXPORT Debug
+	{
+	public:
+		Debug() {}
+
+		/** Adds a log entry in the "Debug" channel. */
+		void logDebug(const String& msg);
+
+		/** Adds a log entry in the "Warning" channel. */
+		void logWarning(const String& msg);
+
+		/** Adds a log entry in the "Error" channel. */
+		void logError(const String& msg);
+
+		/** Adds a log entry in the specified channel. You may specify custom channels as needed. */
+		void log(const String& msg, UINT32 channel);
+
+		/** Retrieves the Log used by the Debug instance. */
+		Log& getLog() { return mLog; }
+
+		/** Converts raw pixels into a BMP image. See BitmapWriter for more information. */
+		void writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const Path& filePath, bool overwrite = true) const;
+
+		/**
+		 * Saves a log about the current state of the application to the specified location.
+		 * 
+		 * @param	path	Absolute path to the log filename.
+		 */
+		void saveLog(const Path& path) const;
+
+		/**
+		 * Triggered when a new entry in the log is added.
+		 * 			
+		 * @note	Sim thread only.
+		 */
+		Event<void(const LogEntry&)> onLogEntryAdded;
+
+		/**
+		 * Triggered whenever one or multiple log entries were added or removed. Triggers only once per frame.
+		 * 			
+		 * @note	Sim thread only.
+		 */
+		Event<void()> onLogModified;
+
+	public: // ***** INTERNAL ******
+		/** @cond INTERNAL */
+
+		/**
+		 * Triggers callbacks that notify external code that a log entry was added.
+		 * 			
+		 * @note	Internal method. Sim thread only.
+		 */
+		void _triggerCallbacks();
+
+		/** @endcond */
+	private:
+		UINT64 mLogHash = 0;
+		Log mLog;
+	};
+
+	/** A simpler way of accessing the Debug module. */
+	BS_UTILITY_EXPORT Debug& gDebug();
+
+/** Shortcut for logging a message in the debug channel. */
+#define LOGDBG(x) BansheeEngine::gDebug().logDebug((x));
+
+/** Shortcut for logging a message in the warning channel. */
+#define LOGWRN(x) BansheeEngine::gDebug().logWarning((x));
+
+/** Shortcut for logging a message in the error channel. */
+#define LOGERR(x) BansheeEngine::gDebug().logError((x));
+
+/** Shortcut for logging a verbose message in the debug channel. Verbose messages can be ignored unlike other log messages. */
+#define LOGDBG_VERBOSE(x)
+
+/** Shortcut for logging a verbose message in the warning channel. Verbose messages can be ignored unlike other log messages. */
+#define LOGWRN_VERBOSE(x)
+
+	/** @} */
 }

+ 622 - 624
Source/BansheeUtility/Include/BsPath.h

@@ -1,625 +1,623 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-/** @addtogroup Filesystem
- *  @{
- */
-
-namespace BansheeEngine
-{
-	/**
-	 * Class for storing and manipulating file paths. Paths may be parsed from and to raw strings according to various 
-	 * platform specific path types.
-	 *
-	 * @note	
-	 * In order to allow the system to easily distinguish between file and directory paths, try to ensure that all directory
-	 * paths end with a separator (\ or / depending on platform). System won't fail if you don't but it will be easier to 
-	 * misuse.
-	 */
-	class BS_UTILITY_EXPORT Path
-	{
-	public:
-		enum class PathType
-		{
-			Windows,
-			Unix,
-			Default
-		};
-
-	public:
-		Path();
-
-		/**
-		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		Path(const WString& pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		Path(const String& pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is not 
-		 * valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		Path(wchar_t* pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is 
-		 * not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		Path(const char* pathStr, PathType type = PathType::Default);
-		Path(const Path& other);
-
-		/**
-		 * Assigns a path by parsing the provided path string. Path will be parsed according to the rules of the platform 
-		 * the application is being compiled to.
-		 */
-		Path& operator= (const WString& pathStr);
-
-		/**
-		 * Assigns a path by parsing the provided path string. Path will be parsed according to the rules of the platform 
-		 * the application is being compiled to.
-		 */
-		Path& operator= (const String& pathStr);
-
-		/**
-		 * Assigns a path by parsing the provided path null terminated string. Path will be parsed according to the rules 
-		 * of the platform the application is being compiled to.
-		 */
-		Path& operator= (const wchar_t* pathStr);
-
-		/**
-		 * Assigns a path by parsing the provided path null terminated string. Path will be parsed according to the rules 
-		 * of the platform the application is being compiled to.
-		 */
-		Path& operator= (const char* pathStr);
-
-		Path& operator= (const Path& path);
-
-		/**
-		 * Compares two paths and returns true if they match. Comparison is case insensitive and paths will be compared 
-		 * as-is, without canonization.
-		 */
-		bool operator== (const Path& path) const { return equals(path); }
-
-		/**
-		 * Compares two paths and returns true if they don't match. Comparison is case insensitive and paths will be 
-		 * compared as-is, without canonization.
-		 */
-		bool operator!= (const Path& path) const { return !equals(path); }
-
-		/** Gets a directory name with the specified index from the path. */
-		const WString& operator[] (UINT32 idx) const { return getWDirectory(idx); }
-
-		/** Swap internal data with another Path object. */
-		void swap(Path& path);
-
-		/**
-		 * @brief	Create a path from another Path object.
-		 */
-		void assign(const Path& path);
-
-		/**
-		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		void assign(const WString& pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application 
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		void assign(const String& pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is not 
-		 * valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		void assign(const wchar_t* pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is not 
-		 * valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application 
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		void assign(const char* pathStr, PathType type = PathType::Default);
-
-		/**
-		 * Converts the path in a string according to platform path rules.
-		 *
-		 * @param[in] type	If set to default path will be parsed according to the rules of the platform the application is 
-		 *					being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		WString toWString(PathType type = PathType::Default) const;
-
-		/**
-		 * Converts the path in a string according to platform path rules.
-		 *
-		 * @param[in] type	If set to default path will be parsed according to the rules of the platform the application is 
-		 *					being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		String toString(PathType type = PathType::Default) const;
-
-		/** Checks is the path a directory (contains no file-name). */
-		bool isDirectory() const { return mFilename.empty(); }
-
-		/** Checks does the path point to a file. */
-		bool isFile() const { return !mFilename.empty(); }
-
-		/** Checks is the contained path absolute. */
-		bool isAbsolute() const { return mIsAbsolute; }
-
-		/**
-		 * Returns parent path. If current path points to a file the parent path will be the folder where the file is located.
-		 * Or if it contains a directory the parent will be the parent directory. If no parent exists, same path will be 
-		 * returned.
-		 */
-		Path getParent() const;
-
-		/**
-		 * Returns an absolute path by appending the current path to the provided base. If path was already absolute no 
-		 * changes are made and copy of current path is returned. If base is not absolute, then the returned path will be 
-		 * made relative to base, but will not be absolute.
-		 */
-		Path getAbsolute(const Path& base) const;
-
-		/**
-		 * Returns a relative path by making the current path relative to the provided base. Base must be a part of the 
-		 * current path. If base is not a part of the path no changes are made and a copy of the current path is returned.
-		 */
-		Path getRelative(const Path& base) const;
-
-		/**
-		 * Returns the path as a path to directory. If path was pointing to a file, the filename is removed, otherwise no 
-		 * changes are made and exact copy is returned.
-		 */
-		Path getDirectory() const;
-
-		/**
-		 * Makes the path the parent of the current path. If current path points to a file the parent path will be the 
-		 * folder where the file is located. Or if it contains a directory the parent will be the parent directory. If no 
-		 * parent exists, same path will be returned.
-		 */
-		Path& makeParent();
-
-		/**
-		 * Makes the current path absolute by appending it to base. If path was already absolute no changes are made and 
-		 * copy of current path is returned. If base is not absolute, then the returned path will be made relative to base,
-		 * but will not be absolute.
-		 */
-		Path& makeAbsolute(const Path& base);
-
-		/**
-		 * Makes the current path relative to the provided base. Base must be a part of the current path. If base is not 
-		 * a part of the path no changes are made and a copy of the current path is returned.
-		 */
-		Path& makeRelative(const Path& base);
-
-		/** Appends another path to the end of this path. */
-		Path& append(const Path& path);
-
-		/**
-		 * Checks if the current path contains the provided path. Comparison is case insensitive and paths will be compared 
-		 * as-is, without canonization.
-		 */
-		bool includes(const Path& child) const;
-
-		/**
-		 * Compares two paths and returns true if they match. Comparison is case insensitive and paths will be compared 
-		 * as-is, without canonization.
-		 */
-		bool equals(const Path& other) const;
-
-		/** Change or set the filename in the path. */
-		void setFilename(const WString& filename) { mFilename = filename; }
-
-		/** Change or set the filename in the path. */
-		void setFilename(const String& filename) { mFilename = BansheeEngine::toWString(filename); }
-
-		/**
-		 * Change or set the base name in the path. Base name changes the filename by changing its base to the provided 
-		 * value but keeping extension intact.
-		 */
-		void setBasename(const WString& basename);
-
-		/**
-		 * Change or set the base name in the path. Base name changes the filename by changing its base to the provided 
-		 * value but keeping extension intact.
-		 */
-		void setBasename(const String& basename);
-
-		/**
-		 * Change or set the extension of the filename in the path.
-		 *
-		 * @param[in]	extension	Extension with a leading ".".
-		 */
-		void setExtension(const WString& extension);
-
-		/**
-		 * Change or set the extension of the filename in the path.
-		 *
-		 * @param[in]	extension	Extension with a leading ".".
-		 */
-		void setExtension(const String& extension);
-
-		/**
-		 * Returns a filename in the path.
-		 *
-		 * @param[in]	extension	If true, returned filename will contain an extension.
-		 */
-		WString getWFilename(bool extension = true) const;
-
-		/**
-		 * Returns a filename in the path.
-		 *
-		 * @param[in]	extension	If true, returned filename will contain an extension.
-		 */
-		String getFilename(bool extension = true) const;
-
-		/** Returns file extension with the leading ".". */
-		WString getWExtension() const;
-
-		/** Returns file extension with the leading ".". */
-		String getExtension() const;
-
-		/** Gets the number of directories in the path. */
-		UINT32 getNumDirectories() const { return (UINT32)mDirectories.size(); }
-
-		/** Gets a directory name with the specified index from the path. */
-		const WString& getWDirectory(UINT32 idx) const;
-
-		/** Gets a directory name with the specified index from the path. */
-		String getDirectory(UINT32 idx) const;
-
-		/** Returns path device (e.g. drive, volume, etc.) if one exists in the path. */
-		const WString& getWDevice() const { return mDevice; }
-
-		/** Returns path device (e.g. drive, volume, etc.) if one exists in the path. */
-		String getDevice() const { return BansheeEngine::toString(mDevice); }
-
-		/** Returns path node (e.g. network name) if one exists in the path. */
-		const WString& getWNode() const { return mNode; }
-
-		/** Returns path node (e.g. network name) if one exists in the path. */
-		String getNode() const { return BansheeEngine::toString(mNode); }
-
-		/**
-		 * Gets last element in the path, filename if it exists, otherwise the last directory. If no directories exist 
-		 * returns device or node.
-		 *
-		 * @param[in]	type	Determines format of node or device, in case they are returned. When default, format for 
-		 *						the active platform will be used, otherwise the format defined by the parameter will be used.
-		 */
-		WString getWTail(PathType type = PathType::Default) const;
-
-		/**
-		 * Gets last element in the path, filename if it exists, otherwise the last directory. If no directories exist 
-		 * returns device or node.
-		 *
-		 * @param[in]	type	Determines format of node or device, in case they are returned. When default, format for the
-		 *						active platform will be used, otherwise the format defined by the parameter will be used.
-		 */
-		String getTail(PathType type = PathType::Default) const;
-
-		/** Clears the path to nothing. */
-		void clear();
-
-		/** Returns true if no path has been set. */
-		bool isEmpty() const { return mDirectories.empty() && mFilename.empty() && mDevice.empty() && mNode.empty(); }
-
-		/** Concatenates two paths. */
-		Path operator+ (const Path& rhs) const;
-
-		/** Concatenates two paths. */
-		Path& operator+= (const Path& rhs);
-
-		/** Compares two path elements (i.e. filenames, directory names, etc.). */
-		static bool comparePathElem(const WString& left, const WString& right);
-
-		/** Combines two paths and returns the result. Right path should be relative. */
-		static Path combine(const Path& left, const Path& right);
-
-		static const Path BLANK;
-	private:
-		/**
-		 * Constructs a path by parsing the provided raw string data. Throws exception if provided path is not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application 
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		void assign(const wchar_t* pathStr, UINT32 numChars, PathType type = PathType::Default);
-
-		/**
-		 * Constructs a path by parsing the provided raw string data. Throws exception if provided path is not valid.
-		 *
-		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
-		 *						is being compiled to. Otherwise it will be parsed according to provided type.
-		 */
-		void assign(const char* pathStr, UINT32 numChars, PathType type = PathType::Default);
-
-		/** Parses a Windows path and stores the parsed data internally. Throws an exception if parsing fails. */
-		template<class T>
-		void parseWindows(const T* pathStr, UINT32 numChars)
-		{
-			clear();
-
-			UINT32 idx = 0;
-			BasicStringStream<T> tempStream;
-
-			if (idx < numChars)
-			{
-				if (pathStr[idx] == '\\' || pathStr[idx] == '/')
-				{
-					mIsAbsolute = true;
-					idx++;
-				}
-			}
-
-			if (idx < numChars)
-			{
-				// Path starts with a node, a drive letter or is relative
-				if (mIsAbsolute && (pathStr[idx] == '\\' || pathStr[idx] == '/')) // Node
-				{
-					idx++;
-
-					tempStream.str(BasicString<T>());
-					tempStream.clear();
-					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
-						tempStream << pathStr[idx++];
-
-					setNode(tempStream.str());
-
-					if (idx < numChars)
-						idx++;
-				}
-				else // A drive letter or not absolute
-				{
-					T drive = pathStr[idx];
-					idx++;
-
-					if (idx < numChars && pathStr[idx] == ':')
-					{
-						if (mIsAbsolute || !((drive >= 'a' && drive <= 'z') || (drive >= 'A' && drive <= 'Z')))
-							throwInvalidPathException(BasicString<T>(pathStr, numChars));
-
-						mIsAbsolute = true;
-						setDevice(BansheeEngine::toWString(drive));
-
-						idx++;
-
-						if (idx >= numChars || (pathStr[idx] != '\\' && pathStr[idx] != '/'))
-							throwInvalidPathException(BasicString<T>(pathStr, numChars));
-
-						idx++;
-					}
-					else
-						idx--;
-				}
-
-				while (idx < numChars)
-				{
-					tempStream.str(BasicString<T>());
-					tempStream.clear();
-					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
-					{
-						tempStream << pathStr[idx];
-						idx++;
-					}
-
-					if (idx < numChars)
-						pushDirectory(tempStream.str());
-					else
-						setFilename(tempStream.str());
-
-					idx++;
-				}
-			}
-		}
-
-		/** Parses a Unix path and stores the parsed data internally. Throws an exception if parsing fails. */
-		template<class T>
-		void parseUnix(const T* pathStr, UINT32 numChars)
-		{
-			clear();
-
-			UINT32 idx = 0;
-			BasicStringStream<T> tempStream;
-
-			if (idx < numChars)
-			{
-				if (pathStr[idx] == '/')
-				{
-					mIsAbsolute = true;
-					idx++;
-				}
-				else if (pathStr[idx] == '~')
-				{
-					idx++;
-					if (idx >= numChars || pathStr[idx] == '/')
-					{
-						pushDirectory(BansheeEngine::toWString('~'));
-						mIsAbsolute = true;
-					}
-					else
-						idx--;
-				}
-
-				while (idx < numChars)
-				{
-					tempStream.str(BasicString<T>());
-					tempStream.clear();
-					while (idx < numChars && pathStr[idx] != '/')
-					{
-						tempStream << pathStr[idx];
-						idx++;
-					}
-
-					if (idx < numChars)
-					{
-						if (mDirectories.empty())
-						{
-							BasicString<T> deviceStr = tempStream.str();
-							if (!deviceStr.empty() && *(deviceStr.rbegin()) == ':')
-							{
-								setDevice(deviceStr.substr(0, deviceStr.length() - 1));
-								mIsAbsolute = true;
-							}
-							else
-							{
-								pushDirectory(deviceStr);
-							}
-						}
-						else
-						{
-							pushDirectory(tempStream.str());
-						}
-					}
-					else
-					{
-						setFilename(tempStream.str());
-					}
-
-					idx++;
-				}
-			}
-		}
-
-		void setNode(const WString& node) { mNode = node; }
-		void setNode(const String& node) { mNode = BansheeEngine::toWString(node); }
-
-		void setDevice(const WString& device) { mDevice = device; }
-		void setDevice(const String& device) { mDevice = BansheeEngine::toWString(device); }
-
-		/** Build a Windows path string from internal path data. */
-		WString buildWindows() const;
-
-		/** Build a Unix path string from internal path data. */
-		WString buildUnix() const;
-
-		/** Add new directory to the end of the path. */
-		void pushDirectory(const WString& dir);
-
-		/** Add new directory to the end of the path. */
-		void pushDirectory(const String& dir);
-
-		/** Helper method that throws invalid path exception. */
-		void throwInvalidPathException(const WString& path) const;
-
-		/** Helper method that throws invalid path exception. */
-		void throwInvalidPathException(const String& path) const;
-	private:
-		friend struct RTTIPlainType<Path>; // For serialization
-		friend struct ::std::hash<BansheeEngine::Path>;
-
-		Vector<WString> mDirectories;
-		WString mDevice;
-		WString mFilename;
-		WString mNode;
-		bool mIsAbsolute;
-	};
-
-	/** @cond SPECIALIZATIONS */
-
-	/**
-	 * RTTIPlainType specialization for Path that allows paths be serialized as value types.
-	 *
-	 * @see		RTTIPlainType
-	 */
-	template<> struct RTTIPlainType<Path>
-	{
-		enum { id = TID_Path }; enum { hasDynamicSize = 1 };
-
-		static void toMemory(const Path& data, char* memory)
-		{
-			UINT32 size = getDynamicSize(data);
-			memcpy(memory, &size, sizeof(UINT32));
-			memory += sizeof(UINT32);
-
-			memory = rttiWriteElem(data.mDevice, memory);
-			memory = rttiWriteElem(data.mNode, memory);
-			memory = rttiWriteElem(data.mFilename, memory);
-			memory = rttiWriteElem(data.mIsAbsolute, memory);
-			memory = rttiWriteElem(data.mDirectories, memory);
-		}
-
-		static UINT32 fromMemory(Path& data, char* memory)
-		{
-			UINT32 size;
-			memcpy(&size, memory, sizeof(UINT32));
-			memory += sizeof(UINT32);
-
-			memory = rttiReadElem(data.mDevice, memory);
-			memory = rttiReadElem(data.mNode, memory);
-			memory = rttiReadElem(data.mFilename, memory);
-			memory = rttiReadElem(data.mIsAbsolute, memory);
-			memory = rttiReadElem(data.mDirectories, memory);
-
-			return size;
-		}
-
-		static UINT32 getDynamicSize(const Path& data)
-		{
-			UINT64 dataSize = rttiGetElemSize(data.mDevice) + rttiGetElemSize(data.mNode) + rttiGetElemSize(data.mFilename) +
-				rttiGetElemSize(data.mIsAbsolute) + rttiGetElemSize(data.mDirectories) + sizeof(UINT32);
-
-#if BS_DEBUG_MODE
-			if (dataSize > std::numeric_limits<UINT32>::max())
-			{
-				__string_throwDataOverflowException();
-			}
-#endif
-
-			return (UINT32)dataSize;
-		}
-	};
-
-	/** @endcond */
-}
-
-/** @cond STDLIB */
-
-/** Hash value generator for Path. */
-template<>
-struct std::hash<BansheeEngine::Path>
-{
-	size_t operator()(const BansheeEngine::Path& path) const
-	{
-		size_t hash = 0;
-		BansheeEngine::hash_combine(hash, path.mFilename);
-		BansheeEngine::hash_combine(hash, path.mDevice);
-		BansheeEngine::hash_combine(hash, path.mNode);
-
-		for (auto& dir : path.mDirectories)
-			BansheeEngine::hash_combine(hash, dir);
-
-		return hash;
-	}
-};
-
-/** @endcond */
-
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+/** @addtogroup Filesystem
+ *  @{
+ */
+
+namespace BansheeEngine
+{
+	/**
+	 * Class for storing and manipulating file paths. Paths may be parsed from and to raw strings according to various 
+	 * platform specific path types.
+	 *
+	 * @note	
+	 * In order to allow the system to easily distinguish between file and directory paths, try to ensure that all directory
+	 * paths end with a separator (\ or / depending on platform). System won't fail if you don't but it will be easier to 
+	 * misuse.
+	 */
+	class BS_UTILITY_EXPORT Path
+	{
+	public:
+		enum class PathType
+		{
+			Windows,
+			Unix,
+			Default
+		};
+
+	public:
+		Path();
+
+		/**
+		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		Path(const WString& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		Path(const String& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is not 
+		 * valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		Path(wchar_t* pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is 
+		 * not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		Path(const char* pathStr, PathType type = PathType::Default);
+		Path(const Path& other);
+
+		/**
+		 * Assigns a path by parsing the provided path string. Path will be parsed according to the rules of the platform 
+		 * the application is being compiled to.
+		 */
+		Path& operator= (const WString& pathStr);
+
+		/**
+		 * Assigns a path by parsing the provided path string. Path will be parsed according to the rules of the platform 
+		 * the application is being compiled to.
+		 */
+		Path& operator= (const String& pathStr);
+
+		/**
+		 * Assigns a path by parsing the provided path null terminated string. Path will be parsed according to the rules 
+		 * of the platform the application is being compiled to.
+		 */
+		Path& operator= (const wchar_t* pathStr);
+
+		/**
+		 * Assigns a path by parsing the provided path null terminated string. Path will be parsed according to the rules 
+		 * of the platform the application is being compiled to.
+		 */
+		Path& operator= (const char* pathStr);
+
+		Path& operator= (const Path& path);
+
+		/**
+		 * Compares two paths and returns true if they match. Comparison is case insensitive and paths will be compared 
+		 * as-is, without canonization.
+		 */
+		bool operator== (const Path& path) const { return equals(path); }
+
+		/**
+		 * Compares two paths and returns true if they don't match. Comparison is case insensitive and paths will be 
+		 * compared as-is, without canonization.
+		 */
+		bool operator!= (const Path& path) const { return !equals(path); }
+
+		/** Gets a directory name with the specified index from the path. */
+		const WString& operator[] (UINT32 idx) const { return getWDirectory(idx); }
+
+		/** Swap internal data with another Path object. */
+		void swap(Path& path);
+
+		/**	Create a path from another Path object. */
+		void assign(const Path& path);
+
+		/**
+		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const WString& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided path string. Throws exception if provided path is not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application 
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const String& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is not 
+		 * valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const wchar_t* pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided path null terminated string. Throws exception if provided path is not 
+		 * valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application 
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const char* pathStr, PathType type = PathType::Default);
+
+		/**
+		 * Converts the path in a string according to platform path rules.
+		 *
+		 * @param[in] type	If set to default path will be parsed according to the rules of the platform the application is 
+		 *					being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		WString toWString(PathType type = PathType::Default) const;
+
+		/**
+		 * Converts the path in a string according to platform path rules.
+		 *
+		 * @param[in] type	If set to default path will be parsed according to the rules of the platform the application is 
+		 *					being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		String toString(PathType type = PathType::Default) const;
+
+		/** Checks is the path a directory (contains no file-name). */
+		bool isDirectory() const { return mFilename.empty(); }
+
+		/** Checks does the path point to a file. */
+		bool isFile() const { return !mFilename.empty(); }
+
+		/** Checks is the contained path absolute. */
+		bool isAbsolute() const { return mIsAbsolute; }
+
+		/**
+		 * Returns parent path. If current path points to a file the parent path will be the folder where the file is located.
+		 * Or if it contains a directory the parent will be the parent directory. If no parent exists, same path will be 
+		 * returned.
+		 */
+		Path getParent() const;
+
+		/**
+		 * Returns an absolute path by appending the current path to the provided base. If path was already absolute no 
+		 * changes are made and copy of current path is returned. If base is not absolute, then the returned path will be 
+		 * made relative to base, but will not be absolute.
+		 */
+		Path getAbsolute(const Path& base) const;
+
+		/**
+		 * Returns a relative path by making the current path relative to the provided base. Base must be a part of the 
+		 * current path. If base is not a part of the path no changes are made and a copy of the current path is returned.
+		 */
+		Path getRelative(const Path& base) const;
+
+		/**
+		 * Returns the path as a path to directory. If path was pointing to a file, the filename is removed, otherwise no 
+		 * changes are made and exact copy is returned.
+		 */
+		Path getDirectory() const;
+
+		/**
+		 * Makes the path the parent of the current path. If current path points to a file the parent path will be the 
+		 * folder where the file is located. Or if it contains a directory the parent will be the parent directory. If no 
+		 * parent exists, same path will be returned.
+		 */
+		Path& makeParent();
+
+		/**
+		 * Makes the current path absolute by appending it to base. If path was already absolute no changes are made and 
+		 * copy of current path is returned. If base is not absolute, then the returned path will be made relative to base,
+		 * but will not be absolute.
+		 */
+		Path& makeAbsolute(const Path& base);
+
+		/**
+		 * Makes the current path relative to the provided base. Base must be a part of the current path. If base is not 
+		 * a part of the path no changes are made and a copy of the current path is returned.
+		 */
+		Path& makeRelative(const Path& base);
+
+		/** Appends another path to the end of this path. */
+		Path& append(const Path& path);
+
+		/**
+		 * Checks if the current path contains the provided path. Comparison is case insensitive and paths will be compared 
+		 * as-is, without canonization.
+		 */
+		bool includes(const Path& child) const;
+
+		/**
+		 * Compares two paths and returns true if they match. Comparison is case insensitive and paths will be compared 
+		 * as-is, without canonization.
+		 */
+		bool equals(const Path& other) const;
+
+		/** Change or set the filename in the path. */
+		void setFilename(const WString& filename) { mFilename = filename; }
+
+		/** Change or set the filename in the path. */
+		void setFilename(const String& filename) { mFilename = BansheeEngine::toWString(filename); }
+
+		/**
+		 * Change or set the base name in the path. Base name changes the filename by changing its base to the provided 
+		 * value but keeping extension intact.
+		 */
+		void setBasename(const WString& basename);
+
+		/**
+		 * Change or set the base name in the path. Base name changes the filename by changing its base to the provided 
+		 * value but keeping extension intact.
+		 */
+		void setBasename(const String& basename);
+
+		/**
+		 * Change or set the extension of the filename in the path.
+		 *
+		 * @param[in]	extension	Extension with a leading ".".
+		 */
+		void setExtension(const WString& extension);
+
+		/**
+		 * Change or set the extension of the filename in the path.
+		 *
+		 * @param[in]	extension	Extension with a leading ".".
+		 */
+		void setExtension(const String& extension);
+
+		/**
+		 * Returns a filename in the path.
+		 *
+		 * @param[in]	extension	If true, returned filename will contain an extension.
+		 */
+		WString getWFilename(bool extension = true) const;
+
+		/**
+		 * Returns a filename in the path.
+		 *
+		 * @param[in]	extension	If true, returned filename will contain an extension.
+		 */
+		String getFilename(bool extension = true) const;
+
+		/** Returns file extension with the leading ".". */
+		WString getWExtension() const;
+
+		/** Returns file extension with the leading ".". */
+		String getExtension() const;
+
+		/** Gets the number of directories in the path. */
+		UINT32 getNumDirectories() const { return (UINT32)mDirectories.size(); }
+
+		/** Gets a directory name with the specified index from the path. */
+		const WString& getWDirectory(UINT32 idx) const;
+
+		/** Gets a directory name with the specified index from the path. */
+		String getDirectory(UINT32 idx) const;
+
+		/** Returns path device (e.g. drive, volume, etc.) if one exists in the path. */
+		const WString& getWDevice() const { return mDevice; }
+
+		/** Returns path device (e.g. drive, volume, etc.) if one exists in the path. */
+		String getDevice() const { return BansheeEngine::toString(mDevice); }
+
+		/** Returns path node (e.g. network name) if one exists in the path. */
+		const WString& getWNode() const { return mNode; }
+
+		/** Returns path node (e.g. network name) if one exists in the path. */
+		String getNode() const { return BansheeEngine::toString(mNode); }
+
+		/**
+		 * Gets last element in the path, filename if it exists, otherwise the last directory. If no directories exist 
+		 * returns device or node.
+		 *
+		 * @param[in]	type	Determines format of node or device, in case they are returned. When default, format for 
+		 *						the active platform will be used, otherwise the format defined by the parameter will be used.
+		 */
+		WString getWTail(PathType type = PathType::Default) const;
+
+		/**
+		 * Gets last element in the path, filename if it exists, otherwise the last directory. If no directories exist 
+		 * returns device or node.
+		 *
+		 * @param[in]	type	Determines format of node or device, in case they are returned. When default, format for the
+		 *						active platform will be used, otherwise the format defined by the parameter will be used.
+		 */
+		String getTail(PathType type = PathType::Default) const;
+
+		/** Clears the path to nothing. */
+		void clear();
+
+		/** Returns true if no path has been set. */
+		bool isEmpty() const { return mDirectories.empty() && mFilename.empty() && mDevice.empty() && mNode.empty(); }
+
+		/** Concatenates two paths. */
+		Path operator+ (const Path& rhs) const;
+
+		/** Concatenates two paths. */
+		Path& operator+= (const Path& rhs);
+
+		/** Compares two path elements (i.e. filenames, directory names, etc.). */
+		static bool comparePathElem(const WString& left, const WString& right);
+
+		/** Combines two paths and returns the result. Right path should be relative. */
+		static Path combine(const Path& left, const Path& right);
+
+		static const Path BLANK;
+	private:
+		/**
+		 * Constructs a path by parsing the provided raw string data. Throws exception if provided path is not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application 
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const wchar_t* pathStr, UINT32 numChars, PathType type = PathType::Default);
+
+		/**
+		 * Constructs a path by parsing the provided raw string data. Throws exception if provided path is not valid.
+		 *
+		 * @param[in]	type	If set to default path will be parsed according to the rules of the platform the application
+		 *						is being compiled to. Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const char* pathStr, UINT32 numChars, PathType type = PathType::Default);
+
+		/** Parses a Windows path and stores the parsed data internally. Throws an exception if parsing fails. */
+		template<class T>
+		void parseWindows(const T* pathStr, UINT32 numChars)
+		{
+			clear();
+
+			UINT32 idx = 0;
+			BasicStringStream<T> tempStream;
+
+			if (idx < numChars)
+			{
+				if (pathStr[idx] == '\\' || pathStr[idx] == '/')
+				{
+					mIsAbsolute = true;
+					idx++;
+				}
+			}
+
+			if (idx < numChars)
+			{
+				// Path starts with a node, a drive letter or is relative
+				if (mIsAbsolute && (pathStr[idx] == '\\' || pathStr[idx] == '/')) // Node
+				{
+					idx++;
+
+					tempStream.str(BasicString<T>());
+					tempStream.clear();
+					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
+						tempStream << pathStr[idx++];
+
+					setNode(tempStream.str());
+
+					if (idx < numChars)
+						idx++;
+				}
+				else // A drive letter or not absolute
+				{
+					T drive = pathStr[idx];
+					idx++;
+
+					if (idx < numChars && pathStr[idx] == ':')
+					{
+						if (mIsAbsolute || !((drive >= 'a' && drive <= 'z') || (drive >= 'A' && drive <= 'Z')))
+							throwInvalidPathException(BasicString<T>(pathStr, numChars));
+
+						mIsAbsolute = true;
+						setDevice(BansheeEngine::toWString(drive));
+
+						idx++;
+
+						if (idx >= numChars || (pathStr[idx] != '\\' && pathStr[idx] != '/'))
+							throwInvalidPathException(BasicString<T>(pathStr, numChars));
+
+						idx++;
+					}
+					else
+						idx--;
+				}
+
+				while (idx < numChars)
+				{
+					tempStream.str(BasicString<T>());
+					tempStream.clear();
+					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
+					{
+						tempStream << pathStr[idx];
+						idx++;
+					}
+
+					if (idx < numChars)
+						pushDirectory(tempStream.str());
+					else
+						setFilename(tempStream.str());
+
+					idx++;
+				}
+			}
+		}
+
+		/** Parses a Unix path and stores the parsed data internally. Throws an exception if parsing fails. */
+		template<class T>
+		void parseUnix(const T* pathStr, UINT32 numChars)
+		{
+			clear();
+
+			UINT32 idx = 0;
+			BasicStringStream<T> tempStream;
+
+			if (idx < numChars)
+			{
+				if (pathStr[idx] == '/')
+				{
+					mIsAbsolute = true;
+					idx++;
+				}
+				else if (pathStr[idx] == '~')
+				{
+					idx++;
+					if (idx >= numChars || pathStr[idx] == '/')
+					{
+						pushDirectory(BansheeEngine::toWString('~'));
+						mIsAbsolute = true;
+					}
+					else
+						idx--;
+				}
+
+				while (idx < numChars)
+				{
+					tempStream.str(BasicString<T>());
+					tempStream.clear();
+					while (idx < numChars && pathStr[idx] != '/')
+					{
+						tempStream << pathStr[idx];
+						idx++;
+					}
+
+					if (idx < numChars)
+					{
+						if (mDirectories.empty())
+						{
+							BasicString<T> deviceStr = tempStream.str();
+							if (!deviceStr.empty() && *(deviceStr.rbegin()) == ':')
+							{
+								setDevice(deviceStr.substr(0, deviceStr.length() - 1));
+								mIsAbsolute = true;
+							}
+							else
+							{
+								pushDirectory(deviceStr);
+							}
+						}
+						else
+						{
+							pushDirectory(tempStream.str());
+						}
+					}
+					else
+					{
+						setFilename(tempStream.str());
+					}
+
+					idx++;
+				}
+			}
+		}
+
+		void setNode(const WString& node) { mNode = node; }
+		void setNode(const String& node) { mNode = BansheeEngine::toWString(node); }
+
+		void setDevice(const WString& device) { mDevice = device; }
+		void setDevice(const String& device) { mDevice = BansheeEngine::toWString(device); }
+
+		/** Build a Windows path string from internal path data. */
+		WString buildWindows() const;
+
+		/** Build a Unix path string from internal path data. */
+		WString buildUnix() const;
+
+		/** Add new directory to the end of the path. */
+		void pushDirectory(const WString& dir);
+
+		/** Add new directory to the end of the path. */
+		void pushDirectory(const String& dir);
+
+		/** Helper method that throws invalid path exception. */
+		void throwInvalidPathException(const WString& path) const;
+
+		/** Helper method that throws invalid path exception. */
+		void throwInvalidPathException(const String& path) const;
+	private:
+		friend struct RTTIPlainType<Path>; // For serialization
+		friend struct ::std::hash<BansheeEngine::Path>;
+
+		Vector<WString> mDirectories;
+		WString mDevice;
+		WString mFilename;
+		WString mNode;
+		bool mIsAbsolute;
+	};
+
+	/** @cond SPECIALIZATIONS */
+
+	/**
+	 * RTTIPlainType specialization for Path that allows paths be serialized as value types.
+	 *
+	 * @see		RTTIPlainType
+	 */
+	template<> struct RTTIPlainType<Path>
+	{
+		enum { id = TID_Path }; enum { hasDynamicSize = 1 };
+
+		static void toMemory(const Path& data, char* memory)
+		{
+			UINT32 size = getDynamicSize(data);
+			memcpy(memory, &size, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			memory = rttiWriteElem(data.mDevice, memory);
+			memory = rttiWriteElem(data.mNode, memory);
+			memory = rttiWriteElem(data.mFilename, memory);
+			memory = rttiWriteElem(data.mIsAbsolute, memory);
+			memory = rttiWriteElem(data.mDirectories, memory);
+		}
+
+		static UINT32 fromMemory(Path& data, char* memory)
+		{
+			UINT32 size;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			memory = rttiReadElem(data.mDevice, memory);
+			memory = rttiReadElem(data.mNode, memory);
+			memory = rttiReadElem(data.mFilename, memory);
+			memory = rttiReadElem(data.mIsAbsolute, memory);
+			memory = rttiReadElem(data.mDirectories, memory);
+
+			return size;
+		}
+
+		static UINT32 getDynamicSize(const Path& data)
+		{
+			UINT64 dataSize = rttiGetElemSize(data.mDevice) + rttiGetElemSize(data.mNode) + rttiGetElemSize(data.mFilename) +
+				rttiGetElemSize(data.mIsAbsolute) + rttiGetElemSize(data.mDirectories) + sizeof(UINT32);
+
+#if BS_DEBUG_MODE
+			if (dataSize > std::numeric_limits<UINT32>::max())
+			{
+				__string_throwDataOverflowException();
+			}
+#endif
+
+			return (UINT32)dataSize;
+		}
+	};
+
+	/** @endcond */
+}
+
+/** @cond STDLIB */
+
+/** Hash value generator for Path. */
+template<>
+struct std::hash<BansheeEngine::Path>
+{
+	size_t operator()(const BansheeEngine::Path& path) const
+	{
+		size_t hash = 0;
+		BansheeEngine::hash_combine(hash, path.mFilename);
+		BansheeEngine::hash_combine(hash, path.mDevice);
+		BansheeEngine::hash_combine(hash, path.mNode);
+
+		for (auto& dir : path.mDirectories)
+			BansheeEngine::hash_combine(hash, dir);
+
+		return hash;
+	}
+};
+
+/** @endcond */
+
 /** @} */

+ 206 - 206
Source/BansheeUtility/Include/BsRTTIReflectableField.h

@@ -1,207 +1,207 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsRTTIField.h"
-#include "BsIReflectable.h"
-
-namespace BansheeEngine
-{
-	/** @cond INTERNAL */
-	/** @addtogroup RTTI
-	 *  @{
-	 */
-
-	/**
-	 * Base class containing common functionality for a reflectable class field. 
-	 * 			
-	 * @note	
-	 * Reflectable fields are fields containing complex types deriving from IReflectable. They are serialized recursively 
-	 * and you may add/remove fields from them without breaking the serialized data.
-	 */
-	struct RTTIReflectableFieldBase : public RTTIField
-	{
-		/**
-		 * Retrieves the IReflectable value from the provided instance.
-		 * 			
-		 * @note	Field type must not be an array.
-		 */
-		virtual IReflectable& getValue(void* object) = 0;
-
-		/**
-		 * Retrieves the IReflectable value from an array on the provided instance and index.
-		 * 			
-		 * @note	Field type must be an array.
-		 */
-		virtual IReflectable& getArrayValue(void* object, UINT32 index) = 0;
-
-		/**
-		 * Sets the IReflectable value in the provided instance.
-		 * 			
-		 * @note	Field type must not be an array.
-		 */
-		virtual void setValue(void* object, IReflectable& value) = 0;
-
-		/**
-		 * Sets the IReflectable value in an array on the provided instance and index.
-		 * 			
-		 * @note	Field type must be an array.
-		 */
-		virtual void setArrayValue(void* object, UINT32 index, IReflectable& value) = 0;
-
-		/** Creates a new object of the field type. */
-		virtual std::shared_ptr<IReflectable> newObject() = 0;
-
-		/** @copydoc RTTIField::hasDynamicSize */
-		bool hasDynamicSize() override { return true; }
-
-		/** Retrieves the RTTI object for the type the field contains. */
-		virtual RTTITypeBase* getType() = 0;
-	};
-
-	/**	Reflectable field containing a specific type with RTTI implemented. */
-	template <class DataType, class ObjectType>
-	struct RTTIReflectableField : public RTTIReflectableFieldBase
-	{
-		/**
-		 * Initializes a field containing a single data type implementing IReflectable interface. 
-		 *
-		 * @param[in]	name		Name of the field.
-		 * @param[in]	uniqueId	Unique identifier for this field. Although name is also a unique identifier we want a 
-		 *							small data type that can be used for efficiently serializing data to disk and similar. 
-		 *							It is primarily used for compatibility between different versions of serialized data.
-		 * @param[in]	getter  	The getter method for the field. Must be a specific signature: DataType&(ObjectType*)
-		 * @param[in]	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, DataType)
-		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See "RTTIFieldFlag".
-		 */
-		void initSingle(const String& name, UINT16 uniqueId, Any getter, Any setter, UINT64 flags)
-		{
-			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_Reflectable, flags);
-		}
-
-		/**
-		 * @brief	Initializes a field containing an array of data types implementing IReflectable interface.
-		 *
-		 * @param[in]	name		Name of the field.
-		 * @param[in]	uniqueId	Unique identifier for this field. Although name is also a unique identifier we want a 
-		 *							small data type that can be used for efficiently serializing data to disk and similar. 
-		 *							It is primarily used for compatibility between different versions of serialized data.
-		 * @param[in]	getter  	The getter method for the field. Must be a specific signature: DataType&(ObjectType*, UINT32)
-		 * @param[in]	getSize 	Getter method that returns the size of an array. Must be a specific signature: UINT32(ObjectType*)
-		 * @param[in]	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, UINT32, DataType)
-		 * @param[in]	setSize 	Setter method that allows you to resize an array. Must be a specific signature: void(ObjectType*, UINT32)
-		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See "RTTIFieldFlag".
-		 */
-		void initArray(const String& name, UINT16 uniqueId, Any getter,
-			Any getSize, Any setter, Any setSize, UINT64 flags)
-		{
-			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_Reflectable, flags);
-		}
-
-		/** @copydoc RTTIField::getTypeSize */
-		UINT32 getTypeSize() override
-		{
-			return 0; // Complex types don't store size the conventional way
-		}
-
-		/** @copydoc RTTIReflectableFieldBase::getValue */
-		IReflectable& getValue(void* object) override
-		{
-			checkIsArray(false);
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			std::function<DataType&(ObjectType*)> f = any_cast<std::function<DataType&(ObjectType*)>>(valueGetter);
-			IReflectable& castDataType = f(castObjType);
-
-			return castDataType;
-		}
-
-		/** @copydoc RTTIReflectableFieldBase::getArrayValue */
-		IReflectable& getArrayValue(void* object, UINT32 index) override
-		{
-			checkIsArray(true);
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			std::function<DataType&(ObjectType*, UINT32)> f = any_cast<std::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
-
-			IReflectable& castDataType = f(castObjType, index);
-			return castDataType;
-		}
-
-		/** @copydoc RTTIReflectableFieldBase::setValue */
-		void setValue(void* object, IReflectable& value) override
-		{
-			checkIsArray(false);
-
-			if(valueSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException,
-					"Specified field (" + mName + ") has no setter.");
-			}
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			DataType& castDataObj = static_cast<DataType&>(value);
-			std::function<void(ObjectType*, DataType&)> f = any_cast<std::function<void(ObjectType*, DataType&)>>(valueSetter);
-			f(castObjType, castDataObj);
-		}
-
-		/** @copydoc RTTIReflectableFieldBase::setArrayValue */
-		void setArrayValue(void* object, UINT32 index, IReflectable& value) override
-		{
-			checkIsArray(true);
-
-			if(valueSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Specified field (" + mName + ") has no setter.");
-			}
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			DataType& castDataObj = static_cast<DataType&>(value);
-			std::function<void(ObjectType*, UINT32, DataType&)> f = any_cast<std::function<void(ObjectType*, UINT32, DataType&)>>(valueSetter);
-			f(castObjType, index, castDataObj);
-		}
-
-		/** @copydoc RTTIField::getArraySize */
-		UINT32 getArraySize(void* object) override
-		{
-			checkIsArray(true);
-
-			std::function<UINT32(ObjectType*)> f = any_cast<std::function<UINT32(ObjectType*)>>(arraySizeGetter);
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-			return f(castObject);
-		}
-
-		/** @copydoc RTTIField::setArraySize */
-		void setArraySize(void* object, UINT32 size) override
-		{
-			checkIsArray(true);
-
-			if(arraySizeSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Specified field (" + mName + ") has no array size setter.");
-			}
-
-			std::function<void(ObjectType*, UINT32)> f = any_cast<std::function<void(ObjectType*, UINT32)>>(arraySizeSetter);
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-			f(castObject, size);
-		}
-
-		/** @copydoc RTTIReflectableFieldBase::newObject */
-		std::shared_ptr<IReflectable> newObject() override
-		{
-			return DataType::getRTTIStatic()->newRTTIObject();
-		}
-
-		/** @copydoc RTTIReflectableFieldBase::getType */
-		RTTITypeBase* getType() override
-		{
-			return DataType::getRTTIStatic();
-		}
-	};
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsRTTIField.h"
+#include "BsIReflectable.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup RTTI
+	 *  @{
+	 */
+
+	/**
+	 * Base class containing common functionality for a reflectable class field. 
+	 * 			
+	 * @note	
+	 * Reflectable fields are fields containing complex types deriving from IReflectable. They are serialized recursively 
+	 * and you may add/remove fields from them without breaking the serialized data.
+	 */
+	struct RTTIReflectableFieldBase : public RTTIField
+	{
+		/**
+		 * Retrieves the IReflectable value from the provided instance.
+		 * 			
+		 * @note	Field type must not be an array.
+		 */
+		virtual IReflectable& getValue(void* object) = 0;
+
+		/**
+		 * Retrieves the IReflectable value from an array on the provided instance and index.
+		 * 			
+		 * @note	Field type must be an array.
+		 */
+		virtual IReflectable& getArrayValue(void* object, UINT32 index) = 0;
+
+		/**
+		 * Sets the IReflectable value in the provided instance.
+		 * 			
+		 * @note	Field type must not be an array.
+		 */
+		virtual void setValue(void* object, IReflectable& value) = 0;
+
+		/**
+		 * Sets the IReflectable value in an array on the provided instance and index.
+		 * 			
+		 * @note	Field type must be an array.
+		 */
+		virtual void setArrayValue(void* object, UINT32 index, IReflectable& value) = 0;
+
+		/** Creates a new object of the field type. */
+		virtual std::shared_ptr<IReflectable> newObject() = 0;
+
+		/** @copydoc RTTIField::hasDynamicSize */
+		bool hasDynamicSize() override { return true; }
+
+		/** Retrieves the RTTI object for the type the field contains. */
+		virtual RTTITypeBase* getType() = 0;
+	};
+
+	/**	Reflectable field containing a specific type with RTTI implemented. */
+	template <class DataType, class ObjectType>
+	struct RTTIReflectableField : public RTTIReflectableFieldBase
+	{
+		/**
+		 * Initializes a field containing a single data type implementing IReflectable interface. 
+		 *
+		 * @param[in]	name		Name of the field.
+		 * @param[in]	uniqueId	Unique identifier for this field. Although name is also a unique identifier we want a 
+		 *							small data type that can be used for efficiently serializing data to disk and similar. 
+		 *							It is primarily used for compatibility between different versions of serialized data.
+		 * @param[in]	getter  	The getter method for the field. Must be a specific signature: DataType&(ObjectType*)
+		 * @param[in]	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, DataType)
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See "RTTIFieldFlag".
+		 */
+		void initSingle(const String& name, UINT16 uniqueId, Any getter, Any setter, UINT64 flags)
+		{
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_Reflectable, flags);
+		}
+
+		/**
+		 * Initializes a field containing an array of data types implementing IReflectable interface.
+		 *
+		 * @param[in]	name		Name of the field.
+		 * @param[in]	uniqueId	Unique identifier for this field. Although name is also a unique identifier we want a 
+		 *							small data type that can be used for efficiently serializing data to disk and similar. 
+		 *							It is primarily used for compatibility between different versions of serialized data.
+		 * @param[in]	getter  	The getter method for the field. Must be a specific signature: DataType&(ObjectType*, UINT32)
+		 * @param[in]	getSize 	Getter method that returns the size of an array. Must be a specific signature: UINT32(ObjectType*)
+		 * @param[in]	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, UINT32, DataType)
+		 * @param[in]	setSize 	Setter method that allows you to resize an array. Must be a specific signature: void(ObjectType*, UINT32)
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See "RTTIFieldFlag".
+		 */
+		void initArray(const String& name, UINT16 uniqueId, Any getter,
+			Any getSize, Any setter, Any setSize, UINT64 flags)
+		{
+			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_Reflectable, flags);
+		}
+
+		/** @copydoc RTTIField::getTypeSize */
+		UINT32 getTypeSize() override
+		{
+			return 0; // Complex types don't store size the conventional way
+		}
+
+		/** @copydoc RTTIReflectableFieldBase::getValue */
+		IReflectable& getValue(void* object) override
+		{
+			checkIsArray(false);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			std::function<DataType&(ObjectType*)> f = any_cast<std::function<DataType&(ObjectType*)>>(valueGetter);
+			IReflectable& castDataType = f(castObjType);
+
+			return castDataType;
+		}
+
+		/** @copydoc RTTIReflectableFieldBase::getArrayValue */
+		IReflectable& getArrayValue(void* object, UINT32 index) override
+		{
+			checkIsArray(true);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			std::function<DataType&(ObjectType*, UINT32)> f = any_cast<std::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
+
+			IReflectable& castDataType = f(castObjType, index);
+			return castDataType;
+		}
+
+		/** @copydoc RTTIReflectableFieldBase::setValue */
+		void setValue(void* object, IReflectable& value) override
+		{
+			checkIsArray(false);
+
+			if(valueSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException,
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			DataType& castDataObj = static_cast<DataType&>(value);
+			std::function<void(ObjectType*, DataType&)> f = any_cast<std::function<void(ObjectType*, DataType&)>>(valueSetter);
+			f(castObjType, castDataObj);
+		}
+
+		/** @copydoc RTTIReflectableFieldBase::setArrayValue */
+		void setArrayValue(void* object, UINT32 index, IReflectable& value) override
+		{
+			checkIsArray(true);
+
+			if(valueSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			DataType& castDataObj = static_cast<DataType&>(value);
+			std::function<void(ObjectType*, UINT32, DataType&)> f = any_cast<std::function<void(ObjectType*, UINT32, DataType&)>>(valueSetter);
+			f(castObjType, index, castDataObj);
+		}
+
+		/** @copydoc RTTIField::getArraySize */
+		UINT32 getArraySize(void* object) override
+		{
+			checkIsArray(true);
+
+			std::function<UINT32(ObjectType*)> f = any_cast<std::function<UINT32(ObjectType*)>>(arraySizeGetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			return f(castObject);
+		}
+
+		/** @copydoc RTTIField::setArraySize */
+		void setArraySize(void* object, UINT32 size) override
+		{
+			checkIsArray(true);
+
+			if(arraySizeSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no array size setter.");
+			}
+
+			std::function<void(ObjectType*, UINT32)> f = any_cast<std::function<void(ObjectType*, UINT32)>>(arraySizeSetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			f(castObject, size);
+		}
+
+		/** @copydoc RTTIReflectableFieldBase::newObject */
+		std::shared_ptr<IReflectable> newObject() override
+		{
+			return DataType::getRTTIStatic()->newRTTIObject();
+		}
+
+		/** @copydoc RTTIReflectableFieldBase::getType */
+		RTTITypeBase* getType() override
+		{
+			return DataType::getRTTIStatic();
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 280 - 283
Source/BansheeUtility/Include/BsStringFormat.h

@@ -1,284 +1,281 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-namespace BansheeEngine
-{
-	/** @cond INTERNAL */
-	/** @addtogroup String
-	 *  @{
-	 */
-
-	/** Helper class used for string formatting operations. */
-	class StringFormat
-	{
-	private:
-		/**
-		 * Data structure used during string formatting. It holds information about parameter identifiers to replace with
-		 * actual parameters.
-		 */
-		struct FormatParamRange
-		{
-			FormatParamRange() { }
-			FormatParamRange(UINT32 start, UINT32 identifierSize, UINT32 paramIdx)
-				:start(start), identifierSize(identifierSize), paramIdx(paramIdx)
-			{ }
-
-			UINT32 start;
-			UINT32 identifierSize;
-			UINT32 paramIdx;
-		};
-
-		/**
-		 * @brief	Structure that holds value of a parameter during string
-		 *			formatting.
-		 */
-		template<class T>
-		struct ParamData
-		{
-			T* buffer;
-			UINT32 size;
-		};
-
-	public:
-		/**
-		 * Formats the provided string by replacing the identifiers with the provided parameters. The identifiers are 
-		 * represented like "{0}, {1}" in the source string, where the number represents the position of the parameter 
-		 * that will be used for replacing the identifier.
-		 *			
-		 * @note	You may use "\" to escape identifier brackets.
-		 * @note	Maximum identifier number is 19 (for a total of 20 unique identifiers. e.g. {20} won't be recognized as an identifier).
-		 * @note	Total number of parameters that can be referenced is 200.
-		 */
-		template<class T, class... Args>
-		static BasicString<T> format(const T* source, Args&& ...args)
-		{
-			UINT32 strLength = getLength(source);
-
-			ParamData<T> parameters[MAX_PARAMS];
-			memset(parameters, 0, sizeof(parameters));
-			getParams(parameters, 0U, std::forward<Args>(args)...);
-
-			T bracketChars[MAX_IDENTIFIER_SIZE + 1];
-			UINT32 bracketWriteIdx = 0;
-
-			FormatParamRange paramRanges[MAX_PARAM_REFERENCES];
-			memset(paramRanges, 0, sizeof(paramRanges));
-			UINT32 paramRangeWriteIdx = 0;
-
-			// Determine parameter positions
-			INT32 lastBracket = -1;
-			bool escaped = false;
-			UINT32 charWriteIdx = 0;
-			for (UINT32 i = 0; i < strLength; i++)
-			{
-				if (source[i] == '\\' && !escaped && paramRangeWriteIdx < MAX_PARAM_REFERENCES)
-				{
-					escaped = true;
-					paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, 1, (UINT32)-1);
-					continue;
-				}
-
-				if (lastBracket == -1)
-				{
-					// If current char is non-escaped opening bracket start parameter definition
-					if (source[i] == '{' && !escaped)
-						lastBracket = i;
-					else
-						charWriteIdx++;
-				}
-				else
-				{
-					if (isdigit(source[i]) && bracketWriteIdx < MAX_IDENTIFIER_SIZE)
-						bracketChars[bracketWriteIdx++] = source[i];
-					else
-					{
-						// If current char is non-escaped closing bracket end parameter definition
-						UINT32 numParamChars = bracketWriteIdx;
-						bool processedBracket = false;
-						if (source[i] == '}' && numParamChars > 0 && !escaped)
-						{
-							bracketChars[bracketWriteIdx] = '\0';
-							UINT32 paramIdx = strToInt(bracketChars);
-							if (paramIdx < MAX_PARAMS && paramRangeWriteIdx < MAX_PARAM_REFERENCES) // Check if exceeded maximum parameter limit
-							{
-								paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, numParamChars + 2, paramIdx);
-								charWriteIdx += parameters[paramIdx].size;
-
-								processedBracket = true;
-							}
-						}
-
-						if (!processedBracket)
-						{
-							// Last bracket wasn't really a parameter
-							for (UINT32 j = lastBracket; j <= i; j++)
-								charWriteIdx++;
-						}
-
-						lastBracket = -1;
-						bracketWriteIdx = 0;
-					}
-				}
-
-				escaped = false;
-			}
-
-			// Copy the clean string into output buffer
-			UINT32 finalStringSize = charWriteIdx;
-
-			T* outputBuffer = (T*)bs_alloc(finalStringSize * sizeof(T));
-			UINT32 copySourceIdx = 0;
-			UINT32 copyDestIdx = 0;
-			for (UINT32 i = 0; i < paramRangeWriteIdx; i++)
-			{
-				const FormatParamRange& rangeInfo = paramRanges[i];
-				UINT32 copySize = rangeInfo.start - copyDestIdx;
-				
-				memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, copySize * sizeof(T));
-				copySourceIdx += copySize + rangeInfo.identifierSize;
-				copyDestIdx += copySize;
-
-				if (rangeInfo.paramIdx == (UINT32)-1)
-					continue;
-
-				UINT32 paramSize = parameters[rangeInfo.paramIdx].size;
-				memcpy(outputBuffer + copyDestIdx, parameters[rangeInfo.paramIdx].buffer, paramSize * sizeof(T));
-				copyDestIdx += paramSize;
-			}
-
-			memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, (finalStringSize - copyDestIdx) * sizeof(T));
-
-			BasicString<T> outputStr(outputBuffer, finalStringSize);
-			bs_free(outputBuffer);
-
-			for (UINT32 i = 0; i < MAX_PARAMS; i++)
-			{
-				if (parameters[i].buffer != nullptr)
-					bs_free(parameters[i].buffer);
-			}
-
-			return outputStr;
-		}
-
-	private:
-		/**
-		 * Set of methods that can be specialized so we have a generalized way for retrieving length of strings of 
-		 * different types.
-		 */
-		static UINT32 getLength(const char* source) { return (UINT32)strlen(source); }
-
-		/**
-		 * Set of methods that can be specialized so we have a generalized way for retrieving length of strings of 
-		 * different types.
-		 */
-		static UINT32 getLength(const wchar_t* source) { return (UINT32)wcslen(source); }
-
-		/** Parses the string and returns an integer value extracted from string characters. */
-		static UINT32 strToInt(const char* buffer)
-		{
-			return (UINT32)strtoul(buffer, nullptr, 10);
-		}
-
-		/** Parses the string and returns an integer value extracted from string characters. */
-		static UINT32 strToInt(const wchar_t* buffer)
-		{
-			return (UINT32)wcstoul(buffer, nullptr, 10);
-		}
-
-		/**	Helper method for converting any data type to a narrow string. */
-		template<class T> static std::string toString(const T& param) { return std::to_string(param); }
-
-		/**	Helper method that "converts" a narrow string to a narrow string (simply a pass through). */
-		static std::string toString(const std::string& param) { return param; }
-
-		/**	Helper method that converts a Banshee narrow string to a standard narrow string. */
-		static std::string toString(const String& param)
-		{
-			return std::string(param.c_str());
-		}
-
-		/**	Helper method that converts a narrow character array to a narrow string. */
-		template<class T> static std::string toString(T* param) { static_assert("Invalid pointer type."); }
-
-		/**	Helper method that converts a narrow character array to a narrow string. */
-		static std::string toString(const char* param) { return std::string(param); }
-
-		/**	Helper method that converts a narrow character array to a narrow string. */
-		static std::string toString(char* param) { return std::string(param); }
-
-		/**	Helper method for converting any data type to a wide string. */
-		template<class T> static std::wstring toWString(const T& param) { return std::to_wstring(param); }
-
-		/**	Helper method that "converts" a wide string to a wide string (simply a pass through). */
-		static std::wstring toWString(const std::wstring& param) { return param; }
-
-		/**	Helper method that converts a Banshee wide string to a standard wide string. */
-		static std::wstring toWString(const WString& param)
-		{
-			return std::wstring(param.c_str());
-		}
-
-		/**	Helper method that converts a wide character array to a wide string. */
-		template<class T> static std::wstring toWString(T* param) { static_assert("Invalid pointer type."); }
-
-		/**	Helper method that converts a wide character array to a wide string. */
-		static std::wstring toWString(const wchar_t* param) { return std::wstring(param); }
-
-		/**	Helper method that converts a wide character array to a wide string. */
-		static std::wstring toWString(wchar_t* param) { return std::wstring(param); }
-
-		/**
-		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.
-		 */
-		template<class P, class... Args>
-		static void getParams(ParamData<char>* parameters, UINT32 idx, P&& param, Args&& ...args)
-		{
-			if (idx >= MAX_PARAMS)
-				return;
-
-			std::basic_string<char> sourceParam = toString(param);
-			parameters[idx].buffer = (char*)bs_alloc((UINT32)sourceParam.size() * sizeof(char));
-			parameters[idx].size = (UINT32)sourceParam.size();
-
-			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
-			
-			getParams(parameters, idx + 1, std::forward<Args>(args)...);
-		}
-
-		/**
-		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.
-		 */
-		template<class P, class... Args>
-		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx, P&& param, Args&& ...args)
-		{
-			if (idx >= MAX_PARAMS)
-				return;
-
-			std::basic_string<wchar_t> sourceParam = toWString(param);
-			parameters[idx].buffer = (wchar_t*)bs_alloc((UINT32)sourceParam.size() * sizeof(wchar_t));
-			parameters[idx].size = (UINT32)sourceParam.size();
-			
-			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
-
-			getParams(parameters, idx + 1, std::forward<Args>(args)...);
-		}
-
-		/** Helper method for parameter size calculation. Used as a stopping point in template recursion. */
-		static void getParams(ParamData<char>* parameters, UINT32 idx)
-		{
-			// Do nothing
-		}
-
-		/**	Helper method for parameter size calculation. Used as a stopping point in template recursion. */
-		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx)
-		{
-			// Do nothing
-		}
-
-		static const UINT32 MAX_PARAMS = 20;
-		static const UINT32 MAX_IDENTIFIER_SIZE = 2;
-		static const UINT32 MAX_PARAM_REFERENCES = 200;
-	};
-
-	/** @} */
-	/** @endcond */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup String
+	 *  @{
+	 */
+
+	/** Helper class used for string formatting operations. */
+	class StringFormat
+	{
+	private:
+		/**
+		 * Data structure used during string formatting. It holds information about parameter identifiers to replace with
+		 * actual parameters.
+		 */
+		struct FormatParamRange
+		{
+			FormatParamRange() { }
+			FormatParamRange(UINT32 start, UINT32 identifierSize, UINT32 paramIdx)
+				:start(start), identifierSize(identifierSize), paramIdx(paramIdx)
+			{ }
+
+			UINT32 start;
+			UINT32 identifierSize;
+			UINT32 paramIdx;
+		};
+
+		/** Structure that holds value of a parameter during string formatting. */
+		template<class T>
+		struct ParamData
+		{
+			T* buffer;
+			UINT32 size;
+		};
+
+	public:
+		/**
+		 * Formats the provided string by replacing the identifiers with the provided parameters. The identifiers are 
+		 * represented like "{0}, {1}" in the source string, where the number represents the position of the parameter 
+		 * that will be used for replacing the identifier.
+		 *			
+		 * @note	You may use "\" to escape identifier brackets.
+		 * @note	Maximum identifier number is 19 (for a total of 20 unique identifiers. e.g. {20} won't be recognized as an identifier).
+		 * @note	Total number of parameters that can be referenced is 200.
+		 */
+		template<class T, class... Args>
+		static BasicString<T> format(const T* source, Args&& ...args)
+		{
+			UINT32 strLength = getLength(source);
+
+			ParamData<T> parameters[MAX_PARAMS];
+			memset(parameters, 0, sizeof(parameters));
+			getParams(parameters, 0U, std::forward<Args>(args)...);
+
+			T bracketChars[MAX_IDENTIFIER_SIZE + 1];
+			UINT32 bracketWriteIdx = 0;
+
+			FormatParamRange paramRanges[MAX_PARAM_REFERENCES];
+			memset(paramRanges, 0, sizeof(paramRanges));
+			UINT32 paramRangeWriteIdx = 0;
+
+			// Determine parameter positions
+			INT32 lastBracket = -1;
+			bool escaped = false;
+			UINT32 charWriteIdx = 0;
+			for (UINT32 i = 0; i < strLength; i++)
+			{
+				if (source[i] == '\\' && !escaped && paramRangeWriteIdx < MAX_PARAM_REFERENCES)
+				{
+					escaped = true;
+					paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, 1, (UINT32)-1);
+					continue;
+				}
+
+				if (lastBracket == -1)
+				{
+					// If current char is non-escaped opening bracket start parameter definition
+					if (source[i] == '{' && !escaped)
+						lastBracket = i;
+					else
+						charWriteIdx++;
+				}
+				else
+				{
+					if (isdigit(source[i]) && bracketWriteIdx < MAX_IDENTIFIER_SIZE)
+						bracketChars[bracketWriteIdx++] = source[i];
+					else
+					{
+						// If current char is non-escaped closing bracket end parameter definition
+						UINT32 numParamChars = bracketWriteIdx;
+						bool processedBracket = false;
+						if (source[i] == '}' && numParamChars > 0 && !escaped)
+						{
+							bracketChars[bracketWriteIdx] = '\0';
+							UINT32 paramIdx = strToInt(bracketChars);
+							if (paramIdx < MAX_PARAMS && paramRangeWriteIdx < MAX_PARAM_REFERENCES) // Check if exceeded maximum parameter limit
+							{
+								paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, numParamChars + 2, paramIdx);
+								charWriteIdx += parameters[paramIdx].size;
+
+								processedBracket = true;
+							}
+						}
+
+						if (!processedBracket)
+						{
+							// Last bracket wasn't really a parameter
+							for (UINT32 j = lastBracket; j <= i; j++)
+								charWriteIdx++;
+						}
+
+						lastBracket = -1;
+						bracketWriteIdx = 0;
+					}
+				}
+
+				escaped = false;
+			}
+
+			// Copy the clean string into output buffer
+			UINT32 finalStringSize = charWriteIdx;
+
+			T* outputBuffer = (T*)bs_alloc(finalStringSize * sizeof(T));
+			UINT32 copySourceIdx = 0;
+			UINT32 copyDestIdx = 0;
+			for (UINT32 i = 0; i < paramRangeWriteIdx; i++)
+			{
+				const FormatParamRange& rangeInfo = paramRanges[i];
+				UINT32 copySize = rangeInfo.start - copyDestIdx;
+				
+				memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, copySize * sizeof(T));
+				copySourceIdx += copySize + rangeInfo.identifierSize;
+				copyDestIdx += copySize;
+
+				if (rangeInfo.paramIdx == (UINT32)-1)
+					continue;
+
+				UINT32 paramSize = parameters[rangeInfo.paramIdx].size;
+				memcpy(outputBuffer + copyDestIdx, parameters[rangeInfo.paramIdx].buffer, paramSize * sizeof(T));
+				copyDestIdx += paramSize;
+			}
+
+			memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, (finalStringSize - copyDestIdx) * sizeof(T));
+
+			BasicString<T> outputStr(outputBuffer, finalStringSize);
+			bs_free(outputBuffer);
+
+			for (UINT32 i = 0; i < MAX_PARAMS; i++)
+			{
+				if (parameters[i].buffer != nullptr)
+					bs_free(parameters[i].buffer);
+			}
+
+			return outputStr;
+		}
+
+	private:
+		/**
+		 * Set of methods that can be specialized so we have a generalized way for retrieving length of strings of 
+		 * different types.
+		 */
+		static UINT32 getLength(const char* source) { return (UINT32)strlen(source); }
+
+		/**
+		 * Set of methods that can be specialized so we have a generalized way for retrieving length of strings of 
+		 * different types.
+		 */
+		static UINT32 getLength(const wchar_t* source) { return (UINT32)wcslen(source); }
+
+		/** Parses the string and returns an integer value extracted from string characters. */
+		static UINT32 strToInt(const char* buffer)
+		{
+			return (UINT32)strtoul(buffer, nullptr, 10);
+		}
+
+		/** Parses the string and returns an integer value extracted from string characters. */
+		static UINT32 strToInt(const wchar_t* buffer)
+		{
+			return (UINT32)wcstoul(buffer, nullptr, 10);
+		}
+
+		/**	Helper method for converting any data type to a narrow string. */
+		template<class T> static std::string toString(const T& param) { return std::to_string(param); }
+
+		/**	Helper method that "converts" a narrow string to a narrow string (simply a pass through). */
+		static std::string toString(const std::string& param) { return param; }
+
+		/**	Helper method that converts a Banshee narrow string to a standard narrow string. */
+		static std::string toString(const String& param)
+		{
+			return std::string(param.c_str());
+		}
+
+		/**	Helper method that converts a narrow character array to a narrow string. */
+		template<class T> static std::string toString(T* param) { static_assert("Invalid pointer type."); }
+
+		/**	Helper method that converts a narrow character array to a narrow string. */
+		static std::string toString(const char* param) { return std::string(param); }
+
+		/**	Helper method that converts a narrow character array to a narrow string. */
+		static std::string toString(char* param) { return std::string(param); }
+
+		/**	Helper method for converting any data type to a wide string. */
+		template<class T> static std::wstring toWString(const T& param) { return std::to_wstring(param); }
+
+		/**	Helper method that "converts" a wide string to a wide string (simply a pass through). */
+		static std::wstring toWString(const std::wstring& param) { return param; }
+
+		/**	Helper method that converts a Banshee wide string to a standard wide string. */
+		static std::wstring toWString(const WString& param)
+		{
+			return std::wstring(param.c_str());
+		}
+
+		/**	Helper method that converts a wide character array to a wide string. */
+		template<class T> static std::wstring toWString(T* param) { static_assert("Invalid pointer type."); }
+
+		/**	Helper method that converts a wide character array to a wide string. */
+		static std::wstring toWString(const wchar_t* param) { return std::wstring(param); }
+
+		/**	Helper method that converts a wide character array to a wide string. */
+		static std::wstring toWString(wchar_t* param) { return std::wstring(param); }
+
+		/**
+		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.
+		 */
+		template<class P, class... Args>
+		static void getParams(ParamData<char>* parameters, UINT32 idx, P&& param, Args&& ...args)
+		{
+			if (idx >= MAX_PARAMS)
+				return;
+
+			std::basic_string<char> sourceParam = toString(param);
+			parameters[idx].buffer = (char*)bs_alloc((UINT32)sourceParam.size() * sizeof(char));
+			parameters[idx].size = (UINT32)sourceParam.size();
+
+			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
+			
+			getParams(parameters, idx + 1, std::forward<Args>(args)...);
+		}
+
+		/**
+		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.
+		 */
+		template<class P, class... Args>
+		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx, P&& param, Args&& ...args)
+		{
+			if (idx >= MAX_PARAMS)
+				return;
+
+			std::basic_string<wchar_t> sourceParam = toWString(param);
+			parameters[idx].buffer = (wchar_t*)bs_alloc((UINT32)sourceParam.size() * sizeof(wchar_t));
+			parameters[idx].size = (UINT32)sourceParam.size();
+			
+			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
+
+			getParams(parameters, idx + 1, std::forward<Args>(args)...);
+		}
+
+		/** Helper method for parameter size calculation. Used as a stopping point in template recursion. */
+		static void getParams(ParamData<char>* parameters, UINT32 idx)
+		{
+			// Do nothing
+		}
+
+		/**	Helper method for parameter size calculation. Used as a stopping point in template recursion. */
+		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx)
+		{
+			// Do nothing
+		}
+
+		static const UINT32 MAX_PARAMS = 20;
+		static const UINT32 MAX_IDENTIFIER_SIZE = 2;
+		static const UINT32 MAX_PARAM_REFERENCES = 200;
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 93 - 95
Source/BansheeUtility/Include/BsTestSuite.h

@@ -1,96 +1,94 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-/** @addtogroup Testing
- *  @{
- */
-
-/** Tests if condition is true, and reports unit test failure if it fails. */
-#define BS_TEST_ASSERT(expr) assertment((expr), "", __FILE__, __LINE__); 
-
-/** Tests if condition is true, and reports unit test failure with a message if it fails. */
-#define BS_TEST_ASSERT_MSG(expr, msg) assertment((expr), msg, __FILE__, __LINE__); 
-
-namespace BansheeEngine
-{
-	/**
-	 * Primary class for unit testing. Override and register unit tests in constructor then run the tests using the 
-	 * desired method of output.
-	 */
-	class BS_UTILITY_EXPORT TestSuite
-	{
-	public:
-		typedef void(TestSuite::*Func)();
-
-	private:
-		/** Contains data about a single unit test. */
-		struct TestEntry
-		{
-			TestEntry(Func test, const String& name);
-
-			Func test;
-			String name;
-		};
-
-	public:
-		virtual ~TestSuite() {}
-
-		/** Runs all the tests in the suite (and sub-suites). Tests results are reported to the provided output class. */
-		void run(TestOutput& output);
-
-		/** Adds a new child suite to this suite. This method allows you to group suites and execute them all at once. */
-		void add(const TestSuitePtr& suite);
-
-		/**	Creates a new suite of a particular type. */
-		template <class T>
-		static TestSuitePtr create()
-		{
-			static_assert((std::is_base_of<TestSuite, T>::value), "Invalid test suite type. It needs to derive from BansheeEngine::TestSuite.");
-
-			return std::static_pointer_cast<TestSuite>(bs_shared_ptr_new<T>());
-		}
-
-	protected:
-		TestSuite();
-
-		/** Called right before any tests are ran. */
-		virtual void startUp() {}
-
-		/**
-		 * @brief	Called after all tests and child suite's tests are ran.
-		 */
-		virtual void shutDown() {}
-
-		/**
-		 * Register a new unit test.
-		 *
-		 * @param[in]	test	Function to call in order to execute the test.
-		 * @param[in]	name	Name of the test we can use for referencing it later.
-		 */
-		void addTest(Func test, const String& name);
-
-		/**
-		 * Reports success or failure depending on the result of an expression.
-		 *
-		 * @param[in]	success		If true success is reported, otherwise failure.
-		 * @param[in]	file		Name of the source code file the assertment originates from.
-		 * @param[in]	line		Line number at which the assertment was triggered at.
-		 */
-		void assertment(bool success, const String& desc, const String& file, long line);
-
-		Vector<TestEntry> mTests;
-		Vector<TestSuitePtr> mSuites;
-
-		// Transient
-		TestOutput* mOutput;
-		String mActiveTestName;
-	};
-}
-
-/** Registers a new unit test within an implementation of TestSuite. */
-#define BS_ADD_TEST(func) addTest(static_cast<Func>(&func), #func);
-
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+/** @addtogroup Testing
+ *  @{
+ */
+
+/** Tests if condition is true, and reports unit test failure if it fails. */
+#define BS_TEST_ASSERT(expr) assertment((expr), "", __FILE__, __LINE__); 
+
+/** Tests if condition is true, and reports unit test failure with a message if it fails. */
+#define BS_TEST_ASSERT_MSG(expr, msg) assertment((expr), msg, __FILE__, __LINE__); 
+
+namespace BansheeEngine
+{
+	/**
+	 * Primary class for unit testing. Override and register unit tests in constructor then run the tests using the 
+	 * desired method of output.
+	 */
+	class BS_UTILITY_EXPORT TestSuite
+	{
+	public:
+		typedef void(TestSuite::*Func)();
+
+	private:
+		/** Contains data about a single unit test. */
+		struct TestEntry
+		{
+			TestEntry(Func test, const String& name);
+
+			Func test;
+			String name;
+		};
+
+	public:
+		virtual ~TestSuite() {}
+
+		/** Runs all the tests in the suite (and sub-suites). Tests results are reported to the provided output class. */
+		void run(TestOutput& output);
+
+		/** Adds a new child suite to this suite. This method allows you to group suites and execute them all at once. */
+		void add(const TestSuitePtr& suite);
+
+		/**	Creates a new suite of a particular type. */
+		template <class T>
+		static TestSuitePtr create()
+		{
+			static_assert((std::is_base_of<TestSuite, T>::value), "Invalid test suite type. It needs to derive from BansheeEngine::TestSuite.");
+
+			return std::static_pointer_cast<TestSuite>(bs_shared_ptr_new<T>());
+		}
+
+	protected:
+		TestSuite();
+
+		/** Called right before any tests are ran. */
+		virtual void startUp() {}
+
+		/**	Called after all tests and child suite's tests are ran. */
+		virtual void shutDown() {}
+
+		/**
+		 * Register a new unit test.
+		 *
+		 * @param[in]	test	Function to call in order to execute the test.
+		 * @param[in]	name	Name of the test we can use for referencing it later.
+		 */
+		void addTest(Func test, const String& name);
+
+		/**
+		 * Reports success or failure depending on the result of an expression.
+		 *
+		 * @param[in]	success		If true success is reported, otherwise failure.
+		 * @param[in]	file		Name of the source code file the assertment originates from.
+		 * @param[in]	line		Line number at which the assertment was triggered at.
+		 */
+		void assertment(bool success, const String& desc, const String& file, long line);
+
+		Vector<TestEntry> mTests;
+		Vector<TestSuitePtr> mSuites;
+
+		// Transient
+		TestOutput* mOutput;
+		String mActiveTestName;
+	};
+}
+
+/** Registers a new unit test within an implementation of TestSuite. */
+#define BS_ADD_TEST(func) addTest(static_cast<Func>(&func), #func);
+
 /** @} */

+ 244 - 245
Source/BansheeUtility/Include/BsThreadPool.h

@@ -1,246 +1,245 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsModule.h"
-
-namespace BansheeEngine
-{
-	/** @addtogroup Threading
-	 *  @{
-	 */
-
-	class ThreadPool;
-
-	/** Handle to a thread managed by ThreadPool. */
-	class BS_UTILITY_EXPORT HThread
-	{
-	public:
-		HThread();
-		HThread(ThreadPool* pool, UINT32 threadId);
-
-		/**	Block the calling thread until the thread this handle points to completes. */
-		void blockUntilComplete();
-
-	private:
-		UINT32 mThreadId;
-		ThreadPool* mPool;
-	};
-
-	/** @cond INTERNAL */
-
-	/**	Wrapper around a thread that is used within ThreadPool. */
-	class BS_UTILITY_EXPORT PooledThread
-	{
-	public:
-		PooledThread(const String& name);
-		virtual ~PooledThread();
-
-		/**	Initializes the pooled thread. Must be called right after the object is constructed. */
-		void initialize();
-
-		/**
-		 * Starts executing the given worker method.
-		 *
-		 * @note	
-		 * Caller must ensure worker method is not null and that the thread is currently idle, otherwise undefined behavior
-		 * will occur.
-		 */
-		void start(std::function<void()> workerMethod, UINT32 id);
-
-		/**
-		 * Attempts to join the currently running thread and destroys it. Caller must ensure that any worker method 
-		 * currently running properly returns, otherwise this will block indefinitely.
-		 */
-		void destroy();
-
-		/**	Returns true if the thread is idle and new worker method can be scheduled on it. */
-		bool isIdle();
-
-		/** Returns how long has the thread been idle. Value is undefined if thread is not idle. */
-		time_t idleTime();
-
-		/**	Sets a name of the thread. */
-		void setName(const String& name);
-
-		/**	Gets unique ID of the currently executing thread. */
-		UINT32 getId() const;
-
-		/**	Blocks the current thread until this thread completes. Returns immediately if the thread is idle. */
-		void blockUntilComplete();
-
-		/**	Called when the thread is first created. */
-		virtual void onThreadStarted(const String& name) = 0;
-
-		/**	Called when the thread is being shut down. */
-		virtual void onThreadEnded(const String& name) = 0;
-
-	protected:
-		friend class HThread;
-
-		/** Primary worker method that is ran when the thread is first initialized. */
-		void run();
-
-	protected:
-		std::function<void()> mWorkerMethod;
-
-		String mName;
-		UINT32 mId;
-		bool mIdle;
-		bool mThreadStarted;
-		bool mThreadReady;
-
-		time_t mIdleTime;
-
-		BS_THREAD_TYPE* mThread;
-		BS_MUTEX(mMutex);
-		BS_THREAD_SYNCHRONISER(mStartedCond);
-		BS_THREAD_SYNCHRONISER(mReadyCond);
-		BS_THREAD_SYNCHRONISER(mWorkerEndedCond);
-	};
-
-	/**
-	 * @copydoc	PooledThread
-	 * 			
-	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created 
-	 *						 or when a thread is destroyed.
-	 */
-	template<class ThreadPolicy>
-	class TPooledThread : public PooledThread
-	{
-	public:
-		TPooledThread(const String& name)
-			:PooledThread(name)
-		{ }
-
-		/** @copydoc PooledThread::onThreadStarted */
-		void onThreadStarted(const String& name) override
-		{
-			ThreadPolicy::onThreadStarted(name);
-		}
-
-		/** @copydoc PooledThread::onThreadEnded */
-		void onThreadEnded(const String& name) override
-		{
-			ThreadPolicy::onThreadEnded(name);
-		}
-	};
-
-	/** @endcond */
-
-	/**
-	 * Class that maintains a pool of threads we can easily retrieve and use for any task. This saves on the cost of 
-	 * creating and destroying threads.
-	 */
-	class BS_UTILITY_EXPORT ThreadPool : public Module<ThreadPool>
-	{
-	public:
-		/**
-		 * @brief	Constructs a new thread pool
-		 *
-		 * @param[in]	threadCapacity	Default thread capacity, the pool will always try to keep this many threads available.
-		 * @param[in]	maxCapacity   	(optional) Maximum number of threads the pool can create. If we go over this limit an 
-		 *								exception will be thrown.
-		 * @param[in]	idleTimeout   	(optional) How many seconds do threads need to be idle before we remove them from the pool.
-		 */
-		ThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60);
-		virtual ~ThreadPool();
-
-		/**
-		 * Find an unused thread (or creates a new one) and runs the specified worker method on it.
-		 *
-		 * @param[in]	name			A name you may use for more easily identifying the thread.
-		 * @param[in]	workerMethod	The worker method to be called by the thread.
-		 *
-		 * @return	A thread handle you may use for monitoring the thread execution.
-		 */
-		HThread run(const String& name, std::function<void()> workerMethod);
-
-		/**
-		 * Stops all threads and destroys them. Caller must ensure each threads worker method returns otherwise this will 
-		 * never return.
-		 */
-		void stopAll();
-
-		/** Clear any unused threads that are over the capacity. */
-		void clearUnused();
-
-		/**	Returns the number of unused threads in the pool. */
-		UINT32 getNumAvailable() const;
-
-		/**	Returns the number of running threads in the pool. */
-		UINT32 getNumActive() const;
-
-		/**	Returns the total number of created threads in the pool	(both running and unused). */
-		UINT32 getNumAllocated() const;
-
-	protected:
-		friend class HThread;
-
-		Vector<PooledThread*> mThreads;
-		
-		/**	Creates a new thread to be used by the pool. */
-		virtual PooledThread* createThread(const String& name) = 0;
-
-		/**	Destroys the specified thread. Caller needs to make sure the thread is actually shut down beforehand. */
-		void destroyThread(PooledThread* thread);
-
-		/**
-		 * Returns the first unused thread if one exists, otherwise creates a new one.
-		 *
-		 * @param[in]	name	Name to assign the thread.
-		 *
-		 * @note	Throws an exception if we have reached our maximum thread capacity.
-		 */
-		PooledThread* getThread(const String& name);
-
-		UINT32 mDefaultCapacity;
-		UINT32 mMaxCapacity;
-		UINT32 mIdleTimeout;
-		UINT32 mAge;
-		
-		std::atomic_uint mUniqueId;
-		BS_MUTEX(mMutex);
-	};
-
-	/** @cond INTERNAL */
-
-	/** Policy used for thread start & end used by the ThreadPool. */
-	class ThreadNoPolicy
-	{
-	public:
-		static void onThreadStarted(const String& name) { }
-		static void onThreadEnded(const String& name) { }
-	};
-
-	/**
-	 * @copydoc ThreadPool
-	 * 			
-	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created 
-	 *			or when a thread is destroyed.
-	 */
-	template<class ThreadPolicy = ThreadNoPolicy>
-	class TThreadPool : public ThreadPool
-	{
-	public:
-		TThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60)
-			:ThreadPool(threadCapacity, maxCapacity, idleTimeout)
-		{
-
-		}
-
-	protected:
-		/** @copydoc ThreadPool::createThread */
-		PooledThread* createThread(const String& name) override
-		{
-			PooledThread* newThread = bs_new<TPooledThread<ThreadPolicy>>(name);
-			newThread->initialize();
-
-			return newThread;
-		}
-	};
-
-	/** @endcond */
-	/** @} */
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Threading
+	 *  @{
+	 */
+
+	class ThreadPool;
+
+	/** Handle to a thread managed by ThreadPool. */
+	class BS_UTILITY_EXPORT HThread
+	{
+	public:
+		HThread();
+		HThread(ThreadPool* pool, UINT32 threadId);
+
+		/**	Block the calling thread until the thread this handle points to completes. */
+		void blockUntilComplete();
+
+	private:
+		UINT32 mThreadId;
+		ThreadPool* mPool;
+	};
+
+	/** @cond INTERNAL */
+
+	/**	Wrapper around a thread that is used within ThreadPool. */
+	class BS_UTILITY_EXPORT PooledThread
+	{
+	public:
+		PooledThread(const String& name);
+		virtual ~PooledThread();
+
+		/**	Initializes the pooled thread. Must be called right after the object is constructed. */
+		void initialize();
+
+		/**
+		 * Starts executing the given worker method.
+		 *
+		 * @note	
+		 * Caller must ensure worker method is not null and that the thread is currently idle, otherwise undefined behavior
+		 * will occur.
+		 */
+		void start(std::function<void()> workerMethod, UINT32 id);
+
+		/**
+		 * Attempts to join the currently running thread and destroys it. Caller must ensure that any worker method 
+		 * currently running properly returns, otherwise this will block indefinitely.
+		 */
+		void destroy();
+
+		/**	Returns true if the thread is idle and new worker method can be scheduled on it. */
+		bool isIdle();
+
+		/** Returns how long has the thread been idle. Value is undefined if thread is not idle. */
+		time_t idleTime();
+
+		/**	Sets a name of the thread. */
+		void setName(const String& name);
+
+		/**	Gets unique ID of the currently executing thread. */
+		UINT32 getId() const;
+
+		/**	Blocks the current thread until this thread completes. Returns immediately if the thread is idle. */
+		void blockUntilComplete();
+
+		/**	Called when the thread is first created. */
+		virtual void onThreadStarted(const String& name) = 0;
+
+		/**	Called when the thread is being shut down. */
+		virtual void onThreadEnded(const String& name) = 0;
+
+	protected:
+		friend class HThread;
+
+		/** Primary worker method that is ran when the thread is first initialized. */
+		void run();
+
+	protected:
+		std::function<void()> mWorkerMethod;
+
+		String mName;
+		UINT32 mId;
+		bool mIdle;
+		bool mThreadStarted;
+		bool mThreadReady;
+
+		time_t mIdleTime;
+
+		BS_THREAD_TYPE* mThread;
+		BS_MUTEX(mMutex);
+		BS_THREAD_SYNCHRONISER(mStartedCond);
+		BS_THREAD_SYNCHRONISER(mReadyCond);
+		BS_THREAD_SYNCHRONISER(mWorkerEndedCond);
+	};
+
+	/**
+	 * @copydoc	PooledThread
+	 * 			
+	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created 
+	 *						 or when a thread is destroyed.
+	 */
+	template<class ThreadPolicy>
+	class TPooledThread : public PooledThread
+	{
+	public:
+		TPooledThread(const String& name)
+			:PooledThread(name)
+		{ }
+
+		/** @copydoc PooledThread::onThreadStarted */
+		void onThreadStarted(const String& name) override
+		{
+			ThreadPolicy::onThreadStarted(name);
+		}
+
+		/** @copydoc PooledThread::onThreadEnded */
+		void onThreadEnded(const String& name) override
+		{
+			ThreadPolicy::onThreadEnded(name);
+		}
+	};
+
+	/** @endcond */
+
+	/**
+	 * Class that maintains a pool of threads we can easily retrieve and use for any task. This saves on the cost of 
+	 * creating and destroying threads.
+	 */
+	class BS_UTILITY_EXPORT ThreadPool : public Module<ThreadPool>
+	{
+	public:
+		/**
+		 * Constructs a new thread pool
+		 *
+		 * @param[in]	threadCapacity	Default thread capacity, the pool will always try to keep this many threads available.
+		 * @param[in]	maxCapacity   	(optional) Maximum number of threads the pool can create. If we go over this limit an 
+		 *								exception will be thrown.
+		 * @param[in]	idleTimeout   	(optional) How many seconds do threads need to be idle before we remove them from the pool.
+		 */
+		ThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60);
+		virtual ~ThreadPool();
+
+		/**
+		 * Find an unused thread (or creates a new one) and runs the specified worker method on it.
+		 *
+		 * @param[in]	name			A name you may use for more easily identifying the thread.
+		 * @param[in]	workerMethod	The worker method to be called by the thread.
+		 * @return						A thread handle you may use for monitoring the thread execution.
+		 */
+		HThread run(const String& name, std::function<void()> workerMethod);
+
+		/**
+		 * Stops all threads and destroys them. Caller must ensure each threads worker method returns otherwise this will 
+		 * never return.
+		 */
+		void stopAll();
+
+		/** Clear any unused threads that are over the capacity. */
+		void clearUnused();
+
+		/**	Returns the number of unused threads in the pool. */
+		UINT32 getNumAvailable() const;
+
+		/**	Returns the number of running threads in the pool. */
+		UINT32 getNumActive() const;
+
+		/**	Returns the total number of created threads in the pool	(both running and unused). */
+		UINT32 getNumAllocated() const;
+
+	protected:
+		friend class HThread;
+
+		Vector<PooledThread*> mThreads;
+		
+		/**	Creates a new thread to be used by the pool. */
+		virtual PooledThread* createThread(const String& name) = 0;
+
+		/**	Destroys the specified thread. Caller needs to make sure the thread is actually shut down beforehand. */
+		void destroyThread(PooledThread* thread);
+
+		/**
+		 * Returns the first unused thread if one exists, otherwise creates a new one.
+		 *
+		 * @param[in]	name	Name to assign the thread.
+		 *
+		 * @note	Throws an exception if we have reached our maximum thread capacity.
+		 */
+		PooledThread* getThread(const String& name);
+
+		UINT32 mDefaultCapacity;
+		UINT32 mMaxCapacity;
+		UINT32 mIdleTimeout;
+		UINT32 mAge;
+		
+		std::atomic_uint mUniqueId;
+		BS_MUTEX(mMutex);
+	};
+
+	/** @cond INTERNAL */
+
+	/** Policy used for thread start & end used by the ThreadPool. */
+	class ThreadNoPolicy
+	{
+	public:
+		static void onThreadStarted(const String& name) { }
+		static void onThreadEnded(const String& name) { }
+	};
+
+	/**
+	 * @copydoc ThreadPool
+	 * 			
+	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created 
+	 *			or when a thread is destroyed.
+	 */
+	template<class ThreadPolicy = ThreadNoPolicy>
+	class TThreadPool : public ThreadPool
+	{
+	public:
+		TThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60)
+			:ThreadPool(threadCapacity, maxCapacity, idleTimeout)
+		{
+
+		}
+
+	protected:
+		/** @copydoc ThreadPool::createThread */
+		PooledThread* createThread(const String& name) override
+		{
+			PooledThread* newThread = bs_new<TPooledThread<ThreadPolicy>>(name);
+			newThread->initialize();
+
+			return newThread;
+		}
+	};
+
+	/** @endcond */
+	/** @} */
 }

+ 23 - 25
Source/BansheeUtility/Include/BsTypes.h

@@ -1,26 +1,24 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsPlatformDefines.h"
-
-/**
- * @brief	Commonly used types.
- */
-namespace BansheeEngine
-{
-	typedef char INT8;
-	typedef unsigned char UINT8;
-	typedef short INT16;
-	typedef unsigned short UINT16;
-	typedef int INT32;
-	typedef unsigned int UINT32;
-
-#if BS_COMPILER == BS_COMPILER_MSVC
-	typedef unsigned __int64 UINT64;
-	typedef __int64 INT64;
-#else
-	typedef unsigned long long UINT64;
-	typedef long long INT64;
-#endif
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPlatformDefines.h"
+
+/**	Commonly used types. */
+namespace BansheeEngine
+{
+	typedef char INT8;
+	typedef unsigned char UINT8;
+	typedef short INT16;
+	typedef unsigned short UINT16;
+	typedef int INT32;
+	typedef unsigned int UINT32;
+
+#if BS_COMPILER == BS_COMPILER_MSVC
+	typedef unsigned __int64 UINT64;
+	typedef __int64 INT64;
+#else
+	typedef unsigned long long UINT64;
+	typedef long long INT64;
+#endif
 }

+ 1284 - 1286
Source/BansheeUtility/Source/BsBinarySerializer.cpp

@@ -1,1287 +1,1285 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsBinarySerializer.h"
-
-#include "BsException.h"
-#include "BsDebug.h"
-#include "BsIReflectable.h"
-#include "BsRTTIType.h"
-#include "BsRTTIField.h"
-#include "BsRTTIPlainField.h"
-#include "BsRTTIReflectableField.h"
-#include "BsRTTIReflectablePtrField.h"
-#include "BsRTTIManagedDataBlockField.h"
-#include "BsMemorySerializer.h"
-
-#include <unordered_set>
-
-/**
- * @brief	A macro that represents a block of code that gets used a lot inside
- * 			encodeInternal. It checks if the buffer has enough space, and if it does
- * 			it copies the data from the specified location and increments the needed
- * 			pointers and counters. If there is not enough space the buffer is flushed
- * 			(hopefully to make some space). If there is still not enough space the entire
- * 			encoding process ends.
- *
- * @param	dataPtr	Pointer to data which to copy.
- * @param	size   	Size of the data to copy
- */
-#define COPY_TO_BUFFER(dataIter, size)									\
-if((*bytesWritten + size##) > bufferLength)								\
-{																		\
-	mTotalBytesWritten += *bytesWritten;								\
-	buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);	\
-	if(buffer == nullptr || bufferLength < size##) return nullptr;		\
-	*bytesWritten = 0;													\
-}																		\
-																		\
-memcpy(buffer, dataIter##, size##);										\
-buffer += size##;														\
-*bytesWritten += size##;
-
-namespace BansheeEngine
-{
-	BinarySerializer::BinarySerializer()
-		:mLastUsedObjectId(1)
-	{
-	}
-
-	void BinarySerializer::encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, 
-		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
-	{
-		mObjectsToEncode.clear();
-		mObjectAddrToId.clear();
-		mLastUsedObjectId = 1;
-		*bytesWritten = 0;
-		mTotalBytesWritten = 0;
-		UINT8* bufferStart = buffer;
-		Vector<std::shared_ptr<IReflectable>> encodedObjects;
-
-		UINT32 objectId = findOrCreatePersistentId(object);
-		
-		// Encode primary object and its value types
-		buffer = encodeInternal(object, objectId, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
-		if(buffer == nullptr)
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Destination buffer is null or not large enough.");
-		}
-
-		// Encode pointed to objects and their value types
-		UnorderedSet<UINT32> serializedObjects;
-		while(true)
-		{
-			auto iter = mObjectsToEncode.begin();
-			bool foundObjectToProcess = false;
-			for(iter; iter != mObjectsToEncode.end(); ++iter)
-			{
-				auto foundExisting = serializedObjects.find(iter->objectId);
-				if(foundExisting != serializedObjects.end())
-					continue; // Already processed
-
-				std::shared_ptr<IReflectable> curObject = iter->object;
-				UINT32 curObjectid = iter->objectId;
-				serializedObjects.insert(curObjectid);
-				mObjectsToEncode.erase(iter);
-
-				buffer = encodeInternal(curObject.get(), curObjectid, buffer, 
-					bufferLength, bytesWritten, flushBufferCallback, shallow);
-				if(buffer == nullptr)
-				{
-					BS_EXCEPT(InternalErrorException, 
-						"Destination buffer is null or not large enough.");
-				}
-
-				foundObjectToProcess = true;
-
-				// Ensure we keep a reference to the object so it isn't released.
-				// The system assigns unique IDs to IReflectable objects based on pointer 
-				// addresses but if objects get released then same address could be assigned twice.
-				// Note: To get around this I could assign unique IDs to IReflectable objects
-				encodedObjects.push_back(curObject);
-
-				break; // Need to start over as mObjectsToSerialize was possibly modified
-			}
-
-			if(!foundObjectToProcess) // We're done
-				break;
-		}
-
-		// Final flush
-		if(*bytesWritten > 0)
-		{
-			mTotalBytesWritten += *bytesWritten;
-			buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
-		}
-
-		*bytesWritten = mTotalBytesWritten;
-
-		encodedObjects.clear();
-		mObjectsToEncode.clear();
-		mObjectAddrToId.clear();
-	}
-
-	std::shared_ptr<IReflectable> BinarySerializer::decode(UINT8* data, UINT32 dataLength)
-	{
-		if (dataLength == 0)
-			return nullptr;
-
-		SPtr<SerializedObject> intermediateObject = _decodeIntermediate(data, dataLength);
-		if (intermediateObject == nullptr)
-			return nullptr;
-
-		return _decodeIntermediate(intermediateObject);
-	}
-
-	SPtr<IReflectable> BinarySerializer::_decodeIntermediate(const SPtr<SerializedObject>& serializedObject)
-	{
-		mObjectMap.clear();
-
-		SPtr<IReflectable> output;
-		RTTITypeBase* type = IReflectable::_getRTTIfromTypeId(serializedObject->getRootTypeId());
-		if (type != nullptr)
-		{
-			output = type->newRTTIObject();
-			auto iterNewObj = mObjectMap.insert(std::make_pair(serializedObject, ObjectToDecode(output, serializedObject)));
-
-			iterNewObj.first->second.decodeInProgress = true;
-			decodeInternal(output, serializedObject);
-			iterNewObj.first->second.decodeInProgress = false;
-			iterNewObj.first->second.isDecoded = true;
-		}
-
-		// Go through the remaining objects (should be only ones with weak refs)
-		for (auto iter = mObjectMap.begin(); iter != mObjectMap.end(); ++iter)
-		{
-			ObjectToDecode& objToDecode = iter->second;
-
-			if (objToDecode.isDecoded)
-				continue;
-
-			objToDecode.decodeInProgress = true;
-			decodeInternal(objToDecode.object, objToDecode.serializedObject);
-			objToDecode.decodeInProgress = false;
-			objToDecode.isDecoded = true;
-		}
-
-		mObjectMap.clear();
-		return output;
-	}
-
-	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, 
-		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
-	{
-		RTTITypeBase* si = object->getRTTI();
-		bool isBaseClass = false;
-
-		// If an object has base classes, we need to iterate through all of them
-		do
-		{
-			si->onSerializationStarted(object);
-
-			// Encode object ID & type
-			ObjectMetaData objectMetaData = encodeObjectMetaData(objectId, si->getRTTIId(), isBaseClass);
-			COPY_TO_BUFFER(&objectMetaData, sizeof(ObjectMetaData))
-
-			int numFields = si->getNumFields();
-			for(int i = 0; i < numFields; i++)
-			{
-				RTTIField* curGenericField = si->getField(i);
-
-				// Copy field ID & other meta-data like field size and type
-				int metaData = encodeFieldMetaData(curGenericField->mUniqueId, curGenericField->getTypeSize(), 
-					curGenericField->mIsVectorType, curGenericField->mType, curGenericField->hasDynamicSize(), false);
-				COPY_TO_BUFFER(&metaData, META_SIZE)
-
-				if(curGenericField->mIsVectorType)
-				{
-					UINT32 arrayNumElems = curGenericField->getArraySize(object);
-
-					// Copy num vector elements
-					COPY_TO_BUFFER(&arrayNumElems, NUM_ELEM_FIELD_SIZE)
-
-					switch(curGenericField->mType)
-					{
-					case SerializableFT_ReflectablePtr:
-						{
-							RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-
-							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
-							{
-								std::shared_ptr<IReflectable> childObject;
-								
-								if (!shallow)
-									childObject = curField->getArrayValue(object, arrIdx);
-
-								UINT32 objId = registerObjectPtr(childObject);
-								COPY_TO_BUFFER(&objId, sizeof(UINT32))
-							}
-
-							break;
-						}
-					case SerializableFT_Reflectable:
-						{
-							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
-
-							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
-							{
-								IReflectable& childObject = curField->getArrayValue(object, arrIdx);
-
-								buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, 
-									bytesWritten, flushBufferCallback, shallow);
-								if(buffer == nullptr)
-								{
-									si->onSerializationEnded(object);
-									return nullptr;
-								}
-							}
-
-							break;
-						}
-					case SerializableFT_Plain:
-						{
-							RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
-							{
-								UINT32 typeSize = 0;
-								if(curField->hasDynamicSize())
-									typeSize = curField->getArrayElemDynamicSize(object, arrIdx);
-								else
-									typeSize = curField->getTypeSize();
-
-								if ((*bytesWritten + typeSize) > bufferLength)
-								{
-									UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize);
-									curField->arrayElemToBuffer(object, arrIdx, tempBuffer);
-
-									buffer = dataBlockToBuffer(tempBuffer, typeSize, buffer, bufferLength, bytesWritten, flushBufferCallback);
-									if (buffer == nullptr || bufferLength == 0)
-									{
-										bs_stack_free(tempBuffer);
-										si->onSerializationEnded(object);
-										return nullptr;
-									}
-
-									bs_stack_free(tempBuffer);
-								}
-								else
-								{
-									curField->arrayElemToBuffer(object, arrIdx, buffer);
-									buffer += typeSize;
-									*bytesWritten += typeSize;
-								}
-							}
-
-							break;
-						}
-					default:
-						BS_EXCEPT(InternalErrorException, 
-							"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
-							", Is array: " + toString(curGenericField->mIsVectorType));
-					}
-				}
-				else
-				{
-					switch(curGenericField->mType)
-					{
-					case SerializableFT_ReflectablePtr:
-						{
-							RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-							std::shared_ptr<IReflectable> childObject;
-							
-							if (!shallow)
-								childObject = curField->getValue(object);
-
-							UINT32 objId = registerObjectPtr(childObject);
-							COPY_TO_BUFFER(&objId, sizeof(UINT32))
-
-							break;
-						}
-					case SerializableFT_Reflectable:
-						{
-							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
-							IReflectable& childObject = curField->getValue(object);
-
-							buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, 
-								bytesWritten, flushBufferCallback, shallow);
-							if(buffer == nullptr)
-							{
-								si->onSerializationEnded(object);
-								return nullptr;
-							}
-
-							break;
-						}
-					case SerializableFT_Plain:
-						{
-							RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-							UINT32 typeSize = 0;
-							if(curField->hasDynamicSize())
-								typeSize = curField->getDynamicSize(object);
-							else
-								typeSize = curField->getTypeSize();
-
-							if ((*bytesWritten + typeSize) > bufferLength)
-							{
-								UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize);
-								curField->toBuffer(object, tempBuffer);
-								
-								buffer = dataBlockToBuffer(tempBuffer, typeSize, buffer, bufferLength, bytesWritten, flushBufferCallback);
-								if (buffer == nullptr || bufferLength == 0)
-								{
-									bs_stack_free(tempBuffer);
-									si->onSerializationEnded(object);
-									return nullptr;
-								}
-
-								bs_stack_free(tempBuffer);
-							}
-							else
-							{
-								curField->toBuffer(object, buffer);
-								buffer += typeSize;
-								*bytesWritten += typeSize;
-							}
-
-							break;
-						}
-					case SerializableFT_DataBlock:
-						{
-							RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
-							ManagedDataBlock value = curField->getValue(object);
-
-							// Data block size
-							UINT32 dataBlockSize = value.getSize();
-							COPY_TO_BUFFER(&dataBlockSize, sizeof(UINT32))
-
-							// Data block data
-							UINT8* dataToStore = value.getData();
-
-							buffer = dataBlockToBuffer(dataToStore, dataBlockSize, buffer, bufferLength, bytesWritten, flushBufferCallback);
-							if (buffer == nullptr || bufferLength == 0)
-							{
-								si->onSerializationEnded(object);
-								return nullptr;
-							}
-
-							break;
-						}
-					default:
-						BS_EXCEPT(InternalErrorException, 
-							"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
-							", Is array: " + toString(curGenericField->mIsVectorType));
-					}
-				}
-			}
-
-			si->onSerializationEnded(object);
-
-			si = si->getBaseClass();
-			isBaseClass = true;
-
-		} while(si != nullptr); // Repeat until we reach the top of the inheritance hierarchy
-
-		return buffer;
-	}
-
-	SPtr<SerializedObject> BinarySerializer::_encodeIntermediate(IReflectable* object, bool shallow)
-	{
-		// TODO: This is a hacky way of generating an intermediate format to save development time and complexity.
-		// It is hacky because it requires a full on encode to binary and then decode into intermediate. It should 
-		// be better to modify encoding process so it outputs the intermediate format directly (similar to how decoding works). 
-		// This also means that once you have an intermediate format you cannot use it to encode to binary. 
-
-		std::function<void*(UINT32)> allocator = &MemoryAllocator<GenAlloc>::allocate;
-
-		MemorySerializer ms;
-		UINT32 dataLength = 0;
-		UINT8* data = ms.encode(object, dataLength, allocator, shallow);
-
-		BinarySerializer bs;
-		SPtr<SerializedObject> obj = bs._decodeIntermediate(data, dataLength, true);
-
-		bs_free(data);
-		return obj;
-	}
-
-	SPtr<SerializedObject> BinarySerializer::_decodeIntermediate(UINT8* data, UINT32 dataLength, bool copyData)
-	{
-		UINT32 bytesRead = 0;
-		mInterimObjectMap.clear();
-
-		SPtr<SerializedObject> rootObj;
-		bool hasMore = decodeIntermediateInternal(data, dataLength, bytesRead, rootObj, copyData);
-		while (hasMore)
-		{
-			UINT8* dataPtr = data + bytesRead;
-
-			SPtr<SerializedObject> dummyObj;
-			hasMore = decodeIntermediateInternal(dataPtr, dataLength, bytesRead, dummyObj, copyData);
-		}
-
-		return rootObj;
-	}
-
-	bool BinarySerializer::decodeIntermediateInternal(UINT8* data, UINT32 dataLength, UINT32& bytesRead, SPtr<SerializedObject>& output, bool copyData)
-	{
-		if ((bytesRead + sizeof(ObjectMetaData)) > dataLength)
-		{
-			BS_EXCEPT(InternalErrorException,
-				"Error decoding data.");
-		}
-
-		ObjectMetaData objectMetaData;
-		objectMetaData.objectMeta = 0;
-		objectMetaData.typeId = 0;
-		memcpy(&objectMetaData, data, sizeof(ObjectMetaData));
-		data += sizeof(ObjectMetaData);
-		bytesRead += sizeof(ObjectMetaData);
-
-		UINT32 objectId = 0;
-		UINT32 objectTypeId = 0;
-		bool objectIsBaseClass = false;
-		decodeObjectMetaData(objectMetaData, objectId, objectTypeId, objectIsBaseClass);
-
-		if (objectIsBaseClass)
-		{
-			BS_EXCEPT(InternalErrorException, "Encountered a base-class object while looking for a new object. " \
-				"Base class objects are only supposed to be parts of a larger object.");
-		}
-
-		RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(objectTypeId);
-		SerializedSubObject* serializedSubObject = nullptr;
-		
-		if (rtti != nullptr)
-		{
-			if (objectId > 0)
-			{
-				auto iterFind = mInterimObjectMap.find(objectId);
-				if (iterFind == mInterimObjectMap.end())
-				{
-					output = bs_shared_ptr_new<SerializedObject>();
-					mInterimObjectMap.insert(std::make_pair(objectId, output));
-				}
-				else
-					output = iterFind->second;
-			}
-			else // Not a reflectable ptr referenced object
-				output = bs_shared_ptr_new<SerializedObject>();
-
-			output->subObjects.push_back(SerializedSubObject());
-			serializedSubObject = &output->subObjects.back();
-
-			serializedSubObject->typeId = objectTypeId;
-		}
-
-		while (bytesRead < dataLength)
-		{
-			int metaData = -1;
-
-			if ((bytesRead + META_SIZE) > dataLength)
-			{
-				BS_EXCEPT(InternalErrorException,
-					"Error decoding data.");
-			}
-
-			memcpy((void*)&metaData, data, META_SIZE);
-
-			if (isObjectMetaData(metaData)) // We've reached a new object or a base class of the current one
-			{
-				if ((bytesRead + sizeof(ObjectMetaData)) > dataLength)
-				{
-					BS_EXCEPT(InternalErrorException,
-						"Error decoding data.");
-				}
-
-				ObjectMetaData objMetaData;
-				objMetaData.objectMeta = 0;
-				objMetaData.typeId = 0;
-				memcpy(&objMetaData, data, sizeof(ObjectMetaData));
-
-				UINT32 objId = 0;
-				UINT32 objTypeId = 0;
-				bool objIsBaseClass = false;
-				decodeObjectMetaData(objMetaData, objId, objTypeId, objIsBaseClass);
-
-				// If it's a base class, get base class RTTI and handle that
-				if (objIsBaseClass)
-				{
-					if (rtti != nullptr)
-						rtti = rtti->getBaseClass();
-
-					// Saved and current base classes don't match, so just skip over all that data
-					if (rtti == nullptr || rtti->getRTTIId() != objTypeId)
-					{
-						rtti = nullptr;
-					}
-
-					if (rtti != nullptr)
-					{
-						output->subObjects.push_back(SerializedSubObject());
-						serializedSubObject = &output->subObjects.back();
-
-						serializedSubObject->typeId = objTypeId;
-					}
-
-					data += sizeof(ObjectMetaData);
-					bytesRead += sizeof(ObjectMetaData);
-					continue;
-				}
-				else
-				{
-					// Found new object, we're done
-					return true;
-				}
-			}
-
-			data += META_SIZE;
-			bytesRead += META_SIZE;
-
-			bool isArray;
-			SerializableFieldType fieldType;
-			UINT16 fieldId;
-			UINT8 fieldSize;
-			bool hasDynamicSize;
-			bool terminator;
-			decodeFieldMetaData(metaData, fieldId, fieldSize, isArray, fieldType, hasDynamicSize, terminator);
-
-			if (terminator)
-			{
-				// We've processed the last field in this object, so return. Although we return false we don't actually know
-				// if there is an object following this one. However it doesn't matter since terminator fields are only used 
-				// for embedded objects that are all processed within this method so we can compensate.
-				return false;
-			}
-
-			RTTIField* curGenericField = nullptr;
-
-			if (rtti != nullptr)
-				curGenericField = rtti->findField(fieldId);
-
-			if (curGenericField != nullptr)
-			{
-				if (!hasDynamicSize && curGenericField->getTypeSize() != fieldSize)
-				{
-					BS_EXCEPT(InternalErrorException,
-						"Data type mismatch. Type size stored in file and actual type size don't match. ("
-						+ toString(curGenericField->getTypeSize()) + " vs. " + toString(fieldSize) + ")");
-				}
-
-				if (curGenericField->mIsVectorType != isArray)
-				{
-					BS_EXCEPT(InternalErrorException,
-						"Data type mismatch. One is array, other is a single type.");
-				}
-
-				if (curGenericField->mType != fieldType)
-				{
-					BS_EXCEPT(InternalErrorException,
-						"Data type mismatch. Field types don't match. " + toString(UINT32(curGenericField->mType)) + " vs. " + toString(UINT32(fieldType)));
-				}
-			}
-
-			SPtr<SerializedInstance> serializedEntry;
-			bool hasModification = false;
-
-			int arrayNumElems = 1;
-			if (isArray)
-			{
-				if ((bytesRead + NUM_ELEM_FIELD_SIZE) > dataLength)
-				{
-					BS_EXCEPT(InternalErrorException,
-						"Error decoding data.");
-				}
-
-				memcpy((void*)&arrayNumElems, data, NUM_ELEM_FIELD_SIZE);
-				data += NUM_ELEM_FIELD_SIZE;
-				bytesRead += NUM_ELEM_FIELD_SIZE;
-
-				SPtr<SerializedArray> serializedArray;
-				if (curGenericField != nullptr)
-				{
-					serializedArray = bs_shared_ptr_new<SerializedArray>();
-					serializedArray->numElements = arrayNumElems;
-
-					serializedEntry = serializedArray;
-					hasModification = true;
-				}
-
-				switch (fieldType)
-				{
-				case SerializableFT_ReflectablePtr:
-				{
-					RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-
-					for (int i = 0; i < arrayNumElems; i++)
-					{
-						if ((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
-						{
-							BS_EXCEPT(InternalErrorException,
-								"Error decoding data.");
-						}
-
-						int childObjectId = 0;
-						memcpy(&childObjectId, data, COMPLEX_TYPE_FIELD_SIZE);
-						data += COMPLEX_TYPE_FIELD_SIZE;
-						bytesRead += COMPLEX_TYPE_FIELD_SIZE;
-
-						if (curField != nullptr)
-						{
-							SPtr<SerializedObject> serializedArrayEntry = nullptr;
-							
-							if (childObjectId > 0)
-							{
-								auto findObj = mInterimObjectMap.find(childObjectId);
-								if (findObj == mInterimObjectMap.end())
-								{
-									serializedArrayEntry = bs_shared_ptr_new<SerializedObject>();
-									mInterimObjectMap.insert(std::make_pair(childObjectId, serializedArrayEntry));
-								}
-								else
-									serializedArrayEntry = findObj->second;
-							}
-
-							SerializedArrayEntry arrayEntry;
-							arrayEntry.serialized = serializedArrayEntry;
-							arrayEntry.index = i;
-
-							serializedArray->entries[i] = arrayEntry;
-						}
-					}
-
-					break;
-				}
-				case SerializableFT_Reflectable:
-				{
-					RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
-
-					for (int i = 0; i < arrayNumElems; i++)
-					{
-						if (curField != nullptr)
-						{
-							UINT32 bytesReadStart = bytesRead;
-							SPtr<SerializedObject> serializedArrayEntry;
-							decodeIntermediateInternal(data, dataLength, bytesRead, serializedArrayEntry, copyData);
-
-							SerializedArrayEntry arrayEntry;
-							arrayEntry.serialized = serializedArrayEntry;
-							arrayEntry.index = i;
-
-							serializedArray->entries[i] = arrayEntry;
-
-							UINT32 complexTypeSize = bytesRead - bytesReadStart;
-							data += complexTypeSize;
-						}
-					}
-					break;
-				}
-				case SerializableFT_Plain:
-				{
-					RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-					for (int i = 0; i < arrayNumElems; i++)
-					{
-						UINT32 typeSize = fieldSize;
-						if (hasDynamicSize)
-							memcpy(&typeSize, data, sizeof(UINT32));
-
-						if (curField != nullptr)
-						{
-							SPtr<SerializedField> serializedField = bs_shared_ptr_new<SerializedField>();
-
-							if (copyData)
-							{
-								serializedField->value = (UINT8*)bs_alloc(typeSize);
-								memcpy(serializedField->value, data, typeSize);
-								serializedField->ownsMemory = true;
-							}
-							else
-								serializedField->value = data;
-
-							serializedField->size = typeSize;
-
-							SerializedArrayEntry arrayEntry;
-							arrayEntry.serialized = serializedField;
-							arrayEntry.index = i;
-
-							serializedArray->entries[i] = arrayEntry;
-						}
-
-						data += typeSize;
-						bytesRead += typeSize;
-					}
-					break;
-				}
-				default:
-					BS_EXCEPT(InternalErrorException,
-						"Error decoding data. Encountered a type I don't know how to decode. Type: " + toString(UINT32(fieldType)) +
-						", Is array: " + toString(isArray));
-				}
-			}
-			else
-			{
-				switch (fieldType)
-				{
-				case SerializableFT_ReflectablePtr:
-				{
-					RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-
-					if ((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
-					{
-						BS_EXCEPT(InternalErrorException,
-							"Error decoding data.");
-					}
-
-					int childObjectId = 0;
-					memcpy(&childObjectId, data, COMPLEX_TYPE_FIELD_SIZE);
-					data += COMPLEX_TYPE_FIELD_SIZE;
-					bytesRead += COMPLEX_TYPE_FIELD_SIZE;
-
-					if (curField != nullptr)
-					{
-						SPtr<SerializedObject> serializedField = nullptr;
-
-						if (childObjectId > 0)
-						{
-							auto findObj = mInterimObjectMap.find(childObjectId);
-							if (findObj == mInterimObjectMap.end())
-							{
-								serializedField = bs_shared_ptr_new<SerializedObject>();
-								mInterimObjectMap.insert(std::make_pair(childObjectId, serializedField));
-							}
-							else
-								serializedField = findObj->second;
-						}
-
-						serializedEntry = serializedField;
-						hasModification = true;
-					}
-
-					break;
-				}
-				case SerializableFT_Reflectable:
-				{
-					RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
-
-					if (curField != nullptr)
-					{
-						UINT32 bytesReadStart = bytesRead;
-						SPtr<SerializedObject> serializedChildObj;
-						decodeIntermediateInternal(data, dataLength, bytesRead, serializedChildObj, copyData);
-
-						serializedEntry = serializedChildObj;
-						hasModification = true;
-
-						UINT32 complexTypeSize = bytesRead - bytesReadStart;
-						data += complexTypeSize;
-					}
-
-					break;
-				}
-				case SerializableFT_Plain:
-				{
-					RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-					UINT32 typeSize = fieldSize;
-					if (hasDynamicSize)
-						memcpy(&typeSize, data, sizeof(UINT32));
-
-					if (curField != nullptr)
-					{
-						SPtr<SerializedField> serializedField = bs_shared_ptr_new<SerializedField>();
-
-						if (copyData)
-						{
-							serializedField->value = (UINT8*)bs_alloc(typeSize);
-							memcpy(serializedField->value, data, typeSize);
-							serializedField->ownsMemory = true;
-						}
-						else
-							serializedField->value = data;
-
-						serializedField->size = typeSize;
-
-						serializedEntry = serializedField;
-						hasModification = true;
-					}
-
-					data += typeSize;
-					bytesRead += typeSize;
-					break;
-				}
-				case SerializableFT_DataBlock:
-				{
-					RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
-
-					if ((bytesRead + DATA_BLOCK_TYPE_FIELD_SIZE) > dataLength)
-					{
-						BS_EXCEPT(InternalErrorException,
-							"Error decoding data.");
-					}
-
-					// Data block size
-					UINT32 dataBlockSize = 0;
-					memcpy(&dataBlockSize, data, DATA_BLOCK_TYPE_FIELD_SIZE);
-					data += DATA_BLOCK_TYPE_FIELD_SIZE;
-					bytesRead += DATA_BLOCK_TYPE_FIELD_SIZE;
-
-					if ((bytesRead + dataBlockSize) > dataLength)
-					{
-						BS_EXCEPT(InternalErrorException,
-							"Error decoding data.");
-					}
-
-					// Data block data
-					if (curField != nullptr)
-					{
-						SPtr<SerializedField> serializedField = bs_shared_ptr_new<SerializedField>();
-
-						if (copyData)
-						{
-							serializedField->value = (UINT8*)bs_alloc(dataBlockSize);
-							memcpy(serializedField->value, data, dataBlockSize);
-							serializedField->ownsMemory = true;
-						}
-						else
-							serializedField->value = data;
-
-						serializedField->size = dataBlockSize;
-
-						serializedEntry = serializedField;
-						hasModification = true;
-					}
-
-					data += dataBlockSize;
-					bytesRead += dataBlockSize;
-
-					break;
-				}
-				default:
-					BS_EXCEPT(InternalErrorException,
-						"Error decoding data. Encountered a type I don't know how to decode. Type: " + toString(UINT32(fieldType)) +
-						", Is array: " + toString(isArray));
-				}
-			}
-
-			if (hasModification)
-			{
-				SerializedEntry entry;
-				entry.fieldId = curGenericField->mUniqueId;
-				entry.serialized = serializedEntry;
-
-				serializedSubObject->entries.insert(std::make_pair(curGenericField->mUniqueId, entry));
-			}
-		}
-
-		return false;
-	}
-
-	void BinarySerializer::decodeInternal(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serializableObject)
-	{
-		UINT32 numSubObjects = (UINT32)serializableObject->subObjects.size();
-
-		Vector<RTTITypeBase*> rttiTypes;
-		for (UINT32 subObjectIdx = 0; subObjectIdx < numSubObjects; subObjectIdx++)
-		{
-			const SerializedSubObject& subObject = serializableObject->subObjects[subObjectIdx];
-
-			RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
-			if (rtti == nullptr)
-				continue;
-
-			rtti->onDeserializationStarted(object.get());
-			rttiTypes.push_back(rtti);
-
-			UINT32 numFields = rtti->getNumFields();
-			for (UINT32 fieldIdx = 0; fieldIdx < numFields; fieldIdx++)
-			{
-				RTTIField* curGenericField = rtti->getField(fieldIdx);
-
-				auto iterFindFieldData = subObject.entries.find(curGenericField->mUniqueId);
-				if (iterFindFieldData == subObject.entries.end())
-					continue;
-
-				SPtr<SerializedInstance> entryData = iterFindFieldData->second.serialized;
-				if (curGenericField->isArray())
-				{
-					SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
-
-					UINT32 arrayNumElems = (UINT32)arrayData->numElements;
-					curGenericField->setArraySize(object.get(), arrayNumElems);
-
-					switch (curGenericField->mType)
-					{
-					case SerializableFT_ReflectablePtr:
-					{
-						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-
-						for (auto& arrayElem : arrayData->entries)
-						{
-							SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
-							RTTITypeBase* childRtti = nullptr;
-							
-							if (arrayElemData != nullptr)
-								childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
-
-							if (childRtti != nullptr)
-							{
-								auto findObj = mObjectMap.find(arrayElemData);
-								if (findObj == mObjectMap.end())
-								{
-									SPtr<IReflectable> newObject = childRtti->newRTTIObject();
-									findObj = mObjectMap.insert(std::make_pair(arrayElemData, ObjectToDecode(newObject, arrayElemData))).first;
-								}
-
-								ObjectToDecode& objToDecode = findObj->second;
-
-								bool needsDecoding = (curField->getFlags() & RTTI_Flag_WeakRef) == 0 && !objToDecode.isDecoded;
-								if (needsDecoding)
-								{
-									if (objToDecode.decodeInProgress)
-									{
-										LOGWRN("Detected a circular reference when decoding. Referenced object fields " \
-											"will be resolved in an undefined order (i.e. one of the objects will not " \
-											"be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \
-											"get rid of this warning and tell the system which of the objects is allowed " \
-											"to be deserialized after it is assigned to its field.");
-									}
-									else
-									{
-										objToDecode.decodeInProgress = true;
-										decodeInternal(objToDecode.object, objToDecode.serializedObject);
-										objToDecode.decodeInProgress = false;
-										objToDecode.isDecoded = true;
-									}
-								}
-
-								curField->setArrayValue(object.get(), arrayElem.first, objToDecode.object);
-							}
-							else
-							{
-								curField->setArrayValue(object.get(), arrayElem.first, nullptr);
-							}
-						}
-					}
-						break;
-					case SerializableFT_Reflectable:
-					{
-						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
-
-						for (auto& arrayElem : arrayData->entries)
-						{
-							SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
-							RTTITypeBase* childRtti = nullptr;
-
-							if (arrayElemData != nullptr)
-								childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
-
-							if (childRtti != nullptr)
-							{
-								SPtr<IReflectable> newObject = childRtti->newRTTIObject();
-								decodeInternal(newObject, arrayElemData);
-								curField->setArrayValue(object.get(), arrayElem.first, *newObject);
-							}
-						}
-						break;
-					}
-					case SerializableFT_Plain:
-					{
-						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-						for (auto& arrayElem : arrayData->entries)
-						{
-							SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(arrayElem.second.serialized);
-							if (fieldData != nullptr)
-							{
-								curField->arrayElemFromBuffer(object.get(), arrayElem.first, fieldData->value);
-							}
-						}
-					}
-						break;
-					}
-				}
-				else
-				{
-					switch (curGenericField->mType)
-					{
-					case SerializableFT_ReflectablePtr:
-					{
-						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-
-						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
-						RTTITypeBase* childRtti = nullptr;
-
-						if (fieldObjectData != nullptr)
-							childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
-
-						if (childRtti != nullptr)
-						{
-							auto findObj = mObjectMap.find(fieldObjectData);
-							if (findObj == mObjectMap.end())
-							{
-								SPtr<IReflectable> newObject = childRtti->newRTTIObject();
-								findObj = mObjectMap.insert(std::make_pair(fieldObjectData, ObjectToDecode(newObject, fieldObjectData))).first;
-							}
-
-							ObjectToDecode& objToDecode = findObj->second;
-
-							bool needsDecoding = (curField->getFlags() & RTTI_Flag_WeakRef) == 0 && !objToDecode.isDecoded;
-							if (needsDecoding)
-							{
-								if (objToDecode.decodeInProgress)
-								{
-									LOGWRN("Detected a circular reference when decoding. Referenced object's fields " \
-										"will be resolved in an undefined order (i.e. one of the objects will not " \
-										"be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \
-										"get rid of this warning and tell the system which of the objects is allowed " \
-										"to be deserialized after it is assigned to its field.");
-								}
-								else
-								{
-									objToDecode.decodeInProgress = true;
-									decodeInternal(objToDecode.object, objToDecode.serializedObject);
-									objToDecode.decodeInProgress = false;
-									objToDecode.isDecoded = true;
-								}
-							}
-
-							curField->setValue(object.get(), objToDecode.object);
-						}
-						else
-						{
-							curField->setValue(object.get(), nullptr);
-						}
-					}
-						break;
-					case SerializableFT_Reflectable:
-					{
-						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
-
-						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
-						RTTITypeBase* childRtti = nullptr;
-
-						if (fieldObjectData != nullptr)
-							childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
-
-						if (childRtti != nullptr)
-						{
-							SPtr<IReflectable> newObject = childRtti->newRTTIObject();
-							decodeInternal(newObject, fieldObjectData);
-							curField->setValue(object.get(), *newObject);
-						}
-						break;
-					}
-					case SerializableFT_Plain:
-					{
-						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-						SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(entryData);
-						if (fieldData != nullptr)
-						{
-							curField->fromBuffer(object.get(), fieldData->value);
-						}
-					}
-						break;
-					case SerializableFT_DataBlock:
-					{
-						RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
-
-						SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(entryData);
-						if (fieldData != nullptr)
-						{
-							UINT8* dataCopy = curField->allocate(object.get(), fieldData->size); // TODO - Low priority. I need to read files better, so I
-							memcpy(dataCopy, fieldData->value, fieldData->size);		//    can just pass the buffer pointer directly without copying (possibly large amounts of data)
-
-							ManagedDataBlock value(dataCopy, fieldData->size); // Not managed because I assume the owner class will decide whether to delete the data or keep it
-							curField->setValue(object.get(), value);
-						}
-
-						break;
-					}
-					}
-				}
-			}
-		}
-
-		for (auto iterFind = rttiTypes.rbegin(); iterFind != rttiTypes.rend(); ++iterFind)
-		{
-			(*iterFind)->onDeserializationEnded(object.get());
-		}
-	}
-
-	UINT32 BinarySerializer::encodeFieldMetaData(UINT16 id, UINT8 size, bool array, 
-		SerializableFieldType type, bool hasDynamicSize, bool terminator)
-	{
-		// If O == 0 - Meta contains field information (Encoded using this method)
-		//// Encoding: IIII IIII IIII IIII SSSS SSSS xTYP DCAO
-		//// I - Id
-		//// S - Size
-		//// C - Complex
-		//// A - Array
-		//// D - Data block
-		//// P - Complex ptr
-		//// O - Object descriptor
-		//// Y - Plain field has dynamic size
-		//// T - Terminator (last field in an object)
-
-		return (id << 16 | size << 8 | 
-			(array ? 0x02 : 0) | 
-			((type == SerializableFT_DataBlock) ? 0x04 : 0) | 
-			((type == SerializableFT_Reflectable) ? 0x08 : 0) | 
-			((type == SerializableFT_ReflectablePtr) ? 0x10 : 0) | 
-			(hasDynamicSize ? 0x20 : 0) |
-			(terminator ? 0x40 : 0)); // TODO - Low priority. Technically I could encode this much more tightly, and use var-ints for ID
-	}
-
-	void BinarySerializer::decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, 
-		bool& array, SerializableFieldType& type, bool& hasDynamicSize, bool& terminator)
-	{
-		if(isObjectMetaData(encodedData))
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Meta data represents an object description but is trying to be decoded as a field descriptor.");
-		}
-
-		terminator = (encodedData & 0x40) != 0;
-		hasDynamicSize = (encodedData & 0x20) != 0;
-
-		if((encodedData & 0x10) != 0)
-			type = SerializableFT_ReflectablePtr;
-		else if((encodedData & 0x08) != 0)
-			type = SerializableFT_Reflectable;
-		else if((encodedData & 0x04) != 0)
-			type = SerializableFT_DataBlock;
-		else
-			type = SerializableFT_Plain;
-
-		array = (encodedData & 0x02) != 0;
-		size = (UINT8)((encodedData >> 8) & 0xFF);
-		id = (UINT16)((encodedData >> 16) & 0xFFFF);
-	}
-
-	BinarySerializer::ObjectMetaData BinarySerializer::encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass)
-	{
-		// If O == 1 - Meta contains object instance information (Encoded using encodeObjectMetaData)
-		//// Encoding: SSSS SSSS SSSS SSSS xxxx xxxx xxxx xxBO
-		//// S - Size of the object identifier
-		//// O - Object descriptor
-		//// B - Base class indicator
-		
-		if(objId > 1073741823)
-		{
-			BS_EXCEPT(InvalidParametersException, "Object ID is larger than we can store (max 30 bits): " + toString(objId));
-		}
-
-		ObjectMetaData metaData;
-		metaData.objectMeta = (objId << 2) | (isBaseClass ? 0x02 : 0) | 0x01;
-		metaData.typeId = objTypeId;
-		return metaData;
-	}
-
-	void BinarySerializer::decodeObjectMetaData(BinarySerializer::ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass)
-	{
-		if(!isObjectMetaData(encodedData.objectMeta))
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Meta data represents a field description but is trying to be decoded as an object descriptor.");
-		}
-
-		objId = (encodedData.objectMeta >> 2) & 0x3FFFFFFF;
-		isBaseClass = (encodedData.objectMeta & 0x02) != 0;
-		objTypeId = encodedData.typeId;
-	}
-
-	bool BinarySerializer::isObjectMetaData(UINT32 encodedData)
-	{
-		return ((encodedData & 0x01) != 0);
-	}
-
-	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, 
-		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
-	{
-		if (object != nullptr)
-		{
-			buffer = encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
-
-			// Encode terminator field
-			// Complex types require terminator fields because they can be embedded within other complex types and we need
-			// to know when their fields end and parent's resume
-			int metaData = encodeFieldMetaData(0, 0, false, SerializableFT_Plain, false, true);
-			COPY_TO_BUFFER(&metaData, META_SIZE)
-		}
-
-		return buffer;
-	}
-
-	UINT8* BinarySerializer::dataBlockToBuffer(UINT8* data, UINT32 size, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
-		std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback)
-	{
-		UINT32 remainingSize = size;
-		while (remainingSize > 0)
-		{
-			UINT32 remainingSpaceInBuffer = bufferLength - *bytesWritten;
-
-			if (remainingSize <= remainingSpaceInBuffer)
-			{
-				COPY_TO_BUFFER(data, remainingSize);
-				remainingSize = 0;
-			}
-			else
-			{
-				memcpy(buffer, data, remainingSpaceInBuffer);
-				buffer += remainingSpaceInBuffer;
-				*bytesWritten += remainingSpaceInBuffer;
-				data += remainingSpaceInBuffer;
-				remainingSize -= remainingSpaceInBuffer;
-
-				mTotalBytesWritten += *bytesWritten;
-				buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
-				if (buffer == nullptr || bufferLength == 0)
-					return nullptr;
-
-				*bytesWritten = 0;
-			}
-		}
-
-		return buffer;
-	}
-
-	UINT32 BinarySerializer::findOrCreatePersistentId(IReflectable* object)
-	{
-		void* ptrAddress = (void*)object;
-
-		auto findIter = mObjectAddrToId.find(ptrAddress);
-		if(findIter != mObjectAddrToId.end())
-			return findIter->second;
-
-		UINT32 objId = mLastUsedObjectId++;
-		mObjectAddrToId.insert(std::make_pair(ptrAddress, objId));
-
-		return objId;
-	}
-
-	UINT32 BinarySerializer::registerObjectPtr(std::shared_ptr<IReflectable> object)
-	{
-		if(object == nullptr)
-			return 0;
-
-		void* ptrAddress = (void*)object.get();
-
-		auto iterFind = mObjectAddrToId.find(ptrAddress);
-		if(iterFind == mObjectAddrToId.end())
-		{
-			UINT32 objId = findOrCreatePersistentId(object.get());
-
-			mObjectsToEncode.push_back(ObjectToEncode(objId, object));
-			mObjectAddrToId.insert(std::make_pair(ptrAddress, objId));
-
-			return objId;
-		}
-
-		return iterFind->second;
-	}
-}
-
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsBinarySerializer.h"
+
+#include "BsException.h"
+#include "BsDebug.h"
+#include "BsIReflectable.h"
+#include "BsRTTIType.h"
+#include "BsRTTIField.h"
+#include "BsRTTIPlainField.h"
+#include "BsRTTIReflectableField.h"
+#include "BsRTTIReflectablePtrField.h"
+#include "BsRTTIManagedDataBlockField.h"
+#include "BsMemorySerializer.h"
+
+#include <unordered_set>
+
+/**
+ * A macro that represents a block of code that gets used a lot inside encodeInternal. It checks if the buffer has enough
+ * space, and if it does it copies the data from the specified location and increments the needed pointers and counters. If
+ * there is not enough space the buffer is flushed (hopefully to make some space). If there is still not enough space the
+ * entire encoding process ends.
+ *
+ * @param	dataPtr	Pointer to data which to copy.
+ * @param	size   	Size of the data to copy
+ */
+#define COPY_TO_BUFFER(dataIter, size)									\
+if((*bytesWritten + size##) > bufferLength)								\
+{																		\
+	mTotalBytesWritten += *bytesWritten;								\
+	buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);	\
+	if(buffer == nullptr || bufferLength < size##) return nullptr;		\
+	*bytesWritten = 0;													\
+}																		\
+																		\
+memcpy(buffer, dataIter##, size##);										\
+buffer += size##;														\
+*bytesWritten += size##;
+
+namespace BansheeEngine
+{
+	BinarySerializer::BinarySerializer()
+		:mLastUsedObjectId(1)
+	{
+	}
+
+	void BinarySerializer::encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, 
+		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
+	{
+		mObjectsToEncode.clear();
+		mObjectAddrToId.clear();
+		mLastUsedObjectId = 1;
+		*bytesWritten = 0;
+		mTotalBytesWritten = 0;
+		UINT8* bufferStart = buffer;
+		Vector<std::shared_ptr<IReflectable>> encodedObjects;
+
+		UINT32 objectId = findOrCreatePersistentId(object);
+		
+		// Encode primary object and its value types
+		buffer = encodeInternal(object, objectId, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
+		if(buffer == nullptr)
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Destination buffer is null or not large enough.");
+		}
+
+		// Encode pointed to objects and their value types
+		UnorderedSet<UINT32> serializedObjects;
+		while(true)
+		{
+			auto iter = mObjectsToEncode.begin();
+			bool foundObjectToProcess = false;
+			for(iter; iter != mObjectsToEncode.end(); ++iter)
+			{
+				auto foundExisting = serializedObjects.find(iter->objectId);
+				if(foundExisting != serializedObjects.end())
+					continue; // Already processed
+
+				std::shared_ptr<IReflectable> curObject = iter->object;
+				UINT32 curObjectid = iter->objectId;
+				serializedObjects.insert(curObjectid);
+				mObjectsToEncode.erase(iter);
+
+				buffer = encodeInternal(curObject.get(), curObjectid, buffer, 
+					bufferLength, bytesWritten, flushBufferCallback, shallow);
+				if(buffer == nullptr)
+				{
+					BS_EXCEPT(InternalErrorException, 
+						"Destination buffer is null or not large enough.");
+				}
+
+				foundObjectToProcess = true;
+
+				// Ensure we keep a reference to the object so it isn't released.
+				// The system assigns unique IDs to IReflectable objects based on pointer 
+				// addresses but if objects get released then same address could be assigned twice.
+				// Note: To get around this I could assign unique IDs to IReflectable objects
+				encodedObjects.push_back(curObject);
+
+				break; // Need to start over as mObjectsToSerialize was possibly modified
+			}
+
+			if(!foundObjectToProcess) // We're done
+				break;
+		}
+
+		// Final flush
+		if(*bytesWritten > 0)
+		{
+			mTotalBytesWritten += *bytesWritten;
+			buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
+		}
+
+		*bytesWritten = mTotalBytesWritten;
+
+		encodedObjects.clear();
+		mObjectsToEncode.clear();
+		mObjectAddrToId.clear();
+	}
+
+	std::shared_ptr<IReflectable> BinarySerializer::decode(UINT8* data, UINT32 dataLength)
+	{
+		if (dataLength == 0)
+			return nullptr;
+
+		SPtr<SerializedObject> intermediateObject = _decodeIntermediate(data, dataLength);
+		if (intermediateObject == nullptr)
+			return nullptr;
+
+		return _decodeIntermediate(intermediateObject);
+	}
+
+	SPtr<IReflectable> BinarySerializer::_decodeIntermediate(const SPtr<SerializedObject>& serializedObject)
+	{
+		mObjectMap.clear();
+
+		SPtr<IReflectable> output;
+		RTTITypeBase* type = IReflectable::_getRTTIfromTypeId(serializedObject->getRootTypeId());
+		if (type != nullptr)
+		{
+			output = type->newRTTIObject();
+			auto iterNewObj = mObjectMap.insert(std::make_pair(serializedObject, ObjectToDecode(output, serializedObject)));
+
+			iterNewObj.first->second.decodeInProgress = true;
+			decodeInternal(output, serializedObject);
+			iterNewObj.first->second.decodeInProgress = false;
+			iterNewObj.first->second.isDecoded = true;
+		}
+
+		// Go through the remaining objects (should be only ones with weak refs)
+		for (auto iter = mObjectMap.begin(); iter != mObjectMap.end(); ++iter)
+		{
+			ObjectToDecode& objToDecode = iter->second;
+
+			if (objToDecode.isDecoded)
+				continue;
+
+			objToDecode.decodeInProgress = true;
+			decodeInternal(objToDecode.object, objToDecode.serializedObject);
+			objToDecode.decodeInProgress = false;
+			objToDecode.isDecoded = true;
+		}
+
+		mObjectMap.clear();
+		return output;
+	}
+
+	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, 
+		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
+	{
+		RTTITypeBase* si = object->getRTTI();
+		bool isBaseClass = false;
+
+		// If an object has base classes, we need to iterate through all of them
+		do
+		{
+			si->onSerializationStarted(object);
+
+			// Encode object ID & type
+			ObjectMetaData objectMetaData = encodeObjectMetaData(objectId, si->getRTTIId(), isBaseClass);
+			COPY_TO_BUFFER(&objectMetaData, sizeof(ObjectMetaData))
+
+			int numFields = si->getNumFields();
+			for(int i = 0; i < numFields; i++)
+			{
+				RTTIField* curGenericField = si->getField(i);
+
+				// Copy field ID & other meta-data like field size and type
+				int metaData = encodeFieldMetaData(curGenericField->mUniqueId, curGenericField->getTypeSize(), 
+					curGenericField->mIsVectorType, curGenericField->mType, curGenericField->hasDynamicSize(), false);
+				COPY_TO_BUFFER(&metaData, META_SIZE)
+
+				if(curGenericField->mIsVectorType)
+				{
+					UINT32 arrayNumElems = curGenericField->getArraySize(object);
+
+					// Copy num vector elements
+					COPY_TO_BUFFER(&arrayNumElems, NUM_ELEM_FIELD_SIZE)
+
+					switch(curGenericField->mType)
+					{
+					case SerializableFT_ReflectablePtr:
+						{
+							RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+							{
+								std::shared_ptr<IReflectable> childObject;
+								
+								if (!shallow)
+									childObject = curField->getArrayValue(object, arrIdx);
+
+								UINT32 objId = registerObjectPtr(childObject);
+								COPY_TO_BUFFER(&objId, sizeof(UINT32))
+							}
+
+							break;
+						}
+					case SerializableFT_Reflectable:
+						{
+							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+							{
+								IReflectable& childObject = curField->getArrayValue(object, arrIdx);
+
+								buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, 
+									bytesWritten, flushBufferCallback, shallow);
+								if(buffer == nullptr)
+								{
+									si->onSerializationEnded(object);
+									return nullptr;
+								}
+							}
+
+							break;
+						}
+					case SerializableFT_Plain:
+						{
+							RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+							{
+								UINT32 typeSize = 0;
+								if(curField->hasDynamicSize())
+									typeSize = curField->getArrayElemDynamicSize(object, arrIdx);
+								else
+									typeSize = curField->getTypeSize();
+
+								if ((*bytesWritten + typeSize) > bufferLength)
+								{
+									UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize);
+									curField->arrayElemToBuffer(object, arrIdx, tempBuffer);
+
+									buffer = dataBlockToBuffer(tempBuffer, typeSize, buffer, bufferLength, bytesWritten, flushBufferCallback);
+									if (buffer == nullptr || bufferLength == 0)
+									{
+										bs_stack_free(tempBuffer);
+										si->onSerializationEnded(object);
+										return nullptr;
+									}
+
+									bs_stack_free(tempBuffer);
+								}
+								else
+								{
+									curField->arrayElemToBuffer(object, arrIdx, buffer);
+									buffer += typeSize;
+									*bytesWritten += typeSize;
+								}
+							}
+
+							break;
+						}
+					default:
+						BS_EXCEPT(InternalErrorException, 
+							"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
+							", Is array: " + toString(curGenericField->mIsVectorType));
+					}
+				}
+				else
+				{
+					switch(curGenericField->mType)
+					{
+					case SerializableFT_ReflectablePtr:
+						{
+							RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+							std::shared_ptr<IReflectable> childObject;
+							
+							if (!shallow)
+								childObject = curField->getValue(object);
+
+							UINT32 objId = registerObjectPtr(childObject);
+							COPY_TO_BUFFER(&objId, sizeof(UINT32))
+
+							break;
+						}
+					case SerializableFT_Reflectable:
+						{
+							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+							IReflectable& childObject = curField->getValue(object);
+
+							buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, 
+								bytesWritten, flushBufferCallback, shallow);
+							if(buffer == nullptr)
+							{
+								si->onSerializationEnded(object);
+								return nullptr;
+							}
+
+							break;
+						}
+					case SerializableFT_Plain:
+						{
+							RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+							UINT32 typeSize = 0;
+							if(curField->hasDynamicSize())
+								typeSize = curField->getDynamicSize(object);
+							else
+								typeSize = curField->getTypeSize();
+
+							if ((*bytesWritten + typeSize) > bufferLength)
+							{
+								UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize);
+								curField->toBuffer(object, tempBuffer);
+								
+								buffer = dataBlockToBuffer(tempBuffer, typeSize, buffer, bufferLength, bytesWritten, flushBufferCallback);
+								if (buffer == nullptr || bufferLength == 0)
+								{
+									bs_stack_free(tempBuffer);
+									si->onSerializationEnded(object);
+									return nullptr;
+								}
+
+								bs_stack_free(tempBuffer);
+							}
+							else
+							{
+								curField->toBuffer(object, buffer);
+								buffer += typeSize;
+								*bytesWritten += typeSize;
+							}
+
+							break;
+						}
+					case SerializableFT_DataBlock:
+						{
+							RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
+							ManagedDataBlock value = curField->getValue(object);
+
+							// Data block size
+							UINT32 dataBlockSize = value.getSize();
+							COPY_TO_BUFFER(&dataBlockSize, sizeof(UINT32))
+
+							// Data block data
+							UINT8* dataToStore = value.getData();
+
+							buffer = dataBlockToBuffer(dataToStore, dataBlockSize, buffer, bufferLength, bytesWritten, flushBufferCallback);
+							if (buffer == nullptr || bufferLength == 0)
+							{
+								si->onSerializationEnded(object);
+								return nullptr;
+							}
+
+							break;
+						}
+					default:
+						BS_EXCEPT(InternalErrorException, 
+							"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
+							", Is array: " + toString(curGenericField->mIsVectorType));
+					}
+				}
+			}
+
+			si->onSerializationEnded(object);
+
+			si = si->getBaseClass();
+			isBaseClass = true;
+
+		} while(si != nullptr); // Repeat until we reach the top of the inheritance hierarchy
+
+		return buffer;
+	}
+
+	SPtr<SerializedObject> BinarySerializer::_encodeIntermediate(IReflectable* object, bool shallow)
+	{
+		// TODO: This is a hacky way of generating an intermediate format to save development time and complexity.
+		// It is hacky because it requires a full on encode to binary and then decode into intermediate. It should 
+		// be better to modify encoding process so it outputs the intermediate format directly (similar to how decoding works). 
+		// This also means that once you have an intermediate format you cannot use it to encode to binary. 
+
+		std::function<void*(UINT32)> allocator = &MemoryAllocator<GenAlloc>::allocate;
+
+		MemorySerializer ms;
+		UINT32 dataLength = 0;
+		UINT8* data = ms.encode(object, dataLength, allocator, shallow);
+
+		BinarySerializer bs;
+		SPtr<SerializedObject> obj = bs._decodeIntermediate(data, dataLength, true);
+
+		bs_free(data);
+		return obj;
+	}
+
+	SPtr<SerializedObject> BinarySerializer::_decodeIntermediate(UINT8* data, UINT32 dataLength, bool copyData)
+	{
+		UINT32 bytesRead = 0;
+		mInterimObjectMap.clear();
+
+		SPtr<SerializedObject> rootObj;
+		bool hasMore = decodeIntermediateInternal(data, dataLength, bytesRead, rootObj, copyData);
+		while (hasMore)
+		{
+			UINT8* dataPtr = data + bytesRead;
+
+			SPtr<SerializedObject> dummyObj;
+			hasMore = decodeIntermediateInternal(dataPtr, dataLength, bytesRead, dummyObj, copyData);
+		}
+
+		return rootObj;
+	}
+
+	bool BinarySerializer::decodeIntermediateInternal(UINT8* data, UINT32 dataLength, UINT32& bytesRead, SPtr<SerializedObject>& output, bool copyData)
+	{
+		if ((bytesRead + sizeof(ObjectMetaData)) > dataLength)
+		{
+			BS_EXCEPT(InternalErrorException,
+				"Error decoding data.");
+		}
+
+		ObjectMetaData objectMetaData;
+		objectMetaData.objectMeta = 0;
+		objectMetaData.typeId = 0;
+		memcpy(&objectMetaData, data, sizeof(ObjectMetaData));
+		data += sizeof(ObjectMetaData);
+		bytesRead += sizeof(ObjectMetaData);
+
+		UINT32 objectId = 0;
+		UINT32 objectTypeId = 0;
+		bool objectIsBaseClass = false;
+		decodeObjectMetaData(objectMetaData, objectId, objectTypeId, objectIsBaseClass);
+
+		if (objectIsBaseClass)
+		{
+			BS_EXCEPT(InternalErrorException, "Encountered a base-class object while looking for a new object. " \
+				"Base class objects are only supposed to be parts of a larger object.");
+		}
+
+		RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(objectTypeId);
+		SerializedSubObject* serializedSubObject = nullptr;
+		
+		if (rtti != nullptr)
+		{
+			if (objectId > 0)
+			{
+				auto iterFind = mInterimObjectMap.find(objectId);
+				if (iterFind == mInterimObjectMap.end())
+				{
+					output = bs_shared_ptr_new<SerializedObject>();
+					mInterimObjectMap.insert(std::make_pair(objectId, output));
+				}
+				else
+					output = iterFind->second;
+			}
+			else // Not a reflectable ptr referenced object
+				output = bs_shared_ptr_new<SerializedObject>();
+
+			output->subObjects.push_back(SerializedSubObject());
+			serializedSubObject = &output->subObjects.back();
+
+			serializedSubObject->typeId = objectTypeId;
+		}
+
+		while (bytesRead < dataLength)
+		{
+			int metaData = -1;
+
+			if ((bytesRead + META_SIZE) > dataLength)
+			{
+				BS_EXCEPT(InternalErrorException,
+					"Error decoding data.");
+			}
+
+			memcpy((void*)&metaData, data, META_SIZE);
+
+			if (isObjectMetaData(metaData)) // We've reached a new object or a base class of the current one
+			{
+				if ((bytesRead + sizeof(ObjectMetaData)) > dataLength)
+				{
+					BS_EXCEPT(InternalErrorException,
+						"Error decoding data.");
+				}
+
+				ObjectMetaData objMetaData;
+				objMetaData.objectMeta = 0;
+				objMetaData.typeId = 0;
+				memcpy(&objMetaData, data, sizeof(ObjectMetaData));
+
+				UINT32 objId = 0;
+				UINT32 objTypeId = 0;
+				bool objIsBaseClass = false;
+				decodeObjectMetaData(objMetaData, objId, objTypeId, objIsBaseClass);
+
+				// If it's a base class, get base class RTTI and handle that
+				if (objIsBaseClass)
+				{
+					if (rtti != nullptr)
+						rtti = rtti->getBaseClass();
+
+					// Saved and current base classes don't match, so just skip over all that data
+					if (rtti == nullptr || rtti->getRTTIId() != objTypeId)
+					{
+						rtti = nullptr;
+					}
+
+					if (rtti != nullptr)
+					{
+						output->subObjects.push_back(SerializedSubObject());
+						serializedSubObject = &output->subObjects.back();
+
+						serializedSubObject->typeId = objTypeId;
+					}
+
+					data += sizeof(ObjectMetaData);
+					bytesRead += sizeof(ObjectMetaData);
+					continue;
+				}
+				else
+				{
+					// Found new object, we're done
+					return true;
+				}
+			}
+
+			data += META_SIZE;
+			bytesRead += META_SIZE;
+
+			bool isArray;
+			SerializableFieldType fieldType;
+			UINT16 fieldId;
+			UINT8 fieldSize;
+			bool hasDynamicSize;
+			bool terminator;
+			decodeFieldMetaData(metaData, fieldId, fieldSize, isArray, fieldType, hasDynamicSize, terminator);
+
+			if (terminator)
+			{
+				// We've processed the last field in this object, so return. Although we return false we don't actually know
+				// if there is an object following this one. However it doesn't matter since terminator fields are only used 
+				// for embedded objects that are all processed within this method so we can compensate.
+				return false;
+			}
+
+			RTTIField* curGenericField = nullptr;
+
+			if (rtti != nullptr)
+				curGenericField = rtti->findField(fieldId);
+
+			if (curGenericField != nullptr)
+			{
+				if (!hasDynamicSize && curGenericField->getTypeSize() != fieldSize)
+				{
+					BS_EXCEPT(InternalErrorException,
+						"Data type mismatch. Type size stored in file and actual type size don't match. ("
+						+ toString(curGenericField->getTypeSize()) + " vs. " + toString(fieldSize) + ")");
+				}
+
+				if (curGenericField->mIsVectorType != isArray)
+				{
+					BS_EXCEPT(InternalErrorException,
+						"Data type mismatch. One is array, other is a single type.");
+				}
+
+				if (curGenericField->mType != fieldType)
+				{
+					BS_EXCEPT(InternalErrorException,
+						"Data type mismatch. Field types don't match. " + toString(UINT32(curGenericField->mType)) + " vs. " + toString(UINT32(fieldType)));
+				}
+			}
+
+			SPtr<SerializedInstance> serializedEntry;
+			bool hasModification = false;
+
+			int arrayNumElems = 1;
+			if (isArray)
+			{
+				if ((bytesRead + NUM_ELEM_FIELD_SIZE) > dataLength)
+				{
+					BS_EXCEPT(InternalErrorException,
+						"Error decoding data.");
+				}
+
+				memcpy((void*)&arrayNumElems, data, NUM_ELEM_FIELD_SIZE);
+				data += NUM_ELEM_FIELD_SIZE;
+				bytesRead += NUM_ELEM_FIELD_SIZE;
+
+				SPtr<SerializedArray> serializedArray;
+				if (curGenericField != nullptr)
+				{
+					serializedArray = bs_shared_ptr_new<SerializedArray>();
+					serializedArray->numElements = arrayNumElems;
+
+					serializedEntry = serializedArray;
+					hasModification = true;
+				}
+
+				switch (fieldType)
+				{
+				case SerializableFT_ReflectablePtr:
+				{
+					RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+					for (int i = 0; i < arrayNumElems; i++)
+					{
+						if ((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
+						{
+							BS_EXCEPT(InternalErrorException,
+								"Error decoding data.");
+						}
+
+						int childObjectId = 0;
+						memcpy(&childObjectId, data, COMPLEX_TYPE_FIELD_SIZE);
+						data += COMPLEX_TYPE_FIELD_SIZE;
+						bytesRead += COMPLEX_TYPE_FIELD_SIZE;
+
+						if (curField != nullptr)
+						{
+							SPtr<SerializedObject> serializedArrayEntry = nullptr;
+							
+							if (childObjectId > 0)
+							{
+								auto findObj = mInterimObjectMap.find(childObjectId);
+								if (findObj == mInterimObjectMap.end())
+								{
+									serializedArrayEntry = bs_shared_ptr_new<SerializedObject>();
+									mInterimObjectMap.insert(std::make_pair(childObjectId, serializedArrayEntry));
+								}
+								else
+									serializedArrayEntry = findObj->second;
+							}
+
+							SerializedArrayEntry arrayEntry;
+							arrayEntry.serialized = serializedArrayEntry;
+							arrayEntry.index = i;
+
+							serializedArray->entries[i] = arrayEntry;
+						}
+					}
+
+					break;
+				}
+				case SerializableFT_Reflectable:
+				{
+					RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+					for (int i = 0; i < arrayNumElems; i++)
+					{
+						if (curField != nullptr)
+						{
+							UINT32 bytesReadStart = bytesRead;
+							SPtr<SerializedObject> serializedArrayEntry;
+							decodeIntermediateInternal(data, dataLength, bytesRead, serializedArrayEntry, copyData);
+
+							SerializedArrayEntry arrayEntry;
+							arrayEntry.serialized = serializedArrayEntry;
+							arrayEntry.index = i;
+
+							serializedArray->entries[i] = arrayEntry;
+
+							UINT32 complexTypeSize = bytesRead - bytesReadStart;
+							data += complexTypeSize;
+						}
+					}
+					break;
+				}
+				case SerializableFT_Plain:
+				{
+					RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+					for (int i = 0; i < arrayNumElems; i++)
+					{
+						UINT32 typeSize = fieldSize;
+						if (hasDynamicSize)
+							memcpy(&typeSize, data, sizeof(UINT32));
+
+						if (curField != nullptr)
+						{
+							SPtr<SerializedField> serializedField = bs_shared_ptr_new<SerializedField>();
+
+							if (copyData)
+							{
+								serializedField->value = (UINT8*)bs_alloc(typeSize);
+								memcpy(serializedField->value, data, typeSize);
+								serializedField->ownsMemory = true;
+							}
+							else
+								serializedField->value = data;
+
+							serializedField->size = typeSize;
+
+							SerializedArrayEntry arrayEntry;
+							arrayEntry.serialized = serializedField;
+							arrayEntry.index = i;
+
+							serializedArray->entries[i] = arrayEntry;
+						}
+
+						data += typeSize;
+						bytesRead += typeSize;
+					}
+					break;
+				}
+				default:
+					BS_EXCEPT(InternalErrorException,
+						"Error decoding data. Encountered a type I don't know how to decode. Type: " + toString(UINT32(fieldType)) +
+						", Is array: " + toString(isArray));
+				}
+			}
+			else
+			{
+				switch (fieldType)
+				{
+				case SerializableFT_ReflectablePtr:
+				{
+					RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+					if ((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
+					{
+						BS_EXCEPT(InternalErrorException,
+							"Error decoding data.");
+					}
+
+					int childObjectId = 0;
+					memcpy(&childObjectId, data, COMPLEX_TYPE_FIELD_SIZE);
+					data += COMPLEX_TYPE_FIELD_SIZE;
+					bytesRead += COMPLEX_TYPE_FIELD_SIZE;
+
+					if (curField != nullptr)
+					{
+						SPtr<SerializedObject> serializedField = nullptr;
+
+						if (childObjectId > 0)
+						{
+							auto findObj = mInterimObjectMap.find(childObjectId);
+							if (findObj == mInterimObjectMap.end())
+							{
+								serializedField = bs_shared_ptr_new<SerializedObject>();
+								mInterimObjectMap.insert(std::make_pair(childObjectId, serializedField));
+							}
+							else
+								serializedField = findObj->second;
+						}
+
+						serializedEntry = serializedField;
+						hasModification = true;
+					}
+
+					break;
+				}
+				case SerializableFT_Reflectable:
+				{
+					RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+					if (curField != nullptr)
+					{
+						UINT32 bytesReadStart = bytesRead;
+						SPtr<SerializedObject> serializedChildObj;
+						decodeIntermediateInternal(data, dataLength, bytesRead, serializedChildObj, copyData);
+
+						serializedEntry = serializedChildObj;
+						hasModification = true;
+
+						UINT32 complexTypeSize = bytesRead - bytesReadStart;
+						data += complexTypeSize;
+					}
+
+					break;
+				}
+				case SerializableFT_Plain:
+				{
+					RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+					UINT32 typeSize = fieldSize;
+					if (hasDynamicSize)
+						memcpy(&typeSize, data, sizeof(UINT32));
+
+					if (curField != nullptr)
+					{
+						SPtr<SerializedField> serializedField = bs_shared_ptr_new<SerializedField>();
+
+						if (copyData)
+						{
+							serializedField->value = (UINT8*)bs_alloc(typeSize);
+							memcpy(serializedField->value, data, typeSize);
+							serializedField->ownsMemory = true;
+						}
+						else
+							serializedField->value = data;
+
+						serializedField->size = typeSize;
+
+						serializedEntry = serializedField;
+						hasModification = true;
+					}
+
+					data += typeSize;
+					bytesRead += typeSize;
+					break;
+				}
+				case SerializableFT_DataBlock:
+				{
+					RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
+
+					if ((bytesRead + DATA_BLOCK_TYPE_FIELD_SIZE) > dataLength)
+					{
+						BS_EXCEPT(InternalErrorException,
+							"Error decoding data.");
+					}
+
+					// Data block size
+					UINT32 dataBlockSize = 0;
+					memcpy(&dataBlockSize, data, DATA_BLOCK_TYPE_FIELD_SIZE);
+					data += DATA_BLOCK_TYPE_FIELD_SIZE;
+					bytesRead += DATA_BLOCK_TYPE_FIELD_SIZE;
+
+					if ((bytesRead + dataBlockSize) > dataLength)
+					{
+						BS_EXCEPT(InternalErrorException,
+							"Error decoding data.");
+					}
+
+					// Data block data
+					if (curField != nullptr)
+					{
+						SPtr<SerializedField> serializedField = bs_shared_ptr_new<SerializedField>();
+
+						if (copyData)
+						{
+							serializedField->value = (UINT8*)bs_alloc(dataBlockSize);
+							memcpy(serializedField->value, data, dataBlockSize);
+							serializedField->ownsMemory = true;
+						}
+						else
+							serializedField->value = data;
+
+						serializedField->size = dataBlockSize;
+
+						serializedEntry = serializedField;
+						hasModification = true;
+					}
+
+					data += dataBlockSize;
+					bytesRead += dataBlockSize;
+
+					break;
+				}
+				default:
+					BS_EXCEPT(InternalErrorException,
+						"Error decoding data. Encountered a type I don't know how to decode. Type: " + toString(UINT32(fieldType)) +
+						", Is array: " + toString(isArray));
+				}
+			}
+
+			if (hasModification)
+			{
+				SerializedEntry entry;
+				entry.fieldId = curGenericField->mUniqueId;
+				entry.serialized = serializedEntry;
+
+				serializedSubObject->entries.insert(std::make_pair(curGenericField->mUniqueId, entry));
+			}
+		}
+
+		return false;
+	}
+
+	void BinarySerializer::decodeInternal(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serializableObject)
+	{
+		UINT32 numSubObjects = (UINT32)serializableObject->subObjects.size();
+
+		Vector<RTTITypeBase*> rttiTypes;
+		for (UINT32 subObjectIdx = 0; subObjectIdx < numSubObjects; subObjectIdx++)
+		{
+			const SerializedSubObject& subObject = serializableObject->subObjects[subObjectIdx];
+
+			RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
+			if (rtti == nullptr)
+				continue;
+
+			rtti->onDeserializationStarted(object.get());
+			rttiTypes.push_back(rtti);
+
+			UINT32 numFields = rtti->getNumFields();
+			for (UINT32 fieldIdx = 0; fieldIdx < numFields; fieldIdx++)
+			{
+				RTTIField* curGenericField = rtti->getField(fieldIdx);
+
+				auto iterFindFieldData = subObject.entries.find(curGenericField->mUniqueId);
+				if (iterFindFieldData == subObject.entries.end())
+					continue;
+
+				SPtr<SerializedInstance> entryData = iterFindFieldData->second.serialized;
+				if (curGenericField->isArray())
+				{
+					SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
+
+					UINT32 arrayNumElems = (UINT32)arrayData->numElements;
+					curGenericField->setArraySize(object.get(), arrayNumElems);
+
+					switch (curGenericField->mType)
+					{
+					case SerializableFT_ReflectablePtr:
+					{
+						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+						for (auto& arrayElem : arrayData->entries)
+						{
+							SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
+							RTTITypeBase* childRtti = nullptr;
+							
+							if (arrayElemData != nullptr)
+								childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
+
+							if (childRtti != nullptr)
+							{
+								auto findObj = mObjectMap.find(arrayElemData);
+								if (findObj == mObjectMap.end())
+								{
+									SPtr<IReflectable> newObject = childRtti->newRTTIObject();
+									findObj = mObjectMap.insert(std::make_pair(arrayElemData, ObjectToDecode(newObject, arrayElemData))).first;
+								}
+
+								ObjectToDecode& objToDecode = findObj->second;
+
+								bool needsDecoding = (curField->getFlags() & RTTI_Flag_WeakRef) == 0 && !objToDecode.isDecoded;
+								if (needsDecoding)
+								{
+									if (objToDecode.decodeInProgress)
+									{
+										LOGWRN("Detected a circular reference when decoding. Referenced object fields " \
+											"will be resolved in an undefined order (i.e. one of the objects will not " \
+											"be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \
+											"get rid of this warning and tell the system which of the objects is allowed " \
+											"to be deserialized after it is assigned to its field.");
+									}
+									else
+									{
+										objToDecode.decodeInProgress = true;
+										decodeInternal(objToDecode.object, objToDecode.serializedObject);
+										objToDecode.decodeInProgress = false;
+										objToDecode.isDecoded = true;
+									}
+								}
+
+								curField->setArrayValue(object.get(), arrayElem.first, objToDecode.object);
+							}
+							else
+							{
+								curField->setArrayValue(object.get(), arrayElem.first, nullptr);
+							}
+						}
+					}
+						break;
+					case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+						for (auto& arrayElem : arrayData->entries)
+						{
+							SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
+							RTTITypeBase* childRtti = nullptr;
+
+							if (arrayElemData != nullptr)
+								childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
+
+							if (childRtti != nullptr)
+							{
+								SPtr<IReflectable> newObject = childRtti->newRTTIObject();
+								decodeInternal(newObject, arrayElemData);
+								curField->setArrayValue(object.get(), arrayElem.first, *newObject);
+							}
+						}
+						break;
+					}
+					case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+						for (auto& arrayElem : arrayData->entries)
+						{
+							SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(arrayElem.second.serialized);
+							if (fieldData != nullptr)
+							{
+								curField->arrayElemFromBuffer(object.get(), arrayElem.first, fieldData->value);
+							}
+						}
+					}
+						break;
+					}
+				}
+				else
+				{
+					switch (curGenericField->mType)
+					{
+					case SerializableFT_ReflectablePtr:
+					{
+						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
+						RTTITypeBase* childRtti = nullptr;
+
+						if (fieldObjectData != nullptr)
+							childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
+
+						if (childRtti != nullptr)
+						{
+							auto findObj = mObjectMap.find(fieldObjectData);
+							if (findObj == mObjectMap.end())
+							{
+								SPtr<IReflectable> newObject = childRtti->newRTTIObject();
+								findObj = mObjectMap.insert(std::make_pair(fieldObjectData, ObjectToDecode(newObject, fieldObjectData))).first;
+							}
+
+							ObjectToDecode& objToDecode = findObj->second;
+
+							bool needsDecoding = (curField->getFlags() & RTTI_Flag_WeakRef) == 0 && !objToDecode.isDecoded;
+							if (needsDecoding)
+							{
+								if (objToDecode.decodeInProgress)
+								{
+									LOGWRN("Detected a circular reference when decoding. Referenced object's fields " \
+										"will be resolved in an undefined order (i.e. one of the objects will not " \
+										"be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \
+										"get rid of this warning and tell the system which of the objects is allowed " \
+										"to be deserialized after it is assigned to its field.");
+								}
+								else
+								{
+									objToDecode.decodeInProgress = true;
+									decodeInternal(objToDecode.object, objToDecode.serializedObject);
+									objToDecode.decodeInProgress = false;
+									objToDecode.isDecoded = true;
+								}
+							}
+
+							curField->setValue(object.get(), objToDecode.object);
+						}
+						else
+						{
+							curField->setValue(object.get(), nullptr);
+						}
+					}
+						break;
+					case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
+						RTTITypeBase* childRtti = nullptr;
+
+						if (fieldObjectData != nullptr)
+							childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
+
+						if (childRtti != nullptr)
+						{
+							SPtr<IReflectable> newObject = childRtti->newRTTIObject();
+							decodeInternal(newObject, fieldObjectData);
+							curField->setValue(object.get(), *newObject);
+						}
+						break;
+					}
+					case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+						SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(entryData);
+						if (fieldData != nullptr)
+						{
+							curField->fromBuffer(object.get(), fieldData->value);
+						}
+					}
+						break;
+					case SerializableFT_DataBlock:
+					{
+						RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
+
+						SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(entryData);
+						if (fieldData != nullptr)
+						{
+							UINT8* dataCopy = curField->allocate(object.get(), fieldData->size); // TODO - Low priority. I need to read files better, so I
+							memcpy(dataCopy, fieldData->value, fieldData->size);		//    can just pass the buffer pointer directly without copying (possibly large amounts of data)
+
+							ManagedDataBlock value(dataCopy, fieldData->size); // Not managed because I assume the owner class will decide whether to delete the data or keep it
+							curField->setValue(object.get(), value);
+						}
+
+						break;
+					}
+					}
+				}
+			}
+		}
+
+		for (auto iterFind = rttiTypes.rbegin(); iterFind != rttiTypes.rend(); ++iterFind)
+		{
+			(*iterFind)->onDeserializationEnded(object.get());
+		}
+	}
+
+	UINT32 BinarySerializer::encodeFieldMetaData(UINT16 id, UINT8 size, bool array, 
+		SerializableFieldType type, bool hasDynamicSize, bool terminator)
+	{
+		// If O == 0 - Meta contains field information (Encoded using this method)
+		//// Encoding: IIII IIII IIII IIII SSSS SSSS xTYP DCAO
+		//// I - Id
+		//// S - Size
+		//// C - Complex
+		//// A - Array
+		//// D - Data block
+		//// P - Complex ptr
+		//// O - Object descriptor
+		//// Y - Plain field has dynamic size
+		//// T - Terminator (last field in an object)
+
+		return (id << 16 | size << 8 | 
+			(array ? 0x02 : 0) | 
+			((type == SerializableFT_DataBlock) ? 0x04 : 0) | 
+			((type == SerializableFT_Reflectable) ? 0x08 : 0) | 
+			((type == SerializableFT_ReflectablePtr) ? 0x10 : 0) | 
+			(hasDynamicSize ? 0x20 : 0) |
+			(terminator ? 0x40 : 0)); // TODO - Low priority. Technically I could encode this much more tightly, and use var-ints for ID
+	}
+
+	void BinarySerializer::decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, 
+		bool& array, SerializableFieldType& type, bool& hasDynamicSize, bool& terminator)
+	{
+		if(isObjectMetaData(encodedData))
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Meta data represents an object description but is trying to be decoded as a field descriptor.");
+		}
+
+		terminator = (encodedData & 0x40) != 0;
+		hasDynamicSize = (encodedData & 0x20) != 0;
+
+		if((encodedData & 0x10) != 0)
+			type = SerializableFT_ReflectablePtr;
+		else if((encodedData & 0x08) != 0)
+			type = SerializableFT_Reflectable;
+		else if((encodedData & 0x04) != 0)
+			type = SerializableFT_DataBlock;
+		else
+			type = SerializableFT_Plain;
+
+		array = (encodedData & 0x02) != 0;
+		size = (UINT8)((encodedData >> 8) & 0xFF);
+		id = (UINT16)((encodedData >> 16) & 0xFFFF);
+	}
+
+	BinarySerializer::ObjectMetaData BinarySerializer::encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass)
+	{
+		// If O == 1 - Meta contains object instance information (Encoded using encodeObjectMetaData)
+		//// Encoding: SSSS SSSS SSSS SSSS xxxx xxxx xxxx xxBO
+		//// S - Size of the object identifier
+		//// O - Object descriptor
+		//// B - Base class indicator
+		
+		if(objId > 1073741823)
+		{
+			BS_EXCEPT(InvalidParametersException, "Object ID is larger than we can store (max 30 bits): " + toString(objId));
+		}
+
+		ObjectMetaData metaData;
+		metaData.objectMeta = (objId << 2) | (isBaseClass ? 0x02 : 0) | 0x01;
+		metaData.typeId = objTypeId;
+		return metaData;
+	}
+
+	void BinarySerializer::decodeObjectMetaData(BinarySerializer::ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass)
+	{
+		if(!isObjectMetaData(encodedData.objectMeta))
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Meta data represents a field description but is trying to be decoded as an object descriptor.");
+		}
+
+		objId = (encodedData.objectMeta >> 2) & 0x3FFFFFFF;
+		isBaseClass = (encodedData.objectMeta & 0x02) != 0;
+		objTypeId = encodedData.typeId;
+	}
+
+	bool BinarySerializer::isObjectMetaData(UINT32 encodedData)
+	{
+		return ((encodedData & 0x01) != 0);
+	}
+
+	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, 
+		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
+	{
+		if (object != nullptr)
+		{
+			buffer = encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
+
+			// Encode terminator field
+			// Complex types require terminator fields because they can be embedded within other complex types and we need
+			// to know when their fields end and parent's resume
+			int metaData = encodeFieldMetaData(0, 0, false, SerializableFT_Plain, false, true);
+			COPY_TO_BUFFER(&metaData, META_SIZE)
+		}
+
+		return buffer;
+	}
+
+	UINT8* BinarySerializer::dataBlockToBuffer(UINT8* data, UINT32 size, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
+		std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback)
+	{
+		UINT32 remainingSize = size;
+		while (remainingSize > 0)
+		{
+			UINT32 remainingSpaceInBuffer = bufferLength - *bytesWritten;
+
+			if (remainingSize <= remainingSpaceInBuffer)
+			{
+				COPY_TO_BUFFER(data, remainingSize);
+				remainingSize = 0;
+			}
+			else
+			{
+				memcpy(buffer, data, remainingSpaceInBuffer);
+				buffer += remainingSpaceInBuffer;
+				*bytesWritten += remainingSpaceInBuffer;
+				data += remainingSpaceInBuffer;
+				remainingSize -= remainingSpaceInBuffer;
+
+				mTotalBytesWritten += *bytesWritten;
+				buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
+				if (buffer == nullptr || bufferLength == 0)
+					return nullptr;
+
+				*bytesWritten = 0;
+			}
+		}
+
+		return buffer;
+	}
+
+	UINT32 BinarySerializer::findOrCreatePersistentId(IReflectable* object)
+	{
+		void* ptrAddress = (void*)object;
+
+		auto findIter = mObjectAddrToId.find(ptrAddress);
+		if(findIter != mObjectAddrToId.end())
+			return findIter->second;
+
+		UINT32 objId = mLastUsedObjectId++;
+		mObjectAddrToId.insert(std::make_pair(ptrAddress, objId));
+
+		return objId;
+	}
+
+	UINT32 BinarySerializer::registerObjectPtr(std::shared_ptr<IReflectable> object)
+	{
+		if(object == nullptr)
+			return 0;
+
+		void* ptrAddress = (void*)object.get();
+
+		auto iterFind = mObjectAddrToId.find(ptrAddress);
+		if(iterFind == mObjectAddrToId.end())
+		{
+			UINT32 objId = findOrCreatePersistentId(object.get());
+
+			mObjectsToEncode.push_back(ObjectToEncode(objId, object));
+			mObjectAddrToId.insert(std::make_pair(ptrAddress, objId));
+
+			return objId;
+		}
+
+		return iterFind->second;
+	}
+}
+
 #undef COPY_TO_BUFFER

+ 473 - 489
Source/BansheeUtility/Source/BsDataStream.cpp

@@ -1,489 +1,473 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsDataStream.h"
-#include "BsDebug.h"
-#include "BsException.h"
-#include <codecvt>
-
-namespace BansheeEngine 
-{
-	const UINT32 DataStream::StreamTempSize = 128;
-
-	/**
-	 * @brief	Checks does the provided buffer has an UTF32 byte order mark
-	 *			in little endian order.
-	 */
-	bool isUTF32LE(const UINT8* buffer)
-	{
-		return buffer[0] == 0xFF && buffer[1] == 0xFE && buffer[2] == 0x00 && buffer[3] == 0x00;
-	}
-
-	/**
-	 * @brief	Checks does the provided buffer has an UTF32 byte order mark
-	 *			in big endian order.
-	 */
-	bool isUTF32BE(const UINT8* buffer)
-	{
-		return buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0xFE && buffer[3] == 0xFF;
-	}
-
-	/**
-	 * @brief	Checks does the provided buffer has an UTF16 byte order mark
-	 *			in little endian order.
-	 */
-	bool isUTF16LE(const UINT8* buffer)
-	{
-		return buffer[0] == 0xFF && buffer[1] == 0xFE;
-	}
-
-	/**
-	 * @brief	Checks does the provided buffer has an UTF16 byte order mark
-	 *			in big endian order.
-	 */
-	bool isUTF16BE(const UINT8* buffer)
-	{
-		return buffer[0] == 0xFE && buffer[1] == 0xFF;
-	}
-
-	/**
-	 * @brief	Checks does the provided buffer has an UTF8 byte order mark.
-	 */
-	bool isUTF8(const UINT8* buffer)
-	{
-		return (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF);
-	}
-
-    template <typename T> DataStream& DataStream::operator>> (T& val)
-    {
-        read(static_cast<void*>(&val), sizeof(T));
-
-        return *this;
-    }
-
-	void DataStream::writeString(const String& string, StringEncoding encoding)
-	{
-		if (encoding == StringEncoding::UTF16)
-		{
-			const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header);
-			typedef std::codecvt_utf8_utf16<char, 1114111, convMode> UTF8ToUTF16Conv;
-			std::wstring_convert<UTF8ToUTF16Conv, char> conversion("?");
-
-			std::string encodedString = conversion.from_bytes(string.c_str());
-			write(encodedString.data(), encodedString.length());
-		}
-		else
-		{
-			write(string.data(), string.length());
-		}
-	}
-
-	void DataStream::writeString(const WString& string, StringEncoding encoding)
-	{
-		if (encoding == StringEncoding::UTF16)
-		{
-			const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header | std::little_endian);
-			typedef std::codecvt_utf16<wchar_t, 1114111, convMode> WCharToUTF16Conv;
-			std::wstring_convert<WCharToUTF16Conv, wchar_t> conversion("?");
-
-			std::string encodedString = conversion.to_bytes(string.c_str());
-			write(encodedString.data(), encodedString.length());
-		}
-		else
-		{
-			const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header);
-			typedef std::codecvt_utf8<wchar_t, 1114111, convMode> WCharToUTF8Conv;
-			std::wstring_convert<WCharToUTF8Conv, wchar_t> conversion("?");
-
-			std::string encodedString = conversion.to_bytes(string.c_str());
-			write(encodedString.data(), encodedString.length());
-		}
-	}
-
-	String DataStream::getAsString()
-	{
-		// Read the entire buffer - ideally in one read, but if the size of
-		// the buffer is unknown, do multiple fixed size reads.
-		size_t bufSize = (mSize > 0 ? mSize : 4096);
-		std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
-
-		// Ensure read from begin of stream
-		seek(0);
-
-		std::stringstream result;
-		while (!eof())
-		{
-			size_t numReadBytes = read(tempBuffer, bufSize);
-			result.write(tempBuffer, numReadBytes);
-		}
-
-		free(tempBuffer);
-		std::string string = result.str();
-
-		UINT32 readBytes = (UINT32)string.size();
-		if (readBytes >= 4)
-		{
-			if (isUTF32LE((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
-				typedef std::codecvt_utf8<UINT32, 1114111, convMode> utf8utf32;
-
-				std::wstring_convert<utf8utf32, UINT32> conversion("?");
-				UINT32* start = (UINT32*)string.data();
-				UINT32* end = (start + (string.size() - 1) / 4);
-
-				return conversion.to_bytes(start, end).c_str();
-			}
-			else if (isUTF32BE((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
-				typedef std::codecvt_utf8<UINT32, 1114111, convMode> utf8utf32;
-
-				std::wstring_convert<utf8utf32, UINT32> conversion("?");
-				UINT32* start = (UINT32*)string.data();
-				UINT32* end = (start + (string.size() - 1) / 4);
-
-				return conversion.to_bytes(start, end).c_str();
-			}			
-		}
-		
-		if (readBytes >= 3)
-		{
-			if (isUTF8((UINT8*)string.data()))
-			{
-				return string.c_str() + 3;
-			}
-		}
-
-		if (readBytes >= 2)
-		{
-			if (isUTF16LE((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(std::little_endian);
-				typedef std::codecvt_utf8_utf16<UINT16, 1114111, convMode> utf8utf16;
-
-				std::wstring_convert<utf8utf16, UINT16> conversion("?");
-				UINT16* start = (UINT16*)(string.c_str() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
-
-				return conversion.to_bytes(start).c_str();
-			}
-			else if (isUTF16BE((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(0);
-				typedef std::codecvt_utf8_utf16<UINT16, 1114111, convMode> utf8utf16;
-
-				// Bug?: Regardless of not providing the std::little_endian flag it seems that is how the data is read
-				// so I manually flip it
-				UINT32 numChars = (UINT32)(string.size() - 2) / 2;
-				for (UINT32 i = 0; i < numChars; i++)
-					std::swap(string[i * 2 + 0], string[i * 2 + 1]);
-
-				std::wstring_convert<utf8utf16, UINT16> conversion("?");
-				UINT16* start = (UINT16*)(string.c_str() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
-
-				return conversion.to_bytes(start).c_str();
-			}
-		}
-
-		return string.c_str();
-	}
-
-	WString DataStream::getAsWString()
-	{
-		// Read the entire buffer - ideally in one read, but if the size of
-		// the buffer is unknown, do multiple fixed size reads.
-		size_t bufSize = (mSize > 0 ? mSize : 4096);
-		std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
-
-		// Ensure read from begin of stream
-		seek(0);
-
-		std::stringstream result;
-		while (!eof())
-		{
-			size_t numReadBytes = read(tempBuffer, bufSize);
-			result.write(tempBuffer, numReadBytes);
-		}
-
-		free(tempBuffer);
-		std::string string = result.str();
-
-		UINT32 readBytes = (UINT32)string.size();
-		if (readBytes >= 4)
-		{
-			if (isUTF32LE((UINT8*)string.data()))
-			{
-				// Not supported
-			}
-			else if (isUTF32BE((UINT8*)string.data()))
-			{
-				// Not supported
-			}
-		}
-
-		if (readBytes >= 3)
-		{
-			if (isUTF8((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
-				typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
-
-				std::wstring_convert<wcharutf8> conversion("?");
-				return conversion.from_bytes(string).c_str();
-			}
-		}
-
-		if (readBytes >= 2)
-		{
-			if (isUTF16LE((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
-				typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
-
-				std::wstring_convert<wcharutf16> conversion("?");
-				return conversion.from_bytes(string).c_str();
-			}
-			else if (isUTF16BE((UINT8*)string.data()))
-			{
-				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
-				typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
-
-				std::wstring_convert<wcharutf16> conversion("?");
-				return conversion.from_bytes(string).c_str();
-			}
-		}
-
-		{
-			const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
-			typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
-
-			std::wstring_convert<wcharutf8> conversion("?");
-			return conversion.from_bytes(string).c_str();
-		}
-	}
-
-    MemoryDataStream::MemoryDataStream(void* memory, size_t inSize)
-		: DataStream(READ | WRITE), mData(nullptr)
-    {
-        mData = mPos = static_cast<UINT8*>(memory);
-        mSize = inSize;
-        mEnd = mData + mSize;
-
-        assert(mEnd >= mPos);
-    }
-
-    MemoryDataStream::MemoryDataStream(DataStream& sourceStream)
-        : DataStream(READ | WRITE), mData(nullptr)
-    {
-        // Copy data from incoming stream
-        mSize = sourceStream.size();
-
-		mData = (UINT8*)bs_alloc((UINT32)mSize);
-		mPos = mData;
-		mEnd = mData + sourceStream.read(mData, mSize);
-
-        assert(mEnd >= mPos);
-    }
-
-    MemoryDataStream::MemoryDataStream(const DataStreamPtr& sourceStream)
-        :DataStream(READ | WRITE), mData(nullptr)
-    {
-        // Copy data from incoming stream
-        mSize = sourceStream->size();
-
-		mData = (UINT8*)bs_alloc((UINT32)mSize);
-		mPos = mData;
-		mEnd = mData + sourceStream->read(mData, mSize);
-
-        assert(mEnd >= mPos);
-    }
-
-    MemoryDataStream::~MemoryDataStream()
-    {
-        close();
-    }
-
-    size_t MemoryDataStream::read(void* buf, size_t count)
-    {
-        size_t cnt = count;
-
-        if (mPos + cnt > mEnd)
-            cnt = mEnd - mPos;
-        if (cnt == 0)
-            return 0;
-
-        assert (cnt <= count);
-
-        memcpy(buf, mPos, cnt);
-        mPos += cnt;
-
-        return cnt;
-    }
-
-	size_t MemoryDataStream::write(const void* buf, size_t count)
-	{
-		size_t written = 0;
-		if (isWriteable())
-		{
-			written = count;
-
-			if (mPos + written > mEnd)
-				written = mEnd - mPos;
-			if (written == 0)
-				return 0;
-
-			memcpy(mPos, buf, written);
-			mPos += written;
-		}
-
-		return written;
-	}
-
-    void MemoryDataStream::skip(size_t count)
-    {
-        size_t newpos = (size_t)( (mPos - mData) + count );
-        assert(mData + newpos <= mEnd);        
-
-        mPos = mData + newpos;
-    }
-
-    void MemoryDataStream::seek(size_t pos)
-    {
-        assert(mData + pos <= mEnd);
-        mPos = mData + pos;
-    }
-
-    size_t MemoryDataStream::tell() const
-	{
-		return mPos - mData;
-	}
-
-    bool MemoryDataStream::eof() const
-    {
-        return mPos >= mEnd;
-    }
-
-    void MemoryDataStream::close()    
-    {
-        if (mData != nullptr)
-        {
-            bs_free(mData);
-            mData = nullptr;
-        }
-    }
-
-    FileDataStream::FileDataStream(std::shared_ptr<std::ifstream> s, bool freeOnClose)
-        : DataStream(READ), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
-    {
-        mpInStream->seekg(0, std::ios_base::end);
-        mSize = (size_t)mpInStream->tellg();
-        mpInStream->seekg(0, std::ios_base::beg);
-
-		determineAccess();
-    }
-
-    FileDataStream::FileDataStream(std::shared_ptr<std::ifstream> s, size_t inSize, bool freeOnClose)
-        : DataStream(READ), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
-    {
-        mSize = inSize;
-
-		determineAccess();
-    }
-
-	FileDataStream::FileDataStream(std::shared_ptr<std::fstream> s, bool freeOnClose)
-		: DataStream(READ | WRITE), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
-	{
-		mpInStream->seekg(0, std::ios_base::end);
-		mSize = (size_t)mpInStream->tellg();
-		mpInStream->seekg(0, std::ios_base::beg);
-
-		determineAccess();
-	}
-
-	FileDataStream::FileDataStream(std::shared_ptr<std::fstream> s, size_t inSize, bool freeOnClose)
-		: DataStream(READ | WRITE), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
-	{
-		mSize = inSize;
-
-		determineAccess();
-	}
-
-	void FileDataStream::determineAccess()
-	{
-		mAccess = 0;
-
-		if (mpInStream)
-			mAccess |= READ;
-
-		if (mpFStream)
-			mAccess |= WRITE;
-	}
-
-    FileDataStream::~FileDataStream()
-    {
-        close();
-    }
-
-    size_t FileDataStream::read(void* buf, size_t count)
-    {
-		mpInStream->read(static_cast<char*>(buf), static_cast<std::streamsize>(count));
-
-        return (size_t)mpInStream->gcount();
-    }
-
-	size_t FileDataStream::write(const void* buf, size_t count)
-	{
-		size_t written = 0;
-		if (isWriteable() && mpFStream)
-		{
-			mpFStream->write(static_cast<const char*>(buf), static_cast<std::streamsize>(count));
-			written = count;
-		}
-
-		return written;
-	}
-    void FileDataStream::skip(size_t count)
-    {	
-		mpInStream->clear(); // Clear fail status in case eof was set
-		mpInStream->seekg(static_cast<std::ifstream::pos_type>(count), std::ios::cur);
-    }
-
-    void FileDataStream::seek(size_t pos)
-    {
-		mpInStream->clear(); // Clear fail status in case eof was set
-		mpInStream->seekg(static_cast<std::streamoff>(pos), std::ios::beg);
-	}
-
-    size_t FileDataStream::tell() const
-	{
-		mpInStream->clear(); // Clear fail status in case eof was set
-
-		return (size_t)mpInStream->tellg();
-	}
-
-    bool FileDataStream::eof() const
-    {
-        return mpInStream->eof();
-    }
-
-    void FileDataStream::close()
-    {
-        if (mpInStream)
-        {
-			if (mpFStreamRO)
-	            mpFStreamRO->close();
-
-			if (mpFStream)
-			{
-				mpFStream->flush();
-				mpFStream->close();
-			}
-
-            if (mFreeOnClose)
-            {
-				mpInStream = nullptr;
-				mpFStreamRO = nullptr; 
-				mpFStream = nullptr; 
-            }
-        }
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsDataStream.h"
+#include <codecvt>
+
+namespace BansheeEngine 
+{
+	const UINT32 DataStream::StreamTempSize = 128;
+
+	/** Checks does the provided buffer has an UTF32 byte order mark in little endian order. */
+	bool isUTF32LE(const UINT8* buffer)
+	{
+		return buffer[0] == 0xFF && buffer[1] == 0xFE && buffer[2] == 0x00 && buffer[3] == 0x00;
+	}
+
+	/** Checks does the provided buffer has an UTF32 byte order mark in big endian order. */
+	bool isUTF32BE(const UINT8* buffer)
+	{
+		return buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0xFE && buffer[3] == 0xFF;
+	}
+
+	/** Checks does the provided buffer has an UTF16 byte order mark in little endian order. */
+	bool isUTF16LE(const UINT8* buffer)
+	{
+		return buffer[0] == 0xFF && buffer[1] == 0xFE;
+	}
+
+	/**	Checks does the provided buffer has an UTF16 byte order mark in big endian order. */
+	bool isUTF16BE(const UINT8* buffer)
+	{
+		return buffer[0] == 0xFE && buffer[1] == 0xFF;
+	}
+
+	/**	Checks does the provided buffer has an UTF8 byte order mark. */
+	bool isUTF8(const UINT8* buffer)
+	{
+		return (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF);
+	}
+
+    template <typename T> DataStream& DataStream::operator>> (T& val)
+    {
+        read(static_cast<void*>(&val), sizeof(T));
+
+        return *this;
+    }
+
+	void DataStream::writeString(const String& string, StringEncoding encoding)
+	{
+		if (encoding == StringEncoding::UTF16)
+		{
+			const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header);
+			typedef std::codecvt_utf8_utf16<char, 1114111, convMode> UTF8ToUTF16Conv;
+			std::wstring_convert<UTF8ToUTF16Conv, char> conversion("?");
+
+			std::string encodedString = conversion.from_bytes(string.c_str());
+			write(encodedString.data(), encodedString.length());
+		}
+		else
+		{
+			write(string.data(), string.length());
+		}
+	}
+
+	void DataStream::writeString(const WString& string, StringEncoding encoding)
+	{
+		if (encoding == StringEncoding::UTF16)
+		{
+			const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header | std::little_endian);
+			typedef std::codecvt_utf16<wchar_t, 1114111, convMode> WCharToUTF16Conv;
+			std::wstring_convert<WCharToUTF16Conv, wchar_t> conversion("?");
+
+			std::string encodedString = conversion.to_bytes(string.c_str());
+			write(encodedString.data(), encodedString.length());
+		}
+		else
+		{
+			const std::codecvt_mode convMode = (std::codecvt_mode)(std::generate_header);
+			typedef std::codecvt_utf8<wchar_t, 1114111, convMode> WCharToUTF8Conv;
+			std::wstring_convert<WCharToUTF8Conv, wchar_t> conversion("?");
+
+			std::string encodedString = conversion.to_bytes(string.c_str());
+			write(encodedString.data(), encodedString.length());
+		}
+	}
+
+	String DataStream::getAsString()
+	{
+		// Read the entire buffer - ideally in one read, but if the size of
+		// the buffer is unknown, do multiple fixed size reads.
+		size_t bufSize = (mSize > 0 ? mSize : 4096);
+		std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
+
+		// Ensure read from begin of stream
+		seek(0);
+
+		std::stringstream result;
+		while (!eof())
+		{
+			size_t numReadBytes = read(tempBuffer, bufSize);
+			result.write(tempBuffer, numReadBytes);
+		}
+
+		free(tempBuffer);
+		std::string string = result.str();
+
+		UINT32 readBytes = (UINT32)string.size();
+		if (readBytes >= 4)
+		{
+			if (isUTF32LE((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
+				typedef std::codecvt_utf8<UINT32, 1114111, convMode> utf8utf32;
+
+				std::wstring_convert<utf8utf32, UINT32> conversion("?");
+				UINT32* start = (UINT32*)string.data();
+				UINT32* end = (start + (string.size() - 1) / 4);
+
+				return conversion.to_bytes(start, end).c_str();
+			}
+			else if (isUTF32BE((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
+				typedef std::codecvt_utf8<UINT32, 1114111, convMode> utf8utf32;
+
+				std::wstring_convert<utf8utf32, UINT32> conversion("?");
+				UINT32* start = (UINT32*)string.data();
+				UINT32* end = (start + (string.size() - 1) / 4);
+
+				return conversion.to_bytes(start, end).c_str();
+			}			
+		}
+		
+		if (readBytes >= 3)
+		{
+			if (isUTF8((UINT8*)string.data()))
+			{
+				return string.c_str() + 3;
+			}
+		}
+
+		if (readBytes >= 2)
+		{
+			if (isUTF16LE((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(std::little_endian);
+				typedef std::codecvt_utf8_utf16<UINT16, 1114111, convMode> utf8utf16;
+
+				std::wstring_convert<utf8utf16, UINT16> conversion("?");
+				UINT16* start = (UINT16*)(string.c_str() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
+
+				return conversion.to_bytes(start).c_str();
+			}
+			else if (isUTF16BE((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(0);
+				typedef std::codecvt_utf8_utf16<UINT16, 1114111, convMode> utf8utf16;
+
+				// Bug?: Regardless of not providing the std::little_endian flag it seems that is how the data is read
+				// so I manually flip it
+				UINT32 numChars = (UINT32)(string.size() - 2) / 2;
+				for (UINT32 i = 0; i < numChars; i++)
+					std::swap(string[i * 2 + 0], string[i * 2 + 1]);
+
+				std::wstring_convert<utf8utf16, UINT16> conversion("?");
+				UINT16* start = (UINT16*)(string.c_str() + 2); // Bug?: std::consume_header seems to be ignored so I manually remove the header
+
+				return conversion.to_bytes(start).c_str();
+			}
+		}
+
+		return string.c_str();
+	}
+
+	WString DataStream::getAsWString()
+	{
+		// Read the entire buffer - ideally in one read, but if the size of
+		// the buffer is unknown, do multiple fixed size reads.
+		size_t bufSize = (mSize > 0 ? mSize : 4096);
+		std::stringstream::char_type* tempBuffer = (std::stringstream::char_type*)bs_alloc((UINT32)bufSize);
+
+		// Ensure read from begin of stream
+		seek(0);
+
+		std::stringstream result;
+		while (!eof())
+		{
+			size_t numReadBytes = read(tempBuffer, bufSize);
+			result.write(tempBuffer, numReadBytes);
+		}
+
+		free(tempBuffer);
+		std::string string = result.str();
+
+		UINT32 readBytes = (UINT32)string.size();
+		if (readBytes >= 4)
+		{
+			if (isUTF32LE((UINT8*)string.data()))
+			{
+				// Not supported
+			}
+			else if (isUTF32BE((UINT8*)string.data()))
+			{
+				// Not supported
+			}
+		}
+
+		if (readBytes >= 3)
+		{
+			if (isUTF8((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
+				typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
+
+				std::wstring_convert<wcharutf8> conversion("?");
+				return conversion.from_bytes(string).c_str();
+			}
+		}
+
+		if (readBytes >= 2)
+		{
+			if (isUTF16LE((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header | std::little_endian);
+				typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
+
+				std::wstring_convert<wcharutf16> conversion("?");
+				return conversion.from_bytes(string).c_str();
+			}
+			else if (isUTF16BE((UINT8*)string.data()))
+			{
+				const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
+				typedef std::codecvt_utf16<wchar_t, 1114111, convMode> wcharutf16;
+
+				std::wstring_convert<wcharutf16> conversion("?");
+				return conversion.from_bytes(string).c_str();
+			}
+		}
+
+		{
+			const std::codecvt_mode convMode = (std::codecvt_mode)(std::consume_header);
+			typedef std::codecvt_utf8<wchar_t, 1114111, convMode> wcharutf8;
+
+			std::wstring_convert<wcharutf8> conversion("?");
+			return conversion.from_bytes(string).c_str();
+		}
+	}
+
+    MemoryDataStream::MemoryDataStream(void* memory, size_t inSize)
+		: DataStream(READ | WRITE), mData(nullptr)
+    {
+        mData = mPos = static_cast<UINT8*>(memory);
+        mSize = inSize;
+        mEnd = mData + mSize;
+
+        assert(mEnd >= mPos);
+    }
+
+    MemoryDataStream::MemoryDataStream(DataStream& sourceStream)
+        : DataStream(READ | WRITE), mData(nullptr)
+    {
+        // Copy data from incoming stream
+        mSize = sourceStream.size();
+
+		mData = (UINT8*)bs_alloc((UINT32)mSize);
+		mPos = mData;
+		mEnd = mData + sourceStream.read(mData, mSize);
+
+        assert(mEnd >= mPos);
+    }
+
+    MemoryDataStream::MemoryDataStream(const DataStreamPtr& sourceStream)
+        :DataStream(READ | WRITE), mData(nullptr)
+    {
+        // Copy data from incoming stream
+        mSize = sourceStream->size();
+
+		mData = (UINT8*)bs_alloc((UINT32)mSize);
+		mPos = mData;
+		mEnd = mData + sourceStream->read(mData, mSize);
+
+        assert(mEnd >= mPos);
+    }
+
+    MemoryDataStream::~MemoryDataStream()
+    {
+        close();
+    }
+
+    size_t MemoryDataStream::read(void* buf, size_t count)
+    {
+        size_t cnt = count;
+
+        if (mPos + cnt > mEnd)
+            cnt = mEnd - mPos;
+        if (cnt == 0)
+            return 0;
+
+        assert (cnt <= count);
+
+        memcpy(buf, mPos, cnt);
+        mPos += cnt;
+
+        return cnt;
+    }
+
+	size_t MemoryDataStream::write(const void* buf, size_t count)
+	{
+		size_t written = 0;
+		if (isWriteable())
+		{
+			written = count;
+
+			if (mPos + written > mEnd)
+				written = mEnd - mPos;
+			if (written == 0)
+				return 0;
+
+			memcpy(mPos, buf, written);
+			mPos += written;
+		}
+
+		return written;
+	}
+
+    void MemoryDataStream::skip(size_t count)
+    {
+        size_t newpos = (size_t)( (mPos - mData) + count );
+        assert(mData + newpos <= mEnd);        
+
+        mPos = mData + newpos;
+    }
+
+    void MemoryDataStream::seek(size_t pos)
+    {
+        assert(mData + pos <= mEnd);
+        mPos = mData + pos;
+    }
+
+    size_t MemoryDataStream::tell() const
+	{
+		return mPos - mData;
+	}
+
+    bool MemoryDataStream::eof() const
+    {
+        return mPos >= mEnd;
+    }
+
+    void MemoryDataStream::close()    
+    {
+        if (mData != nullptr)
+        {
+            bs_free(mData);
+            mData = nullptr;
+        }
+    }
+
+    FileDataStream::FileDataStream(std::shared_ptr<std::ifstream> s, bool freeOnClose)
+        : DataStream(READ), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
+    {
+        mpInStream->seekg(0, std::ios_base::end);
+        mSize = (size_t)mpInStream->tellg();
+        mpInStream->seekg(0, std::ios_base::beg);
+
+		determineAccess();
+    }
+
+    FileDataStream::FileDataStream(std::shared_ptr<std::ifstream> s, size_t inSize, bool freeOnClose)
+        : DataStream(READ), mpInStream(s), mpFStreamRO(s), mpFStream(0), mFreeOnClose(freeOnClose)
+    {
+        mSize = inSize;
+
+		determineAccess();
+    }
+
+	FileDataStream::FileDataStream(std::shared_ptr<std::fstream> s, bool freeOnClose)
+		: DataStream(READ | WRITE), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
+	{
+		mpInStream->seekg(0, std::ios_base::end);
+		mSize = (size_t)mpInStream->tellg();
+		mpInStream->seekg(0, std::ios_base::beg);
+
+		determineAccess();
+	}
+
+	FileDataStream::FileDataStream(std::shared_ptr<std::fstream> s, size_t inSize, bool freeOnClose)
+		: DataStream(READ | WRITE), mpInStream(s), mpFStreamRO(0), mpFStream(s), mFreeOnClose(freeOnClose)
+	{
+		mSize = inSize;
+
+		determineAccess();
+	}
+
+	void FileDataStream::determineAccess()
+	{
+		mAccess = 0;
+
+		if (mpInStream)
+			mAccess |= READ;
+
+		if (mpFStream)
+			mAccess |= WRITE;
+	}
+
+    FileDataStream::~FileDataStream()
+    {
+        close();
+    }
+
+    size_t FileDataStream::read(void* buf, size_t count)
+    {
+		mpInStream->read(static_cast<char*>(buf), static_cast<std::streamsize>(count));
+
+        return (size_t)mpInStream->gcount();
+    }
+
+	size_t FileDataStream::write(const void* buf, size_t count)
+	{
+		size_t written = 0;
+		if (isWriteable() && mpFStream)
+		{
+			mpFStream->write(static_cast<const char*>(buf), static_cast<std::streamsize>(count));
+			written = count;
+		}
+
+		return written;
+	}
+    void FileDataStream::skip(size_t count)
+    {	
+		mpInStream->clear(); // Clear fail status in case eof was set
+		mpInStream->seekg(static_cast<std::ifstream::pos_type>(count), std::ios::cur);
+    }
+
+    void FileDataStream::seek(size_t pos)
+    {
+		mpInStream->clear(); // Clear fail status in case eof was set
+		mpInStream->seekg(static_cast<std::streamoff>(pos), std::ios::beg);
+	}
+
+    size_t FileDataStream::tell() const
+	{
+		mpInStream->clear(); // Clear fail status in case eof was set
+
+		return (size_t)mpInStream->tellg();
+	}
+
+    bool FileDataStream::eof() const
+    {
+        return mpInStream->eof();
+    }
+
+    void FileDataStream::close()
+    {
+        if (mpInStream)
+        {
+			if (mpFStreamRO)
+	            mpFStreamRO->close();
+
+			if (mpFStream)
+			{
+				mpFStream->flush();
+				mpFStream->close();
+			}
+
+            if (mFreeOnClose)
+            {
+				mpInStream = nullptr;
+				mpFStreamRO = nullptr; 
+				mpFStream = nullptr; 
+            }
+        }
+    }
+}

+ 557 - 566
Source/BansheeUtility/Source/Win32/BsWin32CrashHandler.cpp

@@ -1,567 +1,558 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPrerequisitesUtil.h"
-#include "BsDebug.h"
-#include "BsDynLib.h"
-#include "BsFileSystem.h"
-#include "windows.h"
-#include <psapi.h>
-
-// Disable warning in VS2015 that's not under my control
-#pragma warning(disable : 4091)
-#include "DbgHelp.h"
-#pragma warning(default : 4091)
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Returns the raw stack trace using the provided context. Raw stack trace contains only
-	 * 			function addresses.
-	 * 			
-	 * @param	context		Processor context from which to start the stack trace. 
-	 * @param	stackTrace	Output parameter that will contain the function addresses. First address is the deepest
-	 * 						called function and following address is its caller and so on.
-	 * 						
-	 * @returns	Number of functions in the call stack.
-	 */
-	UINT32 win32_getRawStackTrace(CONTEXT context, UINT64 stackTrace[BS_MAX_STACKTRACE_DEPTH])
-	{
-		HANDLE hProcess = GetCurrentProcess();
-		HANDLE hThread = GetCurrentThread();
-		UINT32 machineType;
-
-		STACKFRAME64 stackFrame;
-		memset(&stackFrame, 0, sizeof(stackFrame));
-
-		stackFrame.AddrPC.Mode = AddrModeFlat;
-		stackFrame.AddrStack.Mode = AddrModeFlat;
-		stackFrame.AddrFrame.Mode = AddrModeFlat;
-
-#if BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64
-		stackFrame.AddrPC.Offset = context.Rip;
-		stackFrame.AddrStack.Offset = context.Rsp;
-		stackFrame.AddrFrame.Offset = context.Rbp;
-
-		machineType = IMAGE_FILE_MACHINE_AMD64;
-#else
-		stackFrame.AddrPC.Offset = context.Eip;
-		stackFrame.AddrStack.Offset = context.Esp;
-		stackFrame.AddrFrame.Offset = context.Ebp;
-
-		machineType = IMAGE_FILE_MACHINE_I386;
-#endif
-
-		UINT32 numEntries = 0;
-		while (true)
-		{
-			if (!StackWalk64(machineType, hProcess, hThread, &stackFrame, &context, nullptr,
-				SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
-			{
-				break;
-			}
-
-			if (numEntries < BS_MAX_STACKTRACE_DEPTH)
-				stackTrace[numEntries] = stackFrame.AddrPC.Offset;
-
-			numEntries++;
-
-			if (stackFrame.AddrPC.Offset == 0 || stackFrame.AddrFrame.Offset == 0)
-				break;
-		}
-
-		return numEntries;
-	}
-
-	/**
-	 * @brief	Returns a string containing a stack trace using the provided context. If function can be found in the symbol
-	 * 			table its readable name will be present in the stack trace, otherwise just its address.
-	 * 			
-	 * @param	context		Processor context from which to start the stack trace. 
-	 * @param	skip		Number of bottom-most call stack entries to skip.
-	 * 						
-	 * @returns	String containing the call stack with each function on its own line.
-	 */
-	String win32_getStackTrace(CONTEXT context, UINT32 skip = 0)
-	{
-		UINT64 rawStackTrace[BS_MAX_STACKTRACE_DEPTH];
-		UINT32 numEntries = win32_getRawStackTrace(context, rawStackTrace);
-
-		numEntries = std::min((UINT32)BS_MAX_STACKTRACE_DEPTH, numEntries);
-
-		UINT32 bufferSize = sizeof(PIMAGEHLP_SYMBOL64) + BS_MAX_STACKTRACE_NAME_BYTES;
-		UINT8* buffer = (UINT8*)bs_alloc(bufferSize);
-
-		PIMAGEHLP_SYMBOL64 symbol = (PIMAGEHLP_SYMBOL64)buffer;
-		symbol->SizeOfStruct = bufferSize;
-		symbol->MaxNameLength = BS_MAX_STACKTRACE_NAME_BYTES;
-
-		HANDLE hProcess = GetCurrentProcess();
-
-		StringStream outputStream;
-		for (UINT32 i = skip; i < numEntries; i++)
-		{
-			if (i > skip)
-				outputStream << std::endl;
-
-			DWORD64 funcAddress = rawStackTrace[i];
-
-			// Output function name
-			DWORD64 dummy;
-			if (SymGetSymFromAddr64(hProcess, funcAddress, &dummy, symbol))
-				outputStream << StringUtil::format("{0}() - ", symbol->Name);
-
-			// Output file name and line
-			IMAGEHLP_LINE64	lineData;
-			lineData.SizeOfStruct = sizeof(lineData);
-
-			String addressString = toString(funcAddress, 0, ' ', std::ios::hex);
-
-			DWORD column;
-			if (SymGetLineFromAddr64(hProcess, funcAddress, &column, &lineData))
-			{
-				Path filePath = lineData.FileName;
-
-				outputStream << StringUtil::format("0x{0} File[{1}:{2} ({3})]", addressString, 
-					filePath.getFilename(), lineData.LineNumber, column);
-			}
-			else
-			{
-				outputStream << StringUtil::format("0x{0}", addressString);
-			}
-
-			// Output module name
-			IMAGEHLP_MODULE64 moduleData;
-			moduleData.SizeOfStruct = sizeof(moduleData);
-
-			if (SymGetModuleInfo64(hProcess, funcAddress, &moduleData))
-			{
-				Path filePath = moduleData.ImageName;
-
-				outputStream << StringUtil::format(" Module[{0}]", filePath.getFilename());
-			}
-		}
-
-		bs_free(buffer);
-
-		return outputStream.str();
-	}
-
-	typedef bool(WINAPI *EnumProcessModulesType)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
-	typedef DWORD(WINAPI *GetModuleBaseNameType)(HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize);
-	typedef DWORD(WINAPI *GetModuleFileNameExType)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize);
-	typedef bool(WINAPI *GetModuleInformationType)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
-
-	static DynLib* gPSAPILib = nullptr;
-
-	static EnumProcessModulesType gEnumProcessModules;
-	static GetModuleBaseNameType gGetModuleBaseName;
-	static GetModuleFileNameExType gGetModuleFileNameEx;
-	static GetModuleInformationType gGetModuleInformation;
-
-	/**
-	 * @brief	Dynamically load the PSAPI.dll and the required symbols, if not already loaded.
-	 */
-	void win32_initPSAPI()
-	{
-		if (gPSAPILib != nullptr)
-			return;
-
-		gPSAPILib = bs_new<DynLib>("PSAPI.dll");
-		gEnumProcessModules = (EnumProcessModulesType)gPSAPILib->getSymbol("EnumProcessModules");
-		gGetModuleBaseName = (GetModuleBaseNameType)gPSAPILib->getSymbol("GetModuleFileNameExA");
-		gGetModuleFileNameEx = (GetModuleFileNameExType)gPSAPILib->getSymbol("GetModuleBaseNameA");
-		gGetModuleInformation = (GetModuleInformationType)gPSAPILib->getSymbol("GetModuleInformation");
-	}
-
-	/**
-	 * @brief	Unloads the PSAPI.dll if is loaded.
-	 */
-	void win32_unloadPSAPI()
-	{
-		if (gPSAPILib == nullptr)
-			return;
-
-		gPSAPILib->unload();
-		bs_delete(gPSAPILib);
-		gPSAPILib = nullptr;
-	}
-
-	static bool gSymbolsLoaded = false;
-
-	/**
-	 * @brief	Loads symbols for all modules in the current process. Loaded symbols allow the stack walker to retrieve
-	 * 			human readable method, file, module names and other information.
-	 */
-	void win32_loadSymbols()
-	{
-		if (gSymbolsLoaded)
-			return;
-
-		HANDLE hProcess = GetCurrentProcess();
-		UINT32 options = SymGetOptions();
-
-		options |= SYMOPT_LOAD_LINES;
-		options |= SYMOPT_EXACT_SYMBOLS;
-		options |= SYMOPT_UNDNAME;
-		options |= SYMOPT_FAIL_CRITICAL_ERRORS;
-		options |= SYMOPT_NO_PROMPTS;
-
-		SymSetOptions(options);
-		if(!SymInitialize(hProcess, nullptr, false))
-		{
-			LOGERR("SymInitialize failed. Error code: " + toString((UINT32)GetLastError()));
-			return;
-		}
-
-		DWORD bufferSize;
-		gEnumProcessModules(hProcess, nullptr, 0, &bufferSize);
-
-		HMODULE* modules = (HMODULE*)bs_alloc(bufferSize);
-		gEnumProcessModules(hProcess, modules, bufferSize, &bufferSize);
-
-		UINT32 numModules = bufferSize / sizeof(HMODULE);
-		for (UINT32 i = 0; i < numModules; i++)
-		{
-			MODULEINFO moduleInfo;
-
-			char moduleName[BS_MAX_STACKTRACE_NAME_BYTES];
-			char imageName[BS_MAX_STACKTRACE_NAME_BYTES];
-
-			gGetModuleInformation(hProcess, modules[i], &moduleInfo, sizeof(moduleInfo));
-			gGetModuleFileNameEx(hProcess, modules[i], imageName, BS_MAX_STACKTRACE_NAME_BYTES);
-			gGetModuleBaseName(hProcess, modules[i], moduleName, BS_MAX_STACKTRACE_NAME_BYTES);
-
-			char pdbSearchPath[BS_MAX_STACKTRACE_NAME_BYTES];
-			char* fileName = nullptr;
-			GetFullPathNameA(moduleName, BS_MAX_STACKTRACE_NAME_BYTES, pdbSearchPath, &fileName);
-			*fileName = '\0';
-
-			SymSetSearchPath(GetCurrentProcess(), pdbSearchPath);
-
-			DWORD64 moduleAddress = SymLoadModule64(hProcess, modules[i], imageName, moduleName, (DWORD64)moduleInfo.lpBaseOfDll,
-				(DWORD)moduleInfo.SizeOfImage);
-
-			if (moduleAddress != 0)
-			{
-				IMAGEHLP_MODULE64 imageInfo;
-				memset(&imageInfo, 0, sizeof(imageInfo));
-				imageInfo.SizeOfStruct = sizeof(imageInfo);
-
-				if(!SymGetModuleInfo64(GetCurrentProcess(), moduleAddress, &imageInfo))
-				{
-					LOGWRN("Failed retrieving module info for module: " + String(moduleName) + ". Error code: " + toString((UINT32)GetLastError()));
-				}
-				else
-				{
-					// Disabled because too much spam in the log, enable as needed
-#if 0
-					if (imageInfo.SymType == SymNone)
-						LOGWRN("Failed loading symbols for module: " + String(moduleName));
-#endif
-				}
-			}
-			else
-			{
-				LOGWRN("Failed loading module " + String(moduleName) + ".Error code: " + toString((UINT32)GetLastError()) +
-					". Search path: " + String(pdbSearchPath) + ". Image name: " + String(imageName));
-			}
-		}
-
-		bs_free(modules);
-		gSymbolsLoaded = true;
-	}
-
-	/**
-	 * @brief	Converts an exception record into a human readable error message.
-	 */
-	String win32_getExceptionMessage(EXCEPTION_RECORD* record)
-	{
-		String exceptionAddress = toString((UINT64)record->ExceptionAddress, 0, ' ', std::ios::hex);
-
-		String format;
-		switch (record->ExceptionCode)
-		{
-		case EXCEPTION_ACCESS_VIOLATION:
-			{
-				DWORD_PTR violatedAddress = 0;
-				if (record->NumberParameters == 2)
-				{
-					if (record->ExceptionInformation[0] == 0)
-						format = "Unhandled exception at 0x{0}. Access violation reading 0x{1}.";
-					else if (record->ExceptionInformation[0] == 8)
-						format = "Unhandled exception at 0x{0}. Access violation DEP 0x{1}.";
-					else
-						format = "Unhandled exception at 0x{0}. Access violation writing 0x{1}.";
-
-					violatedAddress = record->ExceptionInformation[1];
-				}
-				else
-					format = "Unhandled exception at 0x{0}. Access violation.";
-
-				String violatedAddressStr = toString((UINT64)violatedAddress, 0, ' ', std::ios::hex);
-				return StringUtil::format(format, exceptionAddress, violatedAddressStr);
-			}
-		case EXCEPTION_IN_PAGE_ERROR:
-		{
-			DWORD_PTR violatedAddress = 0;
-			DWORD_PTR code = 0;
-			if (record->NumberParameters == 3)
-			{
-				if (record->ExceptionInformation[0] == 0)
-					format = "Unhandled exception at 0x{0}. Page fault reading 0x{1} with code 0x{2}.";
-				else if (record->ExceptionInformation[0] == 8)
-					format = "Unhandled exception at 0x{0}. Page fault DEP 0x{1} with code 0x{2}.";
-				else
-					format = "Unhandled exception at 0x{0}. Page fault writing 0x{1} with code 0x{2}.";
-
-				violatedAddress = record->ExceptionInformation[1];
-				code = record->ExceptionInformation[3];
-			}
-			else
-				format = "Unhandled exception at 0x{0}. Page fault.";
-
-			String violatedAddressStr = toString((UINT64)violatedAddress, 0, ' ', std::ios::hex);
-			String codeStr = toString((UINT64)code, 0, ' ', std::ios::hex);
-			return StringUtil::format(format, exceptionAddress, violatedAddressStr, codeStr);
-		}
-		case STATUS_ARRAY_BOUNDS_EXCEEDED:
-		{
-			format = "Unhandled exception at 0x{0}. Attempting to access an out of range array element.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_DATATYPE_MISALIGNMENT:
-		{
-			format = "Unhandled exception at 0x{0}. Attempting to access missaligned data.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_FLT_DENORMAL_OPERAND:
-		{
-			format = "Unhandled exception at 0x{0}. Floating point operand too small.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_FLT_DIVIDE_BY_ZERO:
-		{
-			format = "Unhandled exception at 0x{0}. Floating point operation attempted to divide by zero.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_FLT_INVALID_OPERATION:
-		{
-			format = "Unhandled exception at 0x{0}. Floating point invalid operation.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_FLT_OVERFLOW:
-		{
-			format = "Unhandled exception at 0x{0}. Floating point overflow.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_FLT_UNDERFLOW:
-		{
-			format = "Unhandled exception at 0x{0}. Floating point underflow.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_FLT_STACK_CHECK:
-		{
-			format = "Unhandled exception at 0x{0}. Floating point stack overflow/underflow.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_ILLEGAL_INSTRUCTION:
-		{
-			format = "Unhandled exception at 0x{0}. Attempting to execute an illegal instruction.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_PRIV_INSTRUCTION:
-		{
-			format = "Unhandled exception at 0x{0}. Attempting to execute a private instruction.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_INT_DIVIDE_BY_ZERO:
-		{
-			format = "Unhandled exception at 0x{0}. Integer operation attempted to divide by zero.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_INT_OVERFLOW:
-		{
-			format = "Unhandled exception at 0x{0}. Integer operation result has overflown.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		case EXCEPTION_STACK_OVERFLOW:
-		{
-			format = "Unhandled exception at 0x{0}. Stack overflow.";
-			return StringUtil::format(format, exceptionAddress);
-		}
-		default:
-		{
-			format = "Unhandled exception at 0x{0}. Code 0x{1}.";
-
-			String exceptionCode = toString((UINT32)record->ExceptionCode, 0, ' ', std::ios::hex);
-			return StringUtil::format(format, exceptionAddress, exceptionCode);
-		}
-		}
-	}
-
-	struct MiniDumpParams
-	{
-		Path filePath;
-		EXCEPTION_POINTERS* exceptionData;
-	};
-
-	DWORD CALLBACK win32_writeMiniDumpWorker(void* data)
-	{
-		MiniDumpParams* params = (MiniDumpParams*)data;
-
-		HANDLE hFile = CreateFileW(params->filePath.toWString().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
-			FILE_ATTRIBUTE_NORMAL, nullptr);
-
-		if (hFile != INVALID_HANDLE_VALUE)
-		{
-			MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
-
-			DumpExceptionInfo.ThreadId = GetCurrentThreadId();
-			DumpExceptionInfo.ExceptionPointers = params->exceptionData;
-			DumpExceptionInfo.ClientPointers = false;
-
-			MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal,
-				&DumpExceptionInfo, nullptr, nullptr);
-			CloseHandle(hFile);
-		}
-
-		return 0;
-	}
-
-	void win32_writeMiniDump(const Path& filePath, EXCEPTION_POINTERS* exceptionData)
-	{
-		MiniDumpParams param = { filePath, exceptionData };
-
-		// Write minidump on a second thread in order to preserve the current thread's call stack
-		DWORD threadId = 0;
-		HANDLE hThread = CreateThread(nullptr, 0, &win32_writeMiniDumpWorker, &param, 0, &threadId);
-
-		WaitForSingleObject(hThread, INFINITE);
-		CloseHandle(hThread);
-	}
-
-	static const wchar_t* gMiniDumpName = L"minidump.dmp";
-	const wchar_t* CrashHandler::CrashReportFolder = L"CrashReports/{0}/";
-	const wchar_t* CrashHandler::CrashLogName = L"log.html";
-
-	struct CrashHandler::Data
-	{
-		Mutex mutex;
-	};
-
-	CrashHandler::CrashHandler()
-	{
-		m = bs_new<Data>();
-	}
-
-	CrashHandler::~CrashHandler()
-	{
-		win32_unloadPSAPI();
-
-		bs_delete(m);
-	}
-
-	void CrashHandler::reportCrash(const String& type, const String& description, const String& function,
-		const String& file, UINT32 line) const
-	{
-		// Win32 debug methods are not thread safe
-		Lock<>(m->mutex);
-
-		String stackTrace = getStackTrace();
-
-		StringStream errorMessageStream;
-		errorMessageStream << "Fatal error occurred and the program has to terminate!" << std::endl;
-		errorMessageStream << "\t\t" << type << " - " << description << std::endl;
-		errorMessageStream << "\t\t in " << function << " [" << file << ":" << line << "]" << std::endl;
-		errorMessageStream << std::endl;
-		errorMessageStream << "Stack trace: " << std::endl;
-		errorMessageStream << stackTrace;
-
-		String errorMessage = errorMessageStream.str();
-		gDebug().logError(errorMessage);
-
-		Path crashFolder = getCrashFolder();
-		FileSystem::createDir(crashFolder);
-
-		gDebug().saveLog(crashFolder + WString(CrashLogName));
-		win32_writeMiniDump(crashFolder + WString(gMiniDumpName), nullptr);
-
-		WString simpleErrorMessage = L"Fatal error occurred and the program has to terminate! " \
-			L"\n\nFor more information check the crash report located at:\n " + crashFolder.toWString();
-
-		MessageBoxW(nullptr, simpleErrorMessage.c_str(), L"Banshee fatal error!", MB_OK);
-
-		// Note: Potentially also log Windows Error Report and/or send crash data to server
-	}
-
-	int CrashHandler::reportCrash(void* exceptionDataPtr) const
-	{
-		EXCEPTION_POINTERS* exceptionData = (EXCEPTION_POINTERS*)exceptionDataPtr;
-
-		// Win32 debug methods are not thread safe
-		Lock<>(m->mutex);
-
-		win32_initPSAPI();
-		win32_loadSymbols();
-		String stackTrace = win32_getStackTrace(*exceptionData->ContextRecord, 0);
-
-		StringStream errorMessageStream;
-		errorMessageStream << "Fatal error occurred and the program has to terminate!" << std::endl;
-		errorMessageStream << "\t\t" << win32_getExceptionMessage(exceptionData->ExceptionRecord) << std::endl;;
-		errorMessageStream << std::endl;
-		errorMessageStream << "Stack trace: " << std::endl;
-		errorMessageStream << stackTrace;
-
-		String errorMessage = errorMessageStream.str();
-		gDebug().logError(errorMessage);
-
-		Path crashFolder = getCrashFolder();
-		FileSystem::createDir(crashFolder);
-
-		gDebug().saveLog(crashFolder + WString(CrashLogName));
-		win32_writeMiniDump(crashFolder + WString(gMiniDumpName), exceptionData);
-
-		WString simpleErrorMessage = L"Fatal error occurred and the program has to terminate! " \
-			L"\n\nFor more information check the crash report located at:\n" + crashFolder.toWString();
-
-		MessageBoxW(nullptr, simpleErrorMessage.c_str(), L"Banshee fatal error!", MB_OK);
-
-		// Note: Potentially also log Windows Error Report and/or send crash data to server
-
-		return EXCEPTION_EXECUTE_HANDLER;
-	}
-
-	Path CrashHandler::getCrashFolder() const
-	{
-		SYSTEMTIME systemTime;
-		GetLocalTime(&systemTime);
-
-		WString timeStamp = L"{0}{1}{2}_{3}{4}";
-		WString strYear = toWString(systemTime.wYear, 4, '0');
-		WString strMonth = toWString(systemTime.wMonth, 2, '0');
-		WString strDay = toWString(systemTime.wDay, 2, '0');
-		WString strHour = toWString(systemTime.wHour, 2, '0');
-		WString strMinute = toWString(systemTime.wMinute, 2, '0');
-
-		timeStamp = StringUtil::format(timeStamp, strYear, strMonth, strDay, strHour, strMinute);
-
-		WString folderName = StringUtil::format(CrashReportFolder, timeStamp);
-
-		return FileSystem::getWorkingDirectoryPath() + folderName;
-	}
-
-	String CrashHandler::getStackTrace()
-	{
-		CONTEXT context;
-		RtlCaptureContext(&context);
-
-		win32_initPSAPI();
-		win32_loadSymbols();
-		return win32_getStackTrace(context, 2);
-	}
-
-	CrashHandler& gCrashHandler()
-	{
-		return CrashHandler::instance();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPrerequisitesUtil.h"
+#include "BsDebug.h"
+#include "BsDynLib.h"
+#include "BsFileSystem.h"
+#include "windows.h"
+#include <psapi.h>
+
+// Disable warning in VS2015 that's not under my control
+#pragma warning(disable : 4091)
+#include "DbgHelp.h"
+#pragma warning(default : 4091)
+
+namespace BansheeEngine
+{
+	/**
+	 * Returns the raw stack trace using the provided context. Raw stack trace contains only function addresses.
+	 * 			
+	 * @param[in]	context		Processor context from which to start the stack trace. 
+	 * @param[in]	stackTrace	Output parameter that will contain the function addresses. First address is the deepest
+	 * 							called function and following address is its caller and so on.
+	 * @return					Number of functions in the call stack.
+	 */
+	UINT32 win32_getRawStackTrace(CONTEXT context, UINT64 stackTrace[BS_MAX_STACKTRACE_DEPTH])
+	{
+		HANDLE hProcess = GetCurrentProcess();
+		HANDLE hThread = GetCurrentThread();
+		UINT32 machineType;
+
+		STACKFRAME64 stackFrame;
+		memset(&stackFrame, 0, sizeof(stackFrame));
+
+		stackFrame.AddrPC.Mode = AddrModeFlat;
+		stackFrame.AddrStack.Mode = AddrModeFlat;
+		stackFrame.AddrFrame.Mode = AddrModeFlat;
+
+#if BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64
+		stackFrame.AddrPC.Offset = context.Rip;
+		stackFrame.AddrStack.Offset = context.Rsp;
+		stackFrame.AddrFrame.Offset = context.Rbp;
+
+		machineType = IMAGE_FILE_MACHINE_AMD64;
+#else
+		stackFrame.AddrPC.Offset = context.Eip;
+		stackFrame.AddrStack.Offset = context.Esp;
+		stackFrame.AddrFrame.Offset = context.Ebp;
+
+		machineType = IMAGE_FILE_MACHINE_I386;
+#endif
+
+		UINT32 numEntries = 0;
+		while (true)
+		{
+			if (!StackWalk64(machineType, hProcess, hThread, &stackFrame, &context, nullptr,
+				SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
+			{
+				break;
+			}
+
+			if (numEntries < BS_MAX_STACKTRACE_DEPTH)
+				stackTrace[numEntries] = stackFrame.AddrPC.Offset;
+
+			numEntries++;
+
+			if (stackFrame.AddrPC.Offset == 0 || stackFrame.AddrFrame.Offset == 0)
+				break;
+		}
+
+		return numEntries;
+	}
+
+	/**
+	 * Returns a string containing a stack trace using the provided context. If function can be found in the symbol table
+	 * its readable name will be present in the stack trace, otherwise just its address.
+	 * 			
+	 * @param[in]	context		Processor context from which to start the stack trace. 
+	 * @param[in]	skip		Number of bottom-most call stack entries to skip.
+	 * @return					String containing the call stack with each function on its own line.
+	 */
+	String win32_getStackTrace(CONTEXT context, UINT32 skip = 0)
+	{
+		UINT64 rawStackTrace[BS_MAX_STACKTRACE_DEPTH];
+		UINT32 numEntries = win32_getRawStackTrace(context, rawStackTrace);
+
+		numEntries = std::min((UINT32)BS_MAX_STACKTRACE_DEPTH, numEntries);
+
+		UINT32 bufferSize = sizeof(PIMAGEHLP_SYMBOL64) + BS_MAX_STACKTRACE_NAME_BYTES;
+		UINT8* buffer = (UINT8*)bs_alloc(bufferSize);
+
+		PIMAGEHLP_SYMBOL64 symbol = (PIMAGEHLP_SYMBOL64)buffer;
+		symbol->SizeOfStruct = bufferSize;
+		symbol->MaxNameLength = BS_MAX_STACKTRACE_NAME_BYTES;
+
+		HANDLE hProcess = GetCurrentProcess();
+
+		StringStream outputStream;
+		for (UINT32 i = skip; i < numEntries; i++)
+		{
+			if (i > skip)
+				outputStream << std::endl;
+
+			DWORD64 funcAddress = rawStackTrace[i];
+
+			// Output function name
+			DWORD64 dummy;
+			if (SymGetSymFromAddr64(hProcess, funcAddress, &dummy, symbol))
+				outputStream << StringUtil::format("{0}() - ", symbol->Name);
+
+			// Output file name and line
+			IMAGEHLP_LINE64	lineData;
+			lineData.SizeOfStruct = sizeof(lineData);
+
+			String addressString = toString(funcAddress, 0, ' ', std::ios::hex);
+
+			DWORD column;
+			if (SymGetLineFromAddr64(hProcess, funcAddress, &column, &lineData))
+			{
+				Path filePath = lineData.FileName;
+
+				outputStream << StringUtil::format("0x{0} File[{1}:{2} ({3})]", addressString, 
+					filePath.getFilename(), lineData.LineNumber, column);
+			}
+			else
+			{
+				outputStream << StringUtil::format("0x{0}", addressString);
+			}
+
+			// Output module name
+			IMAGEHLP_MODULE64 moduleData;
+			moduleData.SizeOfStruct = sizeof(moduleData);
+
+			if (SymGetModuleInfo64(hProcess, funcAddress, &moduleData))
+			{
+				Path filePath = moduleData.ImageName;
+
+				outputStream << StringUtil::format(" Module[{0}]", filePath.getFilename());
+			}
+		}
+
+		bs_free(buffer);
+
+		return outputStream.str();
+	}
+
+	typedef bool(WINAPI *EnumProcessModulesType)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
+	typedef DWORD(WINAPI *GetModuleBaseNameType)(HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize);
+	typedef DWORD(WINAPI *GetModuleFileNameExType)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize);
+	typedef bool(WINAPI *GetModuleInformationType)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
+
+	static DynLib* gPSAPILib = nullptr;
+
+	static EnumProcessModulesType gEnumProcessModules;
+	static GetModuleBaseNameType gGetModuleBaseName;
+	static GetModuleFileNameExType gGetModuleFileNameEx;
+	static GetModuleInformationType gGetModuleInformation;
+
+	/**	Dynamically load the PSAPI.dll and the required symbols, if not already loaded. */
+	void win32_initPSAPI()
+	{
+		if (gPSAPILib != nullptr)
+			return;
+
+		gPSAPILib = bs_new<DynLib>("PSAPI.dll");
+		gEnumProcessModules = (EnumProcessModulesType)gPSAPILib->getSymbol("EnumProcessModules");
+		gGetModuleBaseName = (GetModuleBaseNameType)gPSAPILib->getSymbol("GetModuleFileNameExA");
+		gGetModuleFileNameEx = (GetModuleFileNameExType)gPSAPILib->getSymbol("GetModuleBaseNameA");
+		gGetModuleInformation = (GetModuleInformationType)gPSAPILib->getSymbol("GetModuleInformation");
+	}
+
+	/**	Unloads the PSAPI.dll if is loaded. */
+	void win32_unloadPSAPI()
+	{
+		if (gPSAPILib == nullptr)
+			return;
+
+		gPSAPILib->unload();
+		bs_delete(gPSAPILib);
+		gPSAPILib = nullptr;
+	}
+
+	static bool gSymbolsLoaded = false;
+
+	/**
+	 * Loads symbols for all modules in the current process. Loaded symbols allow the stack walker to retrieve human
+	 * readable method, file, module names and other information.
+	 */
+	void win32_loadSymbols()
+	{
+		if (gSymbolsLoaded)
+			return;
+
+		HANDLE hProcess = GetCurrentProcess();
+		UINT32 options = SymGetOptions();
+
+		options |= SYMOPT_LOAD_LINES;
+		options |= SYMOPT_EXACT_SYMBOLS;
+		options |= SYMOPT_UNDNAME;
+		options |= SYMOPT_FAIL_CRITICAL_ERRORS;
+		options |= SYMOPT_NO_PROMPTS;
+
+		SymSetOptions(options);
+		if(!SymInitialize(hProcess, nullptr, false))
+		{
+			LOGERR("SymInitialize failed. Error code: " + toString((UINT32)GetLastError()));
+			return;
+		}
+
+		DWORD bufferSize;
+		gEnumProcessModules(hProcess, nullptr, 0, &bufferSize);
+
+		HMODULE* modules = (HMODULE*)bs_alloc(bufferSize);
+		gEnumProcessModules(hProcess, modules, bufferSize, &bufferSize);
+
+		UINT32 numModules = bufferSize / sizeof(HMODULE);
+		for (UINT32 i = 0; i < numModules; i++)
+		{
+			MODULEINFO moduleInfo;
+
+			char moduleName[BS_MAX_STACKTRACE_NAME_BYTES];
+			char imageName[BS_MAX_STACKTRACE_NAME_BYTES];
+
+			gGetModuleInformation(hProcess, modules[i], &moduleInfo, sizeof(moduleInfo));
+			gGetModuleFileNameEx(hProcess, modules[i], imageName, BS_MAX_STACKTRACE_NAME_BYTES);
+			gGetModuleBaseName(hProcess, modules[i], moduleName, BS_MAX_STACKTRACE_NAME_BYTES);
+
+			char pdbSearchPath[BS_MAX_STACKTRACE_NAME_BYTES];
+			char* fileName = nullptr;
+			GetFullPathNameA(moduleName, BS_MAX_STACKTRACE_NAME_BYTES, pdbSearchPath, &fileName);
+			*fileName = '\0';
+
+			SymSetSearchPath(GetCurrentProcess(), pdbSearchPath);
+
+			DWORD64 moduleAddress = SymLoadModule64(hProcess, modules[i], imageName, moduleName, (DWORD64)moduleInfo.lpBaseOfDll,
+				(DWORD)moduleInfo.SizeOfImage);
+
+			if (moduleAddress != 0)
+			{
+				IMAGEHLP_MODULE64 imageInfo;
+				memset(&imageInfo, 0, sizeof(imageInfo));
+				imageInfo.SizeOfStruct = sizeof(imageInfo);
+
+				if(!SymGetModuleInfo64(GetCurrentProcess(), moduleAddress, &imageInfo))
+				{
+					LOGWRN("Failed retrieving module info for module: " + String(moduleName) + ". Error code: " + toString((UINT32)GetLastError()));
+				}
+				else
+				{
+					// Disabled because too much spam in the log, enable as needed
+#if 0
+					if (imageInfo.SymType == SymNone)
+						LOGWRN("Failed loading symbols for module: " + String(moduleName));
+#endif
+				}
+			}
+			else
+			{
+				LOGWRN("Failed loading module " + String(moduleName) + ".Error code: " + toString((UINT32)GetLastError()) +
+					". Search path: " + String(pdbSearchPath) + ". Image name: " + String(imageName));
+			}
+		}
+
+		bs_free(modules);
+		gSymbolsLoaded = true;
+	}
+
+	/**	Converts an exception record into a human readable error message. */
+	String win32_getExceptionMessage(EXCEPTION_RECORD* record)
+	{
+		String exceptionAddress = toString((UINT64)record->ExceptionAddress, 0, ' ', std::ios::hex);
+
+		String format;
+		switch (record->ExceptionCode)
+		{
+		case EXCEPTION_ACCESS_VIOLATION:
+			{
+				DWORD_PTR violatedAddress = 0;
+				if (record->NumberParameters == 2)
+				{
+					if (record->ExceptionInformation[0] == 0)
+						format = "Unhandled exception at 0x{0}. Access violation reading 0x{1}.";
+					else if (record->ExceptionInformation[0] == 8)
+						format = "Unhandled exception at 0x{0}. Access violation DEP 0x{1}.";
+					else
+						format = "Unhandled exception at 0x{0}. Access violation writing 0x{1}.";
+
+					violatedAddress = record->ExceptionInformation[1];
+				}
+				else
+					format = "Unhandled exception at 0x{0}. Access violation.";
+
+				String violatedAddressStr = toString((UINT64)violatedAddress, 0, ' ', std::ios::hex);
+				return StringUtil::format(format, exceptionAddress, violatedAddressStr);
+			}
+		case EXCEPTION_IN_PAGE_ERROR:
+		{
+			DWORD_PTR violatedAddress = 0;
+			DWORD_PTR code = 0;
+			if (record->NumberParameters == 3)
+			{
+				if (record->ExceptionInformation[0] == 0)
+					format = "Unhandled exception at 0x{0}. Page fault reading 0x{1} with code 0x{2}.";
+				else if (record->ExceptionInformation[0] == 8)
+					format = "Unhandled exception at 0x{0}. Page fault DEP 0x{1} with code 0x{2}.";
+				else
+					format = "Unhandled exception at 0x{0}. Page fault writing 0x{1} with code 0x{2}.";
+
+				violatedAddress = record->ExceptionInformation[1];
+				code = record->ExceptionInformation[3];
+			}
+			else
+				format = "Unhandled exception at 0x{0}. Page fault.";
+
+			String violatedAddressStr = toString((UINT64)violatedAddress, 0, ' ', std::ios::hex);
+			String codeStr = toString((UINT64)code, 0, ' ', std::ios::hex);
+			return StringUtil::format(format, exceptionAddress, violatedAddressStr, codeStr);
+		}
+		case STATUS_ARRAY_BOUNDS_EXCEEDED:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to access an out of range array element.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_DATATYPE_MISALIGNMENT:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to access missaligned data.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_DENORMAL_OPERAND:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point operand too small.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point operation attempted to divide by zero.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_INVALID_OPERATION:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point invalid operation.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_OVERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point overflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_UNDERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point underflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_FLT_STACK_CHECK:
+		{
+			format = "Unhandled exception at 0x{0}. Floating point stack overflow/underflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_ILLEGAL_INSTRUCTION:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to execute an illegal instruction.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_PRIV_INSTRUCTION:
+		{
+			format = "Unhandled exception at 0x{0}. Attempting to execute a private instruction.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_INT_DIVIDE_BY_ZERO:
+		{
+			format = "Unhandled exception at 0x{0}. Integer operation attempted to divide by zero.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_INT_OVERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Integer operation result has overflown.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		case EXCEPTION_STACK_OVERFLOW:
+		{
+			format = "Unhandled exception at 0x{0}. Stack overflow.";
+			return StringUtil::format(format, exceptionAddress);
+		}
+		default:
+		{
+			format = "Unhandled exception at 0x{0}. Code 0x{1}.";
+
+			String exceptionCode = toString((UINT32)record->ExceptionCode, 0, ' ', std::ios::hex);
+			return StringUtil::format(format, exceptionAddress, exceptionCode);
+		}
+		}
+	}
+
+	struct MiniDumpParams
+	{
+		Path filePath;
+		EXCEPTION_POINTERS* exceptionData;
+	};
+
+	DWORD CALLBACK win32_writeMiniDumpWorker(void* data)
+	{
+		MiniDumpParams* params = (MiniDumpParams*)data;
+
+		HANDLE hFile = CreateFileW(params->filePath.toWString().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+			FILE_ATTRIBUTE_NORMAL, nullptr);
+
+		if (hFile != INVALID_HANDLE_VALUE)
+		{
+			MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
+
+			DumpExceptionInfo.ThreadId = GetCurrentThreadId();
+			DumpExceptionInfo.ExceptionPointers = params->exceptionData;
+			DumpExceptionInfo.ClientPointers = false;
+
+			MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal,
+				&DumpExceptionInfo, nullptr, nullptr);
+			CloseHandle(hFile);
+		}
+
+		return 0;
+	}
+
+	void win32_writeMiniDump(const Path& filePath, EXCEPTION_POINTERS* exceptionData)
+	{
+		MiniDumpParams param = { filePath, exceptionData };
+
+		// Write minidump on a second thread in order to preserve the current thread's call stack
+		DWORD threadId = 0;
+		HANDLE hThread = CreateThread(nullptr, 0, &win32_writeMiniDumpWorker, &param, 0, &threadId);
+
+		WaitForSingleObject(hThread, INFINITE);
+		CloseHandle(hThread);
+	}
+
+	static const wchar_t* gMiniDumpName = L"minidump.dmp";
+	const wchar_t* CrashHandler::CrashReportFolder = L"CrashReports/{0}/";
+	const wchar_t* CrashHandler::CrashLogName = L"log.html";
+
+	struct CrashHandler::Data
+	{
+		Mutex mutex;
+	};
+
+	CrashHandler::CrashHandler()
+	{
+		m = bs_new<Data>();
+	}
+
+	CrashHandler::~CrashHandler()
+	{
+		win32_unloadPSAPI();
+
+		bs_delete(m);
+	}
+
+	void CrashHandler::reportCrash(const String& type, const String& description, const String& function,
+		const String& file, UINT32 line) const
+	{
+		// Win32 debug methods are not thread safe
+		Lock<>(m->mutex);
+
+		String stackTrace = getStackTrace();
+
+		StringStream errorMessageStream;
+		errorMessageStream << "Fatal error occurred and the program has to terminate!" << std::endl;
+		errorMessageStream << "\t\t" << type << " - " << description << std::endl;
+		errorMessageStream << "\t\t in " << function << " [" << file << ":" << line << "]" << std::endl;
+		errorMessageStream << std::endl;
+		errorMessageStream << "Stack trace: " << std::endl;
+		errorMessageStream << stackTrace;
+
+		String errorMessage = errorMessageStream.str();
+		gDebug().logError(errorMessage);
+
+		Path crashFolder = getCrashFolder();
+		FileSystem::createDir(crashFolder);
+
+		gDebug().saveLog(crashFolder + WString(CrashLogName));
+		win32_writeMiniDump(crashFolder + WString(gMiniDumpName), nullptr);
+
+		WString simpleErrorMessage = L"Fatal error occurred and the program has to terminate! " \
+			L"\n\nFor more information check the crash report located at:\n " + crashFolder.toWString();
+
+		MessageBoxW(nullptr, simpleErrorMessage.c_str(), L"Banshee fatal error!", MB_OK);
+
+		// Note: Potentially also log Windows Error Report and/or send crash data to server
+	}
+
+	int CrashHandler::reportCrash(void* exceptionDataPtr) const
+	{
+		EXCEPTION_POINTERS* exceptionData = (EXCEPTION_POINTERS*)exceptionDataPtr;
+
+		// Win32 debug methods are not thread safe
+		Lock<>(m->mutex);
+
+		win32_initPSAPI();
+		win32_loadSymbols();
+		String stackTrace = win32_getStackTrace(*exceptionData->ContextRecord, 0);
+
+		StringStream errorMessageStream;
+		errorMessageStream << "Fatal error occurred and the program has to terminate!" << std::endl;
+		errorMessageStream << "\t\t" << win32_getExceptionMessage(exceptionData->ExceptionRecord) << std::endl;;
+		errorMessageStream << std::endl;
+		errorMessageStream << "Stack trace: " << std::endl;
+		errorMessageStream << stackTrace;
+
+		String errorMessage = errorMessageStream.str();
+		gDebug().logError(errorMessage);
+
+		Path crashFolder = getCrashFolder();
+		FileSystem::createDir(crashFolder);
+
+		gDebug().saveLog(crashFolder + WString(CrashLogName));
+		win32_writeMiniDump(crashFolder + WString(gMiniDumpName), exceptionData);
+
+		WString simpleErrorMessage = L"Fatal error occurred and the program has to terminate! " \
+			L"\n\nFor more information check the crash report located at:\n" + crashFolder.toWString();
+
+		MessageBoxW(nullptr, simpleErrorMessage.c_str(), L"Banshee fatal error!", MB_OK);
+
+		// Note: Potentially also log Windows Error Report and/or send crash data to server
+
+		return EXCEPTION_EXECUTE_HANDLER;
+	}
+
+	Path CrashHandler::getCrashFolder() const
+	{
+		SYSTEMTIME systemTime;
+		GetLocalTime(&systemTime);
+
+		WString timeStamp = L"{0}{1}{2}_{3}{4}";
+		WString strYear = toWString(systemTime.wYear, 4, '0');
+		WString strMonth = toWString(systemTime.wMonth, 2, '0');
+		WString strDay = toWString(systemTime.wDay, 2, '0');
+		WString strHour = toWString(systemTime.wHour, 2, '0');
+		WString strMinute = toWString(systemTime.wMinute, 2, '0');
+
+		timeStamp = StringUtil::format(timeStamp, strYear, strMonth, strDay, strHour, strMinute);
+
+		WString folderName = StringUtil::format(CrashReportFolder, timeStamp);
+
+		return FileSystem::getWorkingDirectoryPath() + folderName;
+	}
+
+	String CrashHandler::getStackTrace()
+	{
+		CONTEXT context;
+		RtlCaptureContext(&context);
+
+		win32_initPSAPI();
+		win32_loadSymbols();
+		return win32_getStackTrace(context, 2);
+	}
+
+	CrashHandler& gCrashHandler()
+	{
+		return CrashHandler::instance();
+	}
 }

+ 21 - 25
Source/RenderBeast/Source/BsRenderBeastPlugin.cpp

@@ -1,26 +1,22 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsRenderBeastPrerequisites.h"
-#include "BsRenderBeastFactory.h"
-#include "BsRendererManager.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Returns a name of the plugin.
-	 */
-	extern "C" BS_BSRND_EXPORT const String& getPluginName()
-	{
-		return SystemName;
-	}
-
-	/**
-	 * @brief	Entry point to the plugin. Called by the engine when the plugin is loaded.
-	 */
-	extern "C" BS_BSRND_EXPORT void* loadPlugin()
-	{
-		RendererManager::instance()._registerFactory(bs_shared_ptr_new<RenderBeastFactory>());
-
-		return nullptr;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsRenderBeastPrerequisites.h"
+#include "BsRenderBeastFactory.h"
+#include "BsRendererManager.h"
+
+namespace BansheeEngine
+{
+	/**	Returns a name of the plugin. */
+	extern "C" BS_BSRND_EXPORT const String& getPluginName()
+	{
+		return SystemName;
+	}
+
+	/**	Entry point to the plugin. Called by the engine when the plugin is loaded. */
+	extern "C" BS_BSRND_EXPORT void* loadPlugin()
+	{
+		RendererManager::instance()._registerFactory(bs_shared_ptr_new<RenderBeastFactory>());
+
+		return nullptr;
+	}
 }