Browse Source

Preparing documentation for Doxygen generation

BearishSun 10 years ago
parent
commit
783a2546e6
44 changed files with 6007 additions and 6444 deletions
  1. 10 10
      BansheeUtility/BansheeUtility.vcxproj.filters
  2. 9 9
      BansheeUtility/Include/BsAABox.h
  3. 182 187
      BansheeUtility/Include/BsAny.h
  4. 75 82
      BansheeUtility/Include/BsBinaryCloner.h
  5. 119 122
      BansheeUtility/Include/BsBinaryDiff.h
  6. 200 217
      BansheeUtility/Include/BsBinarySerializer.h
  7. 275 298
      BansheeUtility/Include/BsBitwise.h
  8. 282 282
      BansheeUtility/Include/BsColor.h
  9. 28 33
      BansheeUtility/Include/BsCrashHandler.h
  10. 278 332
      BansheeUtility/Include/BsDataStream.h
  11. 71 79
      BansheeUtility/Include/BsDynLib.h
  12. 41 37
      BansheeUtility/Include/BsDynLibManager.h
  13. 334 357
      BansheeUtility/Include/BsEvent.h
  14. 29 44
      BansheeUtility/Include/BsException.h
  15. 54 60
      BansheeUtility/Include/BsFileSerializer.h
  16. 133 137
      BansheeUtility/Include/BsFileSystem.h
  17. 43 56
      BansheeUtility/Include/BsFrameAlloc.h
  18. 181 173
      BansheeUtility/Include/BsGlobalFrameAlloc.h
  19. 82 79
      BansheeUtility/Include/BsIReflectable.h
  20. 54 49
      BansheeUtility/Include/BsManagedDataBlock.h
  21. 50 52
      BansheeUtility/Include/BsMemAllocProfiler.h
  22. 78 85
      BansheeUtility/Include/BsMemStack.h
  23. 40 63
      BansheeUtility/Include/BsMemoryAllocator.h
  24. 57 58
      BansheeUtility/Include/BsMemorySerializer.h
  25. 49 48
      BansheeUtility/Include/BsMessageHandler.h
  26. 64 63
      BansheeUtility/Include/BsMessageHandlerFwd.h
  27. 170 174
      BansheeUtility/Include/BsModule.h
  28. 623 712
      BansheeUtility/Include/BsPath.h
  29. 104 107
      BansheeUtility/Include/BsPlatformUtility.h
  30. 20 0
      BansheeUtility/Include/BsPrerequisitesUtil.h
  31. 187 185
      BansheeUtility/Include/BsRTTIField.h
  32. 117 130
      BansheeUtility/Include/BsRTTIManagedDataBlockField.h
  33. 287 315
      BansheeUtility/Include/BsRTTIPlainField.h
  34. 204 226
      BansheeUtility/Include/BsRTTIReflectableField.h
  35. 226 257
      BansheeUtility/Include/BsRTTIReflectablePtrField.h
  36. 170 214
      BansheeUtility/Include/BsRTTIType.h
  37. 169 186
      BansheeUtility/Include/BsSerializedObject.h
  38. 372 368
      BansheeUtility/Include/BsSerializedObjectRTTI.h
  39. 55 54
      BansheeUtility/Include/BsServiceLocator.h
  40. 211 214
      BansheeUtility/Include/BsStaticAlloc.h
  41. 108 111
      BansheeUtility/Include/BsTexAtlasGenerator.h
  42. 92 94
      BansheeUtility/Include/BsTime.h
  43. 51 61
      BansheeUtility/Include/BsTimer.h
  44. 23 24
      BansheeUtility/Include/BsUtil.h

+ 10 - 10
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -84,18 +84,18 @@
     <Filter Include="Source Files\Filesystem">
       <UniqueIdentifier>{3675d971-ea02-410e-af4f-fb3e9c6e44eb}</UniqueIdentifier>
     </Filter>
-    <Filter Include="Header Files\Graphics">
-      <UniqueIdentifier>{db53bb17-9025-45bd-8fb2-82615f7eb40d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Source Files\Graphics">
-      <UniqueIdentifier>{dea9161b-d3f5-401f-9005-aceafe004b3d}</UniqueIdentifier>
-    </Filter>
     <Filter Include="Header Files\General">
       <UniqueIdentifier>{db663898-59b6-41a1-adf8-1aa06efc57cd}</UniqueIdentifier>
     </Filter>
     <Filter Include="Source Files\General">
       <UniqueIdentifier>{5c5b3495-a9a3-4d91-82a1-3096c7c67d23}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\Image">
+      <UniqueIdentifier>{db53bb17-9025-45bd-8fb2-82615f7eb40d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Image">
+      <UniqueIdentifier>{dea9161b-d3f5-401f-9005-aceafe004b3d}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsThreadDefines.h">
@@ -297,10 +297,10 @@
       <Filter>Header Files\Filesystem</Filter>
     </ClInclude>
     <ClInclude Include="Include\BsColor.h">
-      <Filter>Header Files\Graphics</Filter>
+      <Filter>Header Files\Image</Filter>
     </ClInclude>
     <ClInclude Include="Include\BsTexAtlasGenerator.h">
-      <Filter>Header Files\Graphics</Filter>
+      <Filter>Header Files\Image</Filter>
     </ClInclude>
     <ClInclude Include="Include\BsAny.h">
       <Filter>Header Files\General</Filter>
@@ -521,10 +521,10 @@
       <Filter>Source Files\Filesystem</Filter>
     </ClCompile>
     <ClCompile Include="Source\BsColor.cpp">
-      <Filter>Source Files\Graphics</Filter>
+      <Filter>Source Files\Image</Filter>
     </ClCompile>
     <ClCompile Include="Source\BsTexAtlasGenerator.cpp">
-      <Filter>Source Files\Graphics</Filter>
+      <Filter>Source Files\Image</Filter>
     </ClCompile>
     <ClCompile Include="Source\BsDynLib.cpp">
       <Filter>Source Files\General</Filter>

+ 9 - 9
BansheeUtility/Include/BsAABox.h

@@ -15,15 +15,15 @@ namespace BansheeEngine
 	{
 	public:
 		/** Different corners of a box. */
-		/*
-		   1-----2
-		  /|    /|
-		 / |   / |
-		5-----4  |
-		|  0--|--3
-		| /   | /
-		|/    |/
-		6-----7
+		/*
+		   1-----2
+		  /|    /|
+		 / |   / |
+		5-----4  |
+		|  0--|--3
+		| /   | /
+		|/    |/
+		6-----7
 		*/
 		enum CornerEnum 
 		{

+ 182 - 187
BansheeUtility/Include/BsAny.h

@@ -1,188 +1,183 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsDebug.h"
-#include <algorithm>
-#include <typeinfo>
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Class capable of storing any general type, and safely extracting 
-	 *			the proper type from the internal data.
-	 */
-	class Any
-	{
-	private:
-		class DataBase
-		{
-		public:
-			virtual ~DataBase()
-			{ }
-
-			virtual DataBase* clone() const = 0;
-		};
-
-		template <typename ValueType>
-		class Data : public DataBase
-		{
-		public:
-			Data(const ValueType& value)
-				:value(value)
-			{ }
-
-			virtual DataBase* clone() const override
-			{
-				return new Data(value);
-			}
-
-			ValueType value;
-		};
-
-	public:
-		Any() 
-			:mData(nullptr)
-		{ }
-
-		template <typename ValueType>
-		Any(const ValueType& value) 
-			:mData(bs_new<Data<ValueType>>(value))
-		{ }
-
-		Any(const Any& other) 
-			:mData(other.mData != nullptr ? other.mData->clone() : nullptr)
-		{ }
-
-		~Any()
-		{
-			if (mData != nullptr)
-				bs_delete(mData);
-		}
-
-		/**
-		 * @brief	Swaps the contents of this object with another.
-		 */
-		Any& swap(Any& rhs)
-		{
-			std::swap(mData, rhs.mData);
-			return *this;
-		}
-
-		template <typename ValueType>
-		Any& operator= (const ValueType& rhs)
-		{
-			Any(rhs).swap(*this);
-			return *this;
-		}
-
-		Any& operator= (const Any& rhs)
-		{
-			Any(rhs).swap(*this);
-			return *this;
-		}
-
-		/**
-		 * @brief	Returns true if no type is set.
-		 */
-		bool empty() const
-		{
-			return mData == nullptr;
-		}
-
-	private:
-		template <typename ValueType>
-		friend ValueType* any_cast(Any*);
-
-		template <typename ValueType>
-		friend ValueType* any_cast_unsafe(Any*);
-
-		DataBase* mData;
-	};
-
-	/**
-	* @brief	Returns a pointer to the internal data of the specified type.
-	*
-	* @note		Will return null if cast fails.
-	*/
-	template <typename ValueType>
-	ValueType* any_cast(Any* operand)
-	{
-		if (operand != nullptr)
-			return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
-		else
-			return nullptr;
-	}
-
-	/**
-	 * @brief	Returns a const pointer to the internal data of the specified type.
-	 *
-	 * @note	Will return null if cast fails.
-	 */
-	template <typename ValueType>
-	const ValueType* any_cast(const Any* operand)
-	{
-		return any_cast<ValueType>(const_cast<Any*>(operand));
-	}
-
-	/**
-	* @brief	Returns a copy of the internal data of the specified type.
-	*
-	* @note		Throws an exception if cast fails.
-	*/
-	template <typename ValueType>
-	ValueType any_cast(const Any& operand)
-	{
-		return *any_cast<ValueType>(const_cast<Any*>(&operand));
-	}
-
-	/**
-	 * @brief	Returns a copy of the internal data of the specified type.
-	 *
-	 * @note	Throws an exception if cast fails.
-	 */
-	template <typename ValueType>
-	ValueType any_cast(Any& operand)
-	{
-		return *any_cast<ValueType>(&operand);
-	}
-
-	/**
-	* @brief	Returns a reference to the internal data of the specified type.
-	*
-	* @note		Throws an exception if cast fails.
-	*/
-	template <typename ValueType>
-	const ValueType& any_cast_ref(const Any & operand)
-	{
-		return *any_cast<ValueType>(const_cast<Any*>(&operand));
-	}
-
-	/**
-	 * @brief	Returns a reference to the internal data of the specified type.
-	 *
-	 * @note	Throws an exception if cast fails.
-	 */
-	template <typename ValueType>
-	ValueType& any_cast_ref(Any& operand)
-	{
-		return *any_cast<ValueType>(&operand);
-	}
-
-	/**
-	 * @brief	Casts a type without performing any kind of checks.
-	 */
-	template <typename ValueType>
-	ValueType* any_cast_unsafe(Any* operand)
-	{
-		return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
-	}
-
-	/**
-	* @brief	Casts a type without performing any kind of checks.
-	*/
-	template <typename ValueType>
-	const ValueType* any_cast_unsafe(const Any* operand)
-	{
-		return any_cast_unsafe<ValueType>(const_cast<Any*>(operand));
-	}
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsDebug.h"
+#include <algorithm>
+#include <typeinfo>
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/** Class capable of storing any general type, and safely extracting the proper type from the internal data. */
+	class Any
+	{
+	private:
+		class DataBase
+		{
+		public:
+			virtual ~DataBase()
+			{ }
+
+			virtual DataBase* clone() const = 0;
+		};
+
+		template <typename ValueType>
+		class Data : public DataBase
+		{
+		public:
+			Data(const ValueType& value)
+				:value(value)
+			{ }
+
+			virtual DataBase* clone() const override
+			{
+				return new Data(value);
+			}
+
+			ValueType value;
+		};
+
+	public:
+		Any() 
+			:mData(nullptr)
+		{ }
+
+		template <typename ValueType>
+		Any(const ValueType& value) 
+			:mData(bs_new<Data<ValueType>>(value))
+		{ }
+
+		Any(const Any& other) 
+			:mData(other.mData != nullptr ? other.mData->clone() : nullptr)
+		{ }
+
+		~Any()
+		{
+			if (mData != nullptr)
+				bs_delete(mData);
+		}
+
+		/** Swaps the contents of this object with another. */
+		Any& swap(Any& rhs)
+		{
+			std::swap(mData, rhs.mData);
+			return *this;
+		}
+
+		template <typename ValueType>
+		Any& operator= (const ValueType& rhs)
+		{
+			Any(rhs).swap(*this);
+			return *this;
+		}
+
+		Any& operator= (const Any& rhs)
+		{
+			Any(rhs).swap(*this);
+			return *this;
+		}
+
+		/** Returns true if no type is set. */
+		bool empty() const
+		{
+			return mData == nullptr;
+		}
+
+	private:
+		template <typename ValueType>
+		friend ValueType* any_cast(Any*);
+
+		template <typename ValueType>
+		friend ValueType* any_cast_unsafe(Any*);
+
+		DataBase* mData;
+	};
+
+	/**
+	 * Returns a pointer to the internal data of the specified type.
+	 *
+	 * @note		Will return null if cast fails.
+	 */
+	template <typename ValueType>
+	ValueType* any_cast(Any* operand)
+	{
+		if (operand != nullptr)
+			return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
+		else
+			return nullptr;
+	}
+
+	/**
+	 * Returns a const pointer to the internal data of the specified type.
+	 *
+	 * @note	Will return null if cast fails.
+	 */
+	template <typename ValueType>
+	const ValueType* any_cast(const Any* operand)
+	{
+		return any_cast<ValueType>(const_cast<Any*>(operand));
+	}
+
+	/**
+	 * Returns a copy of the internal data of the specified type.
+	 *
+	 * @note	Throws an exception if cast fails.
+	 */
+	template <typename ValueType>
+	ValueType any_cast(const Any& operand)
+	{
+		return *any_cast<ValueType>(const_cast<Any*>(&operand));
+	}
+
+	/**
+	 * Returns a copy of the internal data of the specified type.
+	 *
+	 * @note	Throws an exception if cast fails.
+	 */
+	template <typename ValueType>
+	ValueType any_cast(Any& operand)
+	{
+		return *any_cast<ValueType>(&operand);
+	}
+
+	/**
+	 * Returns a reference to the internal data of the specified type.
+	 *
+	 * @note	Throws an exception if cast fails.
+	 */
+	template <typename ValueType>
+	const ValueType& any_cast_ref(const Any & operand)
+	{
+		return *any_cast<ValueType>(const_cast<Any*>(&operand));
+	}
+
+	/**
+	 * Returns a reference to the internal data of the specified type.
+	 *
+	 * @note	Throws an exception if cast fails.
+	 */
+	template <typename ValueType>
+	ValueType& any_cast_ref(Any& operand)
+	{
+		return *any_cast<ValueType>(&operand);
+	}
+
+	/** Casts a type without performing any kind of checks. */
+	template <typename ValueType>
+	ValueType* any_cast_unsafe(Any* operand)
+	{
+		return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
+	}
+
+	/** Casts a type without performing any kind of checks. */
+	template <typename ValueType>
+	const ValueType* any_cast_unsafe(const Any* operand)
+	{
+		return any_cast_unsafe<ValueType>(const_cast<Any*>(operand));
+	}
+
+	/** @} */
 }

+ 75 - 82
BansheeUtility/Include/BsBinaryCloner.h

@@ -1,83 +1,76 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Helper class that performs cloning of an object that implements RTTI.
-	 */
-	class BS_UTILITY_EXPORT BinaryCloner
-	{
-	public:
-
-		/**
-		 * @brief	Returns a copy of the provided object with identical data.
-		 *
-		 * @param[in]	object		Object to clone.
-		 * @param[in]	shallow		If false then all referenced objects will be cloned
-		 *							as well, otherwise the references to the original
-		 *							objects will be kept.
-		 */
-		static SPtr<IReflectable> clone(IReflectable* object, bool shallow = false);
-
-	private:
-		struct ObjectReferenceData;
-
-		/**
-		 * @brief	Identifier representing a single field
-		 *			or an array entry in an object.
-		 */
-		struct FieldId
-		{
-			RTTIField* field;
-			INT32 arrayIdx;
-		};
-
-		/**
-		 * @brief	A saved reference to an object with a field
-		 *			identifier that owns it.
-		 */
-		struct ObjectReference
-		{
-			FieldId fieldId;
-			SPtr<IReflectable> object;
-		};
-
-		/**
-		 * @brief	Contains all object references in a portion of an
-		 *			object belonging to a specific class (base and derived 
-		 *			classes count as separate sub-objects).
-		 */
-		struct SubObjectReferenceData
-		{
-			RTTITypeBase* rtti;
-			Vector<ObjectReference> references;
-			Vector<ObjectReferenceData> children;
-		};
-
-		/**
-		 * @brief	Contains all object references in an entire object, as well
-		 *			as the identifier of the field owning this object.
-		 */
-		struct ObjectReferenceData
-		{
-			FieldId fieldId;
-			Vector<SubObjectReferenceData> subObjectData;
-		};
-
-		/**
-		 * @brief	Iterates over the provided object hierarchy and retrieves all object references
-		 *			which are returned in "referenceData" output parameter, also in a hierarchical
-		 *			format for easier parsing.
-		 */
-		static void gatherReferences(IReflectable* object, ObjectReferenceData& referenceData);
-
-		/**
-		 * @brief	Restores a set of references retrieved by "gatherReferences" and applies them to
-		 *			a specific object. Type of the object must be the same as the type that was used
-		 *			when calling "gatherReferences".
-		 */
-		static void restoreReferences(IReflectable* object, const ObjectReferenceData& referenceData);
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	/** Helper class that performs cloning of an object that implements RTTI. */
+	class BS_UTILITY_EXPORT BinaryCloner
+	{
+	public:
+
+		/**
+		 * Returns a copy of the provided object with identical data.
+		 *
+		 * @param[in]	object		Object to clone.
+		 * @param[in]	shallow		If false then all referenced objects will be cloned as well, otherwise the references 
+		 *							to the original objects will be kept.
+		 */
+		static SPtr<IReflectable> clone(IReflectable* object, bool shallow = false);
+
+	private:
+		struct ObjectReferenceData;
+
+		/** Identifier representing a single field or an array entry in an object. */
+		struct FieldId
+		{
+			RTTIField* field;
+			INT32 arrayIdx;
+		};
+
+		/** A saved reference to an object with a field identifier that owns it. */
+		struct ObjectReference
+		{
+			FieldId fieldId;
+			SPtr<IReflectable> object;
+		};
+
+		/**
+		 * Contains all object references in a portion of an object belonging to a specific class (base and derived 
+		 * classes count as separate sub-objects).
+		 */
+		struct SubObjectReferenceData
+		{
+			RTTITypeBase* rtti;
+			Vector<ObjectReference> references;
+			Vector<ObjectReferenceData> children;
+		};
+
+		/**
+		 * Contains all object references in an entire object, as well as the identifier of the field owning this object.
+		 */
+		struct ObjectReferenceData
+		{
+			FieldId fieldId;
+			Vector<SubObjectReferenceData> subObjectData;
+		};
+
+		/**
+		 * Iterates over the provided object hierarchy and retrieves all object references which are returned in 
+		 * @p referenceData output parameter, also in a hierarchical format for easier parsing.
+		 */
+		static void gatherReferences(IReflectable* object, ObjectReferenceData& referenceData);
+
+		/**
+		 * Restores a set of references retrieved by gatherReferences() and applies them toa specific object. Type of the 
+		 * object must be the same as the type that was used when calling gatherReferences().
+		 */
+		static void restoreReferences(IReflectable* object, const ObjectReferenceData& referenceData);
+	};
+
+	/** @} */
 }

+ 119 - 122
BansheeUtility/Include/BsBinaryDiff.h

@@ -1,123 +1,120 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Represents an interface RTTI objects need to implement if they
-	 *			want to provide custom "diff" generation and applying.
-	 */
-	class BS_UTILITY_EXPORT IDiff
-	{
-	public:
-		virtual ~IDiff() { }
-
-		/**
-		 * @brief	Generates per-field differences between the provided original and new object. Any field
-		 *			or array entry that is different in the new object compared to the original will be output
-		 *			in the resulting object, with a full hierarchy of that field.
-		 *
-		 *			Will return null if there is no difference.
-		 */
-		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj);
-
-		/**
-		 * @brief	Applies a previously generated per-field differences to the provided object. This will
-		 *			essentially transform the original object the differences were generated for into the modified
-		 *			version.
-		 */
-		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff);
-
-	protected:
-		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<SerializedObject>> ObjectMap;
-		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<IReflectable>> DiffObjectMap;
-
-		/**
-		 * @brief	Types of commands that are used when applying difference field values.
-		 */
-		enum DiffCommandType
-		{
-			Diff_Plain = 0x01,
-			Diff_Reflectable = 0x02,
-			Diff_ReflectablePtr = 0x03,
-			Diff_DataBlock = 0x04,
-			Diff_ArraySize = 0x05,
-			Diff_ObjectStart = 0x06,
-			Diff_ObjectEnd = 0x07,
-			Diff_ArrayFlag = 0x10
-		};
-		
-		/**
-		 * @brief	A command that is used for delaying writing to an object, it contains
-		 *			all necessary information for setting RTTI field values on an object.
-		 */
-		struct DiffCommand
-		{
-			RTTIField* field;
-			UINT32 type;
-			SPtr<IReflectable> object;
-			UINT8* value;
-			UINT32 size;
-
-			union
-			{
-				UINT32 arrayIdx;
-				UINT32 arraySize;
-			};
-		};
-
-		/**
-		 * @brief	Recursive version of generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&).
-		 *
-		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
-		 */
-		virtual SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) = 0;
-
-		/**
-		 * @brief	Generates a difference between data of a specific field type indiscriminately of the
-		 *			specific field type.
-		 *
-		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
-		 */
-		SPtr<SerializedInstance> generateDiff(RTTITypeBase* rtti, UINT32 fieldType, const SPtr<SerializedInstance>& orgData,
-			const SPtr<SerializedInstance>& newData, ObjectMap& objectMap);
-
-		/**
-		 * @brief	Recursive version of applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff).
-		 *			Outputs a set of commands that then must be executed in order to actually apply the difference to the
-		 *			provided object.
-		 *
-		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
-		 */
-		virtual void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) = 0;
-
-		/**
-		 * @brief	Applies diff according to the diff handler retrieved from the provided RTTI object.
-		 *
-		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
-		 */
-		void applyDiff(RTTITypeBase* rtti, const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands);
-	};
-
-	/**
-	 * @brief	Generates and applies "diffs". Diffs contain per-field differences between
-	 *			an original and new object. These differences can be saved and then applied
-	 *			to an original object to transform it to the new version.
-	 *
-	 * @note	Objects must be in intermediate serialized format generated by BinarySerializer.
-	 */
-	class BS_UTILITY_EXPORT BinaryDiff : public IDiff
-	{
-	private:
-		/**
-		 * @copydoc	IDiff::generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&, ObjectMap&)
-		 */
-		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) override;
-
-		/**
-		 * @copydoc	IDiff::applyDiff(const SPtr<IReflectable>&, const SPtr<SerializedObject>&, DiffObjectMap&, Vector<DiffCommand>&)
-		 */
-		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) override;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	/**
+	 * Represents an interface RTTI objects need to implement if they want to provide custom "diff" generation and applying.
+	 */
+	class BS_UTILITY_EXPORT IDiff
+	{
+	public:
+		virtual ~IDiff() { }
+
+		/**
+		 * Generates per-field differences between the provided original and new object. Any field or array entry that is 
+		 * different in the new object compared to the original will be output in the resulting object, with a full 
+		 * hierarchy of that field.
+		 *
+		 * Will return null if there is no difference.
+		 */
+		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj);
+
+		/**
+		 * Applies a previously generated per-field differences to the provided object. This will essentially transform the
+		 * original object the differences were generated for into the modified version.
+		 */
+		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff);
+
+	protected:
+		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<SerializedObject>> ObjectMap;
+		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<IReflectable>> DiffObjectMap;
+
+		/** Types of commands that are used when applying difference field values. */
+		enum DiffCommandType
+		{
+			Diff_Plain = 0x01,
+			Diff_Reflectable = 0x02,
+			Diff_ReflectablePtr = 0x03,
+			Diff_DataBlock = 0x04,
+			Diff_ArraySize = 0x05,
+			Diff_ObjectStart = 0x06,
+			Diff_ObjectEnd = 0x07,
+			Diff_ArrayFlag = 0x10
+		};
+		
+		/**
+		 * A command that is used for delaying writing to an object, it contains all necessary information for setting RTTI 
+		 * field values on an object.
+		 */
+		struct DiffCommand
+		{
+			RTTIField* field;
+			UINT32 type;
+			SPtr<IReflectable> object;
+			UINT8* value;
+			UINT32 size;
+
+			union
+			{
+				UINT32 arrayIdx;
+				UINT32 arraySize;
+			};
+		};
+
+		/**
+		 * Recursive version of generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&).
+		 *
+		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
+		 */
+		virtual SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) = 0;
+
+		/**
+		 * Generates a difference between data of a specific field type indiscriminately of the specific field type.
+		 *
+		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
+		 */
+		SPtr<SerializedInstance> generateDiff(RTTITypeBase* rtti, UINT32 fieldType, const SPtr<SerializedInstance>& orgData,
+			const SPtr<SerializedInstance>& newData, ObjectMap& objectMap);
+
+		/**
+		 * Recursive version of applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff). Outputs a 
+		 * set of commands that then must be executed in order to actually apply the difference to the provided object.
+		 *
+		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
+		 */
+		virtual void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) = 0;
+
+		/**
+		 * Applies diff according to the diff handler retrieved from the provided RTTI object.
+		 *
+		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
+		 */
+		void applyDiff(RTTITypeBase* rtti, const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands);
+	};
+
+	/**
+	 * Generates and applies "diffs". Diffs contain per-field differences between an original and new object. These 
+	 * differences can be saved and then applied to an original object to transform it to the new version.
+	 *
+	 * @note	Objects must be in intermediate serialized format generated by BinarySerializer.
+	 */
+	class BS_UTILITY_EXPORT BinaryDiff : public IDiff
+	{
+	private:
+		/** @copydoc	IDiff::generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&, ObjectMap&) */
+		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) override;
+
+		/** @copydoc	IDiff::applyDiff(const SPtr<IReflectable>&, const SPtr<SerializedObject>&, DiffObjectMap&, Vector<DiffCommand>&) */
+		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) override;
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 200 - 217
BansheeUtility/Include/BsBinarySerializer.h

@@ -1,218 +1,201 @@
-#pragma once
-
-#include <unordered_map>
-
-#include "BsPrerequisitesUtil.h"
-#include "BsSerializedObject.h"
-#include "BsRTTIField.h"
-
-namespace BansheeEngine
-{
-	class IReflectable;
-	struct RTTIReflectableFieldBase;
-	struct RTTIReflectablePtrFieldBase;
-
-	// TODO - Low priority. I will probably want to extract a generalized Serializer class so we can re-use the code
-	// in text or other serializers
-	// TODO - Low priority. Encode does a chunk-based encode so that we don't need to know the buffer size in advance,
-	// and don't have to use a lot of memory for the buffer. Consider doing something similar for decode.
-	// TODO - Low priority. Add a simple encode method that doesn't require a callback, instead it calls the callback internally
-	// and creates the buffer internally.
-	/**
-	 * @brief	Encodes all the fields of the provided object into a binary format. Fields are
-	 * 			encoded using their unique IDs. Encoded data will remain compatible for decoding even
-	 * 			if you modify the encoded class, as long as you assign new unique field IDs to
-	 * 			added/modified fields.
-	 * 			
-	 *			Like for any serializable class, fields are defined in RTTIType that each
-	 *			IReflectable class must be able to return.
-	 *
-	 * 			Any data the object or its children are pointing to will also be serialized 
-	 *			(unless the pointer isn't registered in RTTIType). Upon decoding the pointer 
-	 *			addresses will be set to proper values.
-	 * 			
-	 * @note	Child elements are guaranteed to be fully deserialized before their parents, except for fields
-	 *			marked with WeakRef flag.
-	 */
-	class BS_UTILITY_EXPORT BinarySerializer
-	{
-	public:
-		BinarySerializer();
-
-		/**
-		 * @brief	Encodes all serializable fields provided by "object" into a binary format. Data is written in chunks.
-		 * 			Whenever a chunk is filled a callback is triggered that gives the user opportunity to expand or 
-		 * 			empty the buffer (for example write the chunk to disk)
-		 *
-		 * @param		object				Object to encode into binary format.
-		 * @param [out]	buffer				Preallocated buffer where the data will be stored.
-		 * @param	bufferLength			Length of the buffer, in bytes.
-		 * @param [out]	bytesWritten		Length of the data that was actually written to the buffer,
-		 * 									in bytes.
-		 * @param	flushBufferCallback 	This callback will get called whenever the buffer gets full (Be careful to check the provided
-		 * 									"bytesRead" variable, as buffer might not be full completely). User must then
-		 * 									either create a new buffer or empty the existing one, and then return it by the callback.
-		 * 									If the returned buffer address is NULL, encoding is aborted.
-		 * @param	shallow					Determines how to handle referenced objects. If true then references will not be encoded
-		 *									and will be set to null. If false then references will be encoded as well and restored
-		 *									upon decoding.
-		 */
-		void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback,
-			bool shallow = false);
-
-		/**
-		 * @brief	Decodes an object from binary data.
-		 *
-		 * @param 	data  	Binary data to decode.
-		 * @param	dataLength	Length of the data in bytes.
-		 */
-		SPtr<IReflectable> decode(UINT8* data, UINT32 dataLength);
-
-		/**
-		 * @brief	Encodes an object into an intermediate representation.
-		 *
-		 * @param	object		Object to encode.
-		 * @param	shallow		Determines how to handle referenced objects. If true then references will not be encoded
-		 *						and will be set to null. If false then references will be encoded as well and restored
-		 *						upon decoding.
-		 */
-		SPtr<SerializedObject> _encodeIntermediate(IReflectable* object, bool shallow = false);
-
-		/**
-		 * @brief	Decodes an object in memory into an intermediate representation for easier parsing.
-		 *			
-		 * @param 	data  		Binary data to decode.
-		 * @param	dataLength	Length of the data in bytes.
-		 * @param	copyData	Determines should the data be copied or just referenced. If referenced
-		 *						then the returned serialized object will be invalid as soon as the original
-		 *						data buffer is destroyed. Referencing is faster than copying.
-		 *
-		 * @note	Internal method.
-		 *			References to field data will point to the original buffer and will become invalid 
-		 *			when it is destroyed.
-		 */
-		SPtr<SerializedObject> _decodeIntermediate(UINT8* data, UINT32 dataLength, bool copyData = false);
-
-		/**
-		 * @brief	Decodes an intermediate representation of a serialized object into the actual object.
-		 *			
-		 * @note	Internal method.
-		 */
-		SPtr<IReflectable> _decodeIntermediate(const SPtr<SerializedObject>& serializedObject);
-
-	private:
-		struct ObjectMetaData
-		{
-			UINT32 objectMeta;
-			UINT32 typeId;
-		};
-
-		struct ObjectToEncode
-		{
-			ObjectToEncode(UINT32 _objectId, std::shared_ptr<IReflectable> _object)
-				:objectId(_objectId), object(_object)
-			{ }
-
-			UINT32 objectId;
-			std::shared_ptr<IReflectable> object;
-		};
-
-		struct ObjectToDecode
-		{
-			ObjectToDecode(const SPtr<IReflectable>& _object, const SPtr<SerializedObject>& serializedObject)
-				:object(_object), serializedObject(serializedObject), isDecoded(false)
-			{ }
-
-			SPtr<IReflectable> object;
-			SPtr<SerializedObject> serializedObject;
-			bool isDecoded;
-		};
-
-		/**
-		 * @brief	Encodes a single IReflectable object. 
-		 */
-		UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
-
-		/**
-		 * @brief	Decodes a single IReflectable object.
-		 */
-		void decodeInternal(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serializableObject);
-
-		/**
-		 * @brief	Decodes an object in memory into an intermediate representation for easier parsing.
-		 */
-		bool decodeIntermediateInternal(UINT8* data, UINT32 dataLength, UINT32& bytesRead, SPtr<SerializedObject>& output, bool copyData);
-
-		/**
-		 * @brief	Helper method for encoding a complex object and copying its data to a buffer.
-		 */
-		UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
-
-		/**
-		 * @brief	Helper method for encoding a data block to a buffer.
-		 */
-		UINT8* dataBlockToBuffer(UINT8* data, UINT32 size, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
-
-		/**
-		 * @brief	Finds an existing, or creates a unique unique identifier for the specified object. 
-		 */
-		UINT32 findOrCreatePersistentId(IReflectable* object);
-
-		/**
-		 * @brief	Finds or creates an id for the provided object and returns it.
-		 * 			And it adds the object to a list of objects that need to be encoded,
-		 * 			if it's not already there.
-		 */
-		UINT32 registerObjectPtr(std::shared_ptr<IReflectable> object);
-
-		/**
-		 * @brief	Encodes data required for representing a serialized field, into 4 bytes.
-		 */
-		static UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, 
-			SerializableFieldType type, bool hasDynamicSize, bool terminator);
-
-		/**
-		 * @brief	Decode meta field that was encoded using encodeFieldMetaData.
-		 */
-		static void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, 
-			SerializableFieldType& type, bool& hasDynamicSize, bool& terminator);
-
-		/**
-		 * @brief	Encodes data required for representing an object identifier, into 8 bytes.
-		 * 			
-		 * 			@note		Id can be a maximum of 30 bits, as two bits are reserved.
-		 *
-		 * @param	objId	   	Unique ID of the object instance.
-		 * @param	objTypeId  	Unique ID of the object type.
-		 * @param	isBaseClass	true if this object is base class (i.e. just a part of a larger object).
-		 */
-		static ObjectMetaData encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass);
-
-		/**
-		* @brief	Decode meta field that was encoded using encodeObjectMetaData.
-		*/
-		static void decodeObjectMetaData(ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass);
-
-		/**
-		 * @brief	Returns true if the provided encoded meta data represents object meta data.
-		 */
-		static bool isObjectMetaData(UINT32 encodedData);
-
-		UnorderedMap<void*, UINT32> mObjectAddrToId;
-		UINT32 mLastUsedObjectId;
-		Vector<ObjectToEncode> mObjectsToEncode;
-		UINT32 mTotalBytesWritten;
-
-		UnorderedMap<SPtr<SerializedObject>, ObjectToDecode> mObjectMap;
-		UnorderedMap<UINT32, SPtr<SerializedObject>> mInterimObjectMap;
-
-		static const int META_SIZE = 4; // Meta field size
-		static const int NUM_ELEM_FIELD_SIZE = 4; // Size of the field storing number of array elements
-		static const int COMPLEX_TYPE_FIELD_SIZE = 4; // Size of the field storing the size of a child complex type
-		static const int DATA_BLOCK_TYPE_FIELD_SIZE = 4;
-	};
+#pragma once
+
+#include <unordered_map>
+
+#include "BsPrerequisitesUtil.h"
+#include "BsSerializedObject.h"
+#include "BsRTTIField.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	class IReflectable;
+	struct RTTIReflectableFieldBase;
+	struct RTTIReflectablePtrFieldBase;
+
+	// TODO - Low priority. I will probably want to extract a generalized Serializer class so we can re-use the code
+	// in text or other serializers
+	// TODO - Low priority. Encode does a chunk-based encode so that we don't need to know the buffer size in advance,
+	// and don't have to use a lot of memory for the buffer. Consider doing something similar for decode.
+	// TODO - Low priority. Add a simple encode method that doesn't require a callback, instead it calls the callback internally
+	// and creates the buffer internally.
+	/**
+	 * Encodes all the fields of the provided object into a binary format. Fields are encoded using their unique IDs. 
+	 * Encoded data will remain compatible for decoding even if you modify the encoded class, as long as you assign new 
+	 * unique field IDs to added/modified fields.
+	 * 			
+	 * Like for any serializable class, fields are defined in RTTIType that each IReflectable class must be able to return.
+	 *
+	 * Any data the object or its children are pointing to will also be serialized (unless the pointer isn't registered in 
+	 * RTTIType). Upon decoding the pointer addresses will be set to proper values.
+	 * 			
+	 * @note	
+	 * Child elements are guaranteed to be fully deserialized before their parents, except for fields marked with WeakRef flag.
+	 */
+	class BS_UTILITY_EXPORT BinarySerializer
+	{
+	public:
+		BinarySerializer();
+
+		/**
+		 * Encodes all serializable fields provided by @p object into a binary format. Data is written in chunks. Whenever a 
+		 * chunk is filled a callback is triggered that gives the user opportunity to expand or empty the buffer (for 
+		 * example write the chunk to disk)
+		 *
+		 * @param[in]	object					Object to encode into binary format.
+		 * @param[out]	buffer					Preallocated buffer where the data will be stored.
+		 * @param[in]	bufferLength			Length of the buffer, in bytes.
+		 * @param[out]	bytesWritten			Length of the data that was actually written to the buffer, in bytes.
+		 * @param[in]	flushBufferCallback 	This callback will get called whenever the buffer gets full (Be careful to 
+		 *										check the provided @p bytesRead variable, as buffer might not be full 
+		 *										completely). User must then either create a new buffer or empty the existing 
+		 *										one, and then return it by the callback. If the returned buffer address is 
+		 *										NULL, encoding is aborted.
+		 * @param[in]	shallow					Determines how to handle referenced objects. If true then references will 
+		 *										not be encoded and will be set to null. If false then references will be 
+		 *										encoded as well and restored upon decoding.
+		 */
+		void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, UINT32* bytesWritten,
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback,
+			bool shallow = false);
+
+		/**
+		 * Decodes an object from binary data.
+		 *
+		 * @param[in]	data  		Binary data to decode.
+		 * @param[in]	dataLength	Length of the data in bytes.
+		 */
+		SPtr<IReflectable> decode(UINT8* data, UINT32 dataLength);
+
+		/**
+		 * Encodes an object into an intermediate representation.
+		 *
+		 * @param[in]	object		Object to encode.
+		 * @param[in]	shallow		Determines how to handle referenced objects. If true then references will not be encoded
+		 *							and will be set to null. If false then references will be encoded as well and restored
+		 *							upon decoding.
+		 */
+		SPtr<SerializedObject> _encodeIntermediate(IReflectable* object, bool shallow = false);
+
+		/**
+		 * Decodes an object in memory into an intermediate representation for easier parsing.
+		 *			
+		 * @param[in] 	data  		Binary data to decode.
+		 * @param[in]	dataLength	Length of the data in bytes.
+		 * @param[in]	copyData	Determines should the data be copied or just referenced. If referenced then the returned
+		 *							serialized object will be invalid as soon as the original data buffer is destroyed. 
+		 *							Referencing is faster than copying.
+		 *
+		 * @note	
+		 * Internal method.
+		 * @note
+		 * References to field data will point to the original buffer and will become invalid when it is destroyed.
+		 */
+		SPtr<SerializedObject> _decodeIntermediate(UINT8* data, UINT32 dataLength, bool copyData = false);
+
+		/**
+		 * Decodes an intermediate representation of a serialized object into the actual object.
+		 *			
+		 * @note	Internal method.
+		 */
+		SPtr<IReflectable> _decodeIntermediate(const SPtr<SerializedObject>& serializedObject);
+
+	private:
+		struct ObjectMetaData
+		{
+			UINT32 objectMeta;
+			UINT32 typeId;
+		};
+
+		struct ObjectToEncode
+		{
+			ObjectToEncode(UINT32 _objectId, std::shared_ptr<IReflectable> _object)
+				:objectId(_objectId), object(_object)
+			{ }
+
+			UINT32 objectId;
+			std::shared_ptr<IReflectable> object;
+		};
+
+		struct ObjectToDecode
+		{
+			ObjectToDecode(const SPtr<IReflectable>& _object, const SPtr<SerializedObject>& serializedObject)
+				:object(_object), serializedObject(serializedObject), isDecoded(false)
+			{ }
+
+			SPtr<IReflectable> object;
+			SPtr<SerializedObject> serializedObject;
+			bool isDecoded;
+		};
+
+		/** Encodes a single IReflectable object. */
+		UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
+
+		/**	Decodes a single IReflectable object. */
+		void decodeInternal(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serializableObject);
+
+		/**	Decodes an object in memory into an intermediate representation for easier parsing. */
+		bool decodeIntermediateInternal(UINT8* data, UINT32 dataLength, UINT32& bytesRead, SPtr<SerializedObject>& output, bool copyData);
+
+		/**	Helper method for encoding a complex object and copying its data to a buffer. */
+		UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
+
+		/**	Helper method for encoding a data block to a buffer. */
+		UINT8* dataBlockToBuffer(UINT8* data, UINT32 size, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+
+		/**	Finds an existing, or creates a unique unique identifier for the specified object. */
+		UINT32 findOrCreatePersistentId(IReflectable* object);
+
+		/**
+		 * Finds or creates an id for the provided object and returns it. And it adds the object to a list of objects that 
+		 * need to be encoded, if it's not already there.
+		 */
+		UINT32 registerObjectPtr(std::shared_ptr<IReflectable> object);
+
+		/** Encodes data required for representing a serialized field, into 4 bytes. */
+		static UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, 
+			SerializableFieldType type, bool hasDynamicSize, bool terminator);
+
+		/** Decode meta field that was encoded using encodeFieldMetaData().*/
+		static void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, 
+			SerializableFieldType& type, bool& hasDynamicSize, bool& terminator);
+
+		/**
+		 * Encodes data required for representing an object identifier, into 8 bytes.
+		 *
+		 * @param[in]	objId	   	Unique ID of the object instance.
+		 * @param[in]	objTypeId  	Unique ID of the object type.
+		 * @param[in]	isBaseClass	true if this object is base class (i.e. just a part of a larger object).
+		 *
+		 * @note		Id can be a maximum of 30 bits, as two bits are reserved.
+		 */
+		static ObjectMetaData encodeObjectMetaData(UINT32 objId, UINT32 objTypeId, bool isBaseClass);
+
+		/** Decode meta field that was encoded using encodeObjectMetaData. */
+		static void decodeObjectMetaData(ObjectMetaData encodedData, UINT32& objId, UINT32& objTypeId, bool& isBaseClass);
+
+		/** Returns true if the provided encoded meta data represents object meta data. */
+		static bool isObjectMetaData(UINT32 encodedData);
+
+		UnorderedMap<void*, UINT32> mObjectAddrToId;
+		UINT32 mLastUsedObjectId;
+		Vector<ObjectToEncode> mObjectsToEncode;
+		UINT32 mTotalBytesWritten;
+
+		UnorderedMap<SPtr<SerializedObject>, ObjectToDecode> mObjectMap;
+		UnorderedMap<UINT32, SPtr<SerializedObject>> mInterimObjectMap;
+
+		static const int META_SIZE = 4; // Meta field size
+		static const int NUM_ELEM_FIELD_SIZE = 4; // Size of the field storing number of array elements
+		static const int COMPLEX_TYPE_FIELD_SIZE = 4; // Size of the field storing the size of a child complex type
+		static const int DATA_BLOCK_TYPE_FIELD_SIZE = 4;
+	};
+
+	/** @} */
 }

+ 275 - 298
BansheeUtility/Include/BsBitwise.h

@@ -1,299 +1,276 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine 
-{
-    /** 
-	 * @brief	Class for manipulating bit patterns.
-     */
-    class Bitwise 
-	{
-    public:
-		/** 
-		 * @brief	Returns the most significant bit set in a value.
-		 */
-		static FORCEINLINE unsigned int mostSignificantBitSet(unsigned int value)
-        {
-            unsigned int result = 0;
-            while (value != 0) {
-                ++result;
-                value >>= 1;
-            }
-            return result-1;
-        }
-
-		/** 
-		 * @brief	Returns the closest power-of-two number greater or equal to value.
-		 */
-        static FORCEINLINE UINT32 firstPO2From(UINT32 n)
-        {
-            --n;            
-            n |= n >> 16;
-            n |= n >> 8;
-            n |= n >> 4;
-            n |= n >> 2;
-            n |= n >> 1;
-            ++n;
-            return n;
-        }
-
-		/** 
-		 * @brief	Determines whether the number is power-of-two or not.
-		 */
-        template<typename T>
-        static FORCEINLINE bool isPO2(T n)
-        {
-            return (n & (n-1)) == 0;
-        }
-
-		/** 
-		 * @brief	Returns the number of bits a pattern must be shifted right by to
-         *			remove right-hand zeros.
-		 */
-		template<typename T>
-        static FORCEINLINE unsigned int getBitShift(T mask)
-		{
-			if (mask == 0)
-				return 0;
-
-			unsigned int result = 0;
-			while ((mask & 1) == 0) {
-				++result;
-				mask >>= 1;
-			}
-			return result;
-		}
-
-		/** 
-		 * @brief	Takes a value with a given src bit mask, and produces another
-         *			value with a desired bit mask.
-		 */
-		template<typename SrcT, typename DestT>
-        static inline DestT convertBitPattern(SrcT srcValue, SrcT srcBitMask, DestT destBitMask)
-		{
-			// Mask off irrelevant source value bits (if any)
-			srcValue = srcValue & srcBitMask;
-
-			// Shift source down to bottom of DWORD
-			const unsigned int srcBitShift = getBitShift(srcBitMask);
-			srcValue >>= srcBitShift;
-
-			// Get max value possible in source from srcMask
-			const SrcT srcMax = srcBitMask >> srcBitShift;
-
-			// Get max available in dest
-			const unsigned int destBitShift = getBitShift(destBitMask);
-			const DestT destMax = destBitMask >> destBitShift;
-
-			// Scale source value into destination, and shift back
-			DestT destValue = (srcValue * destMax) / srcMax;
-			return (destValue << destBitShift);
-		}
-
-		/** 
-		 * @brief	Convert N bit colour channel value to P bits. It fills P bits with the
-         *			bit pattern repeated. (this is /((1<<n)-1) in fixed point).
-		 */
-        static inline unsigned int fixedToFixed(UINT32 value, unsigned int n, unsigned int p) 
-        {
-            if(n > p) 
-            {
-                // Less bits required than available; this is easy
-                value >>= n-p;
-            } 
-            else if(n < p)
-            {
-                // More bits required than are there, do the fill
-                // Use old fashioned division, probably better than a loop
-                if(value == 0)
-                        value = 0;
-                else if(value == (static_cast<unsigned int>(1)<<n)-1)
-                        value = (1<<p)-1;
-                else    value = value*(1<<p)/((1<<n)-1);
-            }
-            return value;    
-        }
-
-		/** 
-		 * @brief	Convert floating point color channel value between 0.0 and 1.0 (otherwise clamped) 
-         *			to integer of a certain number of bits. Works for any value of bits between 0 and 31.
-		 */
-        static inline unsigned int floatToFixed(const float value, const unsigned int bits)
-        {
-            if(value <= 0.0f) return 0;
-            else if (value >= 1.0f) return (1<<bits)-1;
-            else return (unsigned int)(value * (1<<bits));     
-        }
-
-		/** 
-		 * @brief	Fixed point to float.
-		 */
-        static inline float fixedToFloat(unsigned value, unsigned int bits)
-        {
-            return (float)value/(float)((1<<bits)-1);
-        }
-
-		/** 
-		 * @brief	Write a n*8 bits integer value to memory in native endian.
-		 */
-        static inline void intWrite(void *dest, const int n, const unsigned int value)
-        {
-            switch(n) {
-                case 1:
-                    ((UINT8*)dest)[0] = (UINT8)value;
-                    break;
-                case 2:
-                    ((UINT16*)dest)[0] = (UINT16)value;
-                    break;
-                case 3:
-#if BS_ENDIAN == BS_ENDIAN_BIG      
-                    ((UINT8*)dest)[0] = (UINT8)((value >> 16) & 0xFF);
-                    ((UINT8*)dest)[1] = (UINT8)((value >> 8) & 0xFF);
-                    ((UINT8*)dest)[2] = (UINT8)(value & 0xFF);
-#else
-                    ((UINT8*)dest)[2] = (UINT8)((value >> 16) & 0xFF);
-                    ((UINT8*)dest)[1] = (UINT8)((value >> 8) & 0xFF);
-                    ((UINT8*)dest)[0] = (UINT8)(value & 0xFF);
-#endif
-                    break;
-                case 4:
-                    ((UINT32*)dest)[0] = (UINT32)value;                
-                    break;                
-            }        
-        }
-
-		/** 
-		 * @brief	Read a n*8 bits integer value to memory in native endian.
-		 */
-        static inline unsigned int intRead(const void *src, int n) {
-            switch(n) {
-                case 1:
-                    return ((UINT8*)src)[0];
-                case 2:
-                    return ((UINT16*)src)[0];
-                case 3:
-#if BS_ENDIAN == BS_ENDIAN_BIG      
-                    return ((UINT32)((UINT8*)src)[0]<<16)|
-                            ((UINT32)((UINT8*)src)[1]<<8)|
-                            ((UINT32)((UINT8*)src)[2]);
-#else
-                    return ((UINT32)((UINT8*)src)[0])|
-                            ((UINT32)((UINT8*)src)[1]<<8)|
-                            ((UINT32)((UINT8*)src)[2]<<16);
-#endif
-                case 4:
-                    return ((UINT32*)src)[0];
-            } 
-            return 0; // ?
-        }
-
-		/** 
-		 * @brief	Convert a float32 to a float16 (NV_half_float).
-		 */
-        static inline UINT16 floatToHalf(float i)
-        {
-            union { float f; UINT32 i; } v;
-            v.f = i;
-            return floatToHalfI(v.i);
-        }
-
-		/** 
-		 * @brief	Converts float in UINT32 format to a a half in UINT16 format.
-		 */
-        static inline UINT16 floatToHalfI(UINT32 i)
-        {
-            register int s =  (i >> 16) & 0x00008000;
-            register int e = ((i >> 23) & 0x000000ff) - (127 - 15);
-            register int m =   i        & 0x007fffff;
-        
-            if (e <= 0)
-            {
-                if (e < -10)
-                {
-                    return 0;
-                }
-                m = (m | 0x00800000) >> (1 - e);
-        
-                return static_cast<UINT16>(s | (m >> 13));
-            }
-            else if (e == 0xff - (127 - 15))
-            {
-                if (m == 0) // Inf
-                {
-                    return static_cast<UINT16>(s | 0x7c00);
-                } 
-                else    // NAN
-                {
-                    m >>= 13;
-                    return static_cast<UINT16>(s | 0x7c00 | m | (m == 0));
-                }
-            }
-            else
-            {
-                if (e > 30) // Overflow
-                {
-                    return static_cast<UINT16>(s | 0x7c00);
-                }
-        
-                return static_cast<UINT16>(s | (e << 10) | (m >> 13));
-            }
-        }
-        
-		/** 
-		 * @brief	Convert a float16 (NV_half_float) to a float32.
-		 */
-        static inline float halfToFloat(UINT16 y)
-        {
-            union { float f; UINT32 i; } v;
-            v.i = halfToFloatI(y);
-            return v.f;
-        }
-
-		/** 
-		 * @brief	Converts a half in UINT16 format to a float
-		 *			in UINT32 format.
-		 */
-        static inline UINT32 halfToFloatI(UINT16 y)
-        {
-            register int s = (y >> 15) & 0x00000001;
-            register int e = (y >> 10) & 0x0000001f;
-            register int m =  y        & 0x000003ff;
-        
-            if (e == 0)
-            {
-                if (m == 0) // Plus or minus zero
-                {
-                    return s << 31;
-                }
-                else // Denormalized number -- renormalize it
-                {
-                    while (!(m & 0x00000400))
-                    {
-                        m <<= 1;
-                        e -=  1;
-                    }
-        
-                    e += 1;
-                    m &= ~0x00000400;
-                }
-            }
-            else if (e == 31)
-            {
-                if (m == 0) // Inf
-                {
-                    return (s << 31) | 0x7f800000;
-                }
-                else // NaN
-                {
-                    return (s << 31) | 0x7f800000 | (m << 13);
-                }
-            }
-        
-            e = e + (127 - 15);
-            m = m << 13;
-        
-            return (s << 31) | (e << 23) | m;
-        }
-    };
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine 
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+    /** Class for manipulating bit patterns. */
+    class Bitwise 
+	{
+    public:
+		/** Returns the most significant bit set in a value. */
+		static FORCEINLINE unsigned int mostSignificantBitSet(unsigned int value)
+        {
+            unsigned int result = 0;
+            while (value != 0) {
+                ++result;
+                value >>= 1;
+            }
+            return result-1;
+        }
+
+		/** Returns the closest power-of-two number greater or equal to value. */
+        static FORCEINLINE UINT32 firstPO2From(UINT32 n)
+        {
+            --n;            
+            n |= n >> 16;
+            n |= n >> 8;
+            n |= n >> 4;
+            n |= n >> 2;
+            n |= n >> 1;
+            ++n;
+            return n;
+        }
+
+		/** Determines whether the number is power-of-two or not. */
+        template<typename T>
+        static FORCEINLINE bool isPO2(T n)
+        {
+            return (n & (n-1)) == 0;
+        }
+
+		/** Returns the number of bits a pattern must be shifted right by to remove right-hand zeros. */
+		template<typename T>
+        static FORCEINLINE unsigned int getBitShift(T mask)
+		{
+			if (mask == 0)
+				return 0;
+
+			unsigned int result = 0;
+			while ((mask & 1) == 0) {
+				++result;
+				mask >>= 1;
+			}
+			return result;
+		}
+
+		/** Takes a value with a given src bit mask, and produces another value with a desired bit mask. */
+		template<typename SrcT, typename DestT>
+        static inline DestT convertBitPattern(SrcT srcValue, SrcT srcBitMask, DestT destBitMask)
+		{
+			// Mask off irrelevant source value bits (if any)
+			srcValue = srcValue & srcBitMask;
+
+			// Shift source down to bottom of DWORD
+			const unsigned int srcBitShift = getBitShift(srcBitMask);
+			srcValue >>= srcBitShift;
+
+			// Get max value possible in source from srcMask
+			const SrcT srcMax = srcBitMask >> srcBitShift;
+
+			// Get max available in dest
+			const unsigned int destBitShift = getBitShift(destBitMask);
+			const DestT destMax = destBitMask >> destBitShift;
+
+			// Scale source value into destination, and shift back
+			DestT destValue = (srcValue * destMax) / srcMax;
+			return (destValue << destBitShift);
+		}
+
+		/** 
+		 * Convert N bit colour channel value to P bits. It fills P bits with the bit pattern repeated. 
+		 * (this is /((1<<n)-1) in fixed point).
+		 */
+        static inline unsigned int fixedToFixed(UINT32 value, unsigned int n, unsigned int p) 
+        {
+            if(n > p) 
+            {
+                // Less bits required than available; this is easy
+                value >>= n-p;
+            } 
+            else if(n < p)
+            {
+                // More bits required than are there, do the fill
+                // Use old fashioned division, probably better than a loop
+                if(value == 0)
+                        value = 0;
+                else if(value == (static_cast<unsigned int>(1)<<n)-1)
+                        value = (1<<p)-1;
+                else    value = value*(1<<p)/((1<<n)-1);
+            }
+            return value;    
+        }
+
+		/** 
+		 * Convert floating point color channel value between 0.0 and 1.0 (otherwise clamped) to integer of a certain 
+		 * number of bits. Works for any value of bits between 0 and 31.
+		 */
+        static unsigned int floatToFixed(const float value, const unsigned int bits)
+        {
+            if(value <= 0.0f) return 0;
+            else if (value >= 1.0f) return (1<<bits)-1;
+            else return (unsigned int)(value * (1<<bits));     
+        }
+
+		/** Fixed point to float. */
+        static float fixedToFloat(unsigned value, unsigned int bits)
+        {
+            return (float)value/(float)((1<<bits)-1);
+        }
+
+		/** Write a n*8 bits integer value to memory in native endian. */
+        static void intWrite(void *dest, const int n, const unsigned int value)
+        {
+            switch(n) {
+                case 1:
+                    ((UINT8*)dest)[0] = (UINT8)value;
+                    break;
+                case 2:
+                    ((UINT16*)dest)[0] = (UINT16)value;
+                    break;
+                case 3:
+#if BS_ENDIAN == BS_ENDIAN_BIG      
+                    ((UINT8*)dest)[0] = (UINT8)((value >> 16) & 0xFF);
+                    ((UINT8*)dest)[1] = (UINT8)((value >> 8) & 0xFF);
+                    ((UINT8*)dest)[2] = (UINT8)(value & 0xFF);
+#else
+                    ((UINT8*)dest)[2] = (UINT8)((value >> 16) & 0xFF);
+                    ((UINT8*)dest)[1] = (UINT8)((value >> 8) & 0xFF);
+                    ((UINT8*)dest)[0] = (UINT8)(value & 0xFF);
+#endif
+                    break;
+                case 4:
+                    ((UINT32*)dest)[0] = (UINT32)value;                
+                    break;                
+            }        
+        }
+
+		/** Read a n*8 bits integer value to memory in native endian. */
+        static unsigned int intRead(const void *src, int n) {
+            switch(n) {
+                case 1:
+                    return ((UINT8*)src)[0];
+                case 2:
+                    return ((UINT16*)src)[0];
+                case 3:
+#if BS_ENDIAN == BS_ENDIAN_BIG      
+                    return ((UINT32)((UINT8*)src)[0]<<16)|
+                            ((UINT32)((UINT8*)src)[1]<<8)|
+                            ((UINT32)((UINT8*)src)[2]);
+#else
+                    return ((UINT32)((UINT8*)src)[0])|
+                            ((UINT32)((UINT8*)src)[1]<<8)|
+                            ((UINT32)((UINT8*)src)[2]<<16);
+#endif
+                case 4:
+                    return ((UINT32*)src)[0];
+            } 
+            return 0; // ?
+        }
+
+		/** Convert a float32 to a float16 (NV_half_float). */
+        static UINT16 floatToHalf(float i)
+        {
+            union { float f; UINT32 i; } v;
+            v.f = i;
+            return floatToHalfI(v.i);
+        }
+
+		/** Converts float in UINT32 format to a a half in UINT16 format. */
+        static UINT16 floatToHalfI(UINT32 i)
+        {
+            register int s =  (i >> 16) & 0x00008000;
+            register int e = ((i >> 23) & 0x000000ff) - (127 - 15);
+            register int m =   i        & 0x007fffff;
+        
+            if (e <= 0)
+            {
+                if (e < -10)
+                {
+                    return 0;
+                }
+                m = (m | 0x00800000) >> (1 - e);
+        
+                return static_cast<UINT16>(s | (m >> 13));
+            }
+            else if (e == 0xff - (127 - 15))
+            {
+                if (m == 0) // Inf
+                {
+                    return static_cast<UINT16>(s | 0x7c00);
+                } 
+                else    // NAN
+                {
+                    m >>= 13;
+                    return static_cast<UINT16>(s | 0x7c00 | m | (m == 0));
+                }
+            }
+            else
+            {
+                if (e > 30) // Overflow
+                {
+                    return static_cast<UINT16>(s | 0x7c00);
+                }
+        
+                return static_cast<UINT16>(s | (e << 10) | (m >> 13));
+            }
+        }
+        
+		/** Convert a float16 (NV_half_float) to a float32. */
+        static float halfToFloat(UINT16 y)
+        {
+            union { float f; UINT32 i; } v;
+            v.i = halfToFloatI(y);
+            return v.f;
+        }
+
+		/** Converts a half in UINT16 format to a float in UINT32 format. */
+        static UINT32 halfToFloatI(UINT16 y)
+        {
+            register int s = (y >> 15) & 0x00000001;
+            register int e = (y >> 10) & 0x0000001f;
+            register int m =  y        & 0x000003ff;
+        
+            if (e == 0)
+            {
+                if (m == 0) // Plus or minus zero
+                {
+                    return s << 31;
+                }
+                else // Denormalized number -- renormalize it
+                {
+                    while (!(m & 0x00000400))
+                    {
+                        m <<= 1;
+                        e -=  1;
+                    }
+        
+                    e += 1;
+                    m &= ~0x00000400;
+                }
+            }
+            else if (e == 31)
+            {
+                if (m == 0) // Inf
+                {
+                    return (s << 31) | 0x7f800000;
+                }
+                else // NaN
+                {
+                    return (s << 31) | 0x7f800000 | (m << 13);
+                }
+            }
+        
+            e = e + (127 - 15);
+            m = m << 13;
+        
+            return (s << 31) | (e << 23) | m;
+        }
+    };
+
+	/** @} */
 }

+ 282 - 282
BansheeUtility/Include/BsColor.h

@@ -1,282 +1,282 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine 
-{
-    typedef UINT32 RGBA;
-    typedef UINT32 ARGB;
-    typedef UINT32 ABGR;
-	typedef UINT32 BGRA;
-
-	/** 
-	 * @brief	Color represented as 4 components, each being a floating point value ranging from
-	 *			0 to 1. Color components are Red, Green, Blue and Alpha.
-	 */
-    class BS_UTILITY_EXPORT Color
-    {
-    public:
-        static const Color ZERO;
-        static const Color Black;
-        static const Color White;
-        static const Color Red;
-        static const Color Green;
-        static const Color Blue;
-
-	    explicit Color(float red = 1.0f, float green = 1.0f,
-				    float blue = 1.0f, float alpha = 1.0f ) 
-					:r(red), g(green), b(blue), a(alpha)
-        { }
-
-	    bool operator==(const Color& rhs) const;
-	    bool operator!=(const Color& rhs) const;
-
-	    RGBA getAsRGBA(void) const;
-	    ARGB getAsARGB(void) const;
-		BGRA getAsBGRA(void) const;
-	    ABGR getAsABGR(void) const;
-
-        void setAsRGBA(const RGBA val);
-        void setAsARGB(const ARGB val);
-		void setAsBGRA(const BGRA val);
-        void setAsABGR(const ABGR val);
-
-		/** 
-		 * @brief	Clamps colour value to the range [0, 1].
-		 */
-        void saturate()
-        {
-            if (r < 0)
-                r = 0;
-            else if (r > 1)
-                r = 1;
-
-            if (g < 0)
-                g = 0;
-            else if (g > 1)
-                g = 1;
-
-            if (b < 0)
-                b = 0;
-            else if (b > 1)
-                b = 1;
-
-            if (a < 0)
-                a = 0;
-            else if (a > 1)
-                a = 1;
-        }
-
-		/** 
-		 * @brief	Clamps colour value to the range [0, 1]. Returned saturated
-		 *			color as a copy.
-		 */
-        Color saturateCopy() const
-        {
-            Color ret = *this;
-            ret.saturate();
-            return ret;
-        }
-
-		inline float operator[] (const UINT32 i) const
-		{
-			assert(i < 4);
-
-			return *(&r+i);
-		}
-
-		inline float& operator[] (const UINT32 i)
-		{
-			assert(i < 4);
-
-			return *(&r+i);
-		}
-
-		/** 
-		 * @brief	Pointer accessor for direct copying.
-		 */
-		inline float* ptr()
-		{
-			return &r;
-		}
-
-		/** 
-		 * @brief	Pointer accessor for direct copying.
-		 */
-		inline const float* ptr() const
-		{
-			return &r;
-		}
-
-        inline Color operator+ (const Color& rhs) const
-        {
-            Color kSum;
-
-            kSum.r = r + rhs.r;
-            kSum.g = g + rhs.g;
-            kSum.b = b + rhs.b;
-            kSum.a = a + rhs.a;
-
-            return kSum;
-        }
-
-        inline Color operator- ( const Color& rhs) const
-        {
-            Color kDiff;
-
-            kDiff.r = r - rhs.r;
-            kDiff.g = g - rhs.g;
-            kDiff.b = b - rhs.b;
-            kDiff.a = a - rhs.a;
-
-            return kDiff;
-        }
-
-        inline Color operator* (const float rhs) const
-        {
-            Color kProd;
-
-            kProd.r = rhs*r;
-            kProd.g = rhs*g;
-            kProd.b = rhs*b;
-            kProd.a = rhs*a;
-
-            return kProd;
-        }
-
-        inline Color operator* (const Color& rhs) const
-        {
-            Color kProd;
-
-            kProd.r = rhs.r * r;
-            kProd.g = rhs.g * g;
-            kProd.b = rhs.b * b;
-            kProd.a = rhs.a * a;
-
-            return kProd;
-        }
-
-        inline Color operator/ (const Color& rhs) const
-        {
-            Color kProd;
-
-            kProd.r = rhs.r / r;
-            kProd.g = rhs.g / g;
-            kProd.b = rhs.b / b;
-            kProd.a = rhs.a / a;
-
-            return kProd;
-        }
-
-        inline Color operator/ (const float rhs) const
-        {
-            assert(rhs != 0.0f);
-
-            Color kDiv;
-
-            float fInv = 1.0f / rhs;
-            kDiv.r = r * fInv;
-            kDiv.g = g * fInv;
-            kDiv.b = b * fInv;
-            kDiv.a = a * fInv;
-
-            return kDiv;
-        }
-
-        inline friend Color operator* (const float lhs, const Color& rhs)
-        {
-            Color result;
-
-            result.r = lhs * rhs.r;
-            result.g = lhs * rhs.g;
-            result.b = lhs * rhs.b;
-            result.a = lhs * rhs.a;
-
-            return result;
-        }
-
-        inline Color& operator+= (const Color& rhs)
-        {
-            r += rhs.r;
-            g += rhs.g;
-            b += rhs.b;
-            a += rhs.a;
-
-            return *this;
-        }
-
-        inline Color& operator-= (const Color& rhs)
-        {
-            r -= rhs.r;
-            g -= rhs.g;
-            b -= rhs.b;
-            a -= rhs.a;
-
-            return *this;
-        }
-
-        inline Color& operator*= (const float rhs)
-        {
-            r *= rhs;
-            g *= rhs;
-            b *= rhs;
-            a *= rhs;
-
-            return *this;
-        }
-
-        inline Color& operator/= (const float rhs)
-        {
-            assert(rhs != 0.0f);
-
-            float fInv = 1.0f / rhs;
-
-            r *= rhs;
-            g *= rhs;
-            b *= rhs;
-            a *= rhs;
-
-            return *this;
-        }
-
-		/** 
-		 * @brief	Set a colour value from Hue, Saturation and Brightness.
-		 *
-		 * @param hue				Hue value, scaled to the [0,1] range.
-		 * @param saturation		Saturation level, [0,1].
-		 * @param brightness		Brightness level, [0,1].
-		 */
-		void setHSB(float hue, float saturation, float brightness);
-
-		/** 
-		 * @brief Convert the current color to Hue, Saturation and Brightness values. 
-		 * 
-		 * @param hue			Output hue value, scaled to the [0,1] range.
-		 * @param saturation	Output saturation level, [0,1].
-		 * @param brightness	Output brightness level, [0,1].
-		 */
-		void getHSB(float* hue, float* saturation, float* brightness) const;
-
-		float r, g, b, a;
-    };
-
-	BS_ALLOW_MEMCPY_SERIALIZATION(Color);
-}
-
-/**
- * @brief	Hash value generator for Color.
- */
-template<> 
-struct std::hash<BansheeEngine::Color>
-{
-	size_t operator()(const BansheeEngine::Color& color) const
-	{
-		size_t hash = 0;
-		BansheeEngine::hash_combine(hash, color.r);
-		BansheeEngine::hash_combine(hash, color.g);
-		BansheeEngine::hash_combine(hash, color.b);
-		BansheeEngine::hash_combine(hash, color.a);
-
-		return hash;
-	}
-};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+/** @addtogroup Image
+ *  @{
+ */
+
+namespace BansheeEngine 
+{
+    typedef UINT32 RGBA;
+    typedef UINT32 ARGB;
+    typedef UINT32 ABGR;
+	typedef UINT32 BGRA;
+
+	/** 
+	 * Color represented as 4 components, each being a floating point value ranging from 0 to 1. Color components are 
+	 * red, green, blue and alpha.
+	 */
+    class BS_UTILITY_EXPORT Color
+    {
+    public:
+        static const Color ZERO;
+        static const Color Black;
+        static const Color White;
+        static const Color Red;
+        static const Color Green;
+        static const Color Blue;
+
+	    explicit Color(float red = 1.0f, float green = 1.0f,
+				    float blue = 1.0f, float alpha = 1.0f ) 
+					:r(red), g(green), b(blue), a(alpha)
+        { }
+
+	    bool operator==(const Color& rhs) const;
+	    bool operator!=(const Color& rhs) const;
+
+	    RGBA getAsRGBA(void) const;
+	    ARGB getAsARGB(void) const;
+		BGRA getAsBGRA(void) const;
+	    ABGR getAsABGR(void) const;
+
+        void setAsRGBA(const RGBA val);
+        void setAsARGB(const ARGB val);
+		void setAsBGRA(const BGRA val);
+        void setAsABGR(const ABGR val);
+
+		/** Clamps colour value to the range [0, 1]. */
+        void saturate()
+        {
+            if (r < 0)
+                r = 0;
+            else if (r > 1)
+                r = 1;
+
+            if (g < 0)
+                g = 0;
+            else if (g > 1)
+                g = 1;
+
+            if (b < 0)
+                b = 0;
+            else if (b > 1)
+                b = 1;
+
+            if (a < 0)
+                a = 0;
+            else if (a > 1)
+                a = 1;
+        }
+
+		/** Clamps colour value to the range [0, 1]. Returned saturated color as a copy. */
+        Color saturateCopy() const
+        {
+            Color ret = *this;
+            ret.saturate();
+            return ret;
+        }
+
+		float operator[] (const UINT32 i) const
+		{
+			assert(i < 4);
+
+			return *(&r+i);
+		}
+
+		float& operator[] (const UINT32 i)
+		{
+			assert(i < 4);
+
+			return *(&r+i);
+		}
+
+		/** Pointer accessor for direct copying. */
+		float* ptr()
+		{
+			return &r;
+		}
+
+		/** Pointer accessor for direct copying. */
+		const float* ptr() const
+		{
+			return &r;
+		}
+
+        Color operator+ (const Color& rhs) const
+        {
+            Color kSum;
+
+            kSum.r = r + rhs.r;
+            kSum.g = g + rhs.g;
+            kSum.b = b + rhs.b;
+            kSum.a = a + rhs.a;
+
+            return kSum;
+        }
+
+        Color operator- ( const Color& rhs) const
+        {
+            Color kDiff;
+
+            kDiff.r = r - rhs.r;
+            kDiff.g = g - rhs.g;
+            kDiff.b = b - rhs.b;
+            kDiff.a = a - rhs.a;
+
+            return kDiff;
+        }
+
+        Color operator* (const float rhs) const
+        {
+            Color kProd;
+
+            kProd.r = rhs*r;
+            kProd.g = rhs*g;
+            kProd.b = rhs*b;
+            kProd.a = rhs*a;
+
+            return kProd;
+        }
+
+        Color operator* (const Color& rhs) const
+        {
+            Color kProd;
+
+            kProd.r = rhs.r * r;
+            kProd.g = rhs.g * g;
+            kProd.b = rhs.b * b;
+            kProd.a = rhs.a * a;
+
+            return kProd;
+        }
+
+        Color operator/ (const Color& rhs) const
+        {
+            Color kProd;
+
+            kProd.r = rhs.r / r;
+            kProd.g = rhs.g / g;
+            kProd.b = rhs.b / b;
+            kProd.a = rhs.a / a;
+
+            return kProd;
+        }
+
+        Color operator/ (const float rhs) const
+        {
+            assert(rhs != 0.0f);
+
+            Color kDiv;
+
+            float fInv = 1.0f / rhs;
+            kDiv.r = r * fInv;
+            kDiv.g = g * fInv;
+            kDiv.b = b * fInv;
+            kDiv.a = a * fInv;
+
+            return kDiv;
+        }
+
+        friend Color operator* (const float lhs, const Color& rhs)
+        {
+            Color result;
+
+            result.r = lhs * rhs.r;
+            result.g = lhs * rhs.g;
+            result.b = lhs * rhs.b;
+            result.a = lhs * rhs.a;
+
+            return result;
+        }
+
+        Color& operator+= (const Color& rhs)
+        {
+            r += rhs.r;
+            g += rhs.g;
+            b += rhs.b;
+            a += rhs.a;
+
+            return *this;
+        }
+
+        Color& operator-= (const Color& rhs)
+        {
+            r -= rhs.r;
+            g -= rhs.g;
+            b -= rhs.b;
+            a -= rhs.a;
+
+            return *this;
+        }
+
+        Color& operator*= (const float rhs)
+        {
+            r *= rhs;
+            g *= rhs;
+            b *= rhs;
+            a *= rhs;
+
+            return *this;
+        }
+
+        Color& operator/= (const float rhs)
+        {
+            assert(rhs != 0.0f);
+
+            float fInv = 1.0f / rhs;
+
+            r *= rhs;
+            g *= rhs;
+            b *= rhs;
+            a *= rhs;
+
+            return *this;
+        }
+
+		/** 
+		 * Set a colour value from Hue, Saturation and Brightness.
+		 *
+		 * @param[in] hue			Hue value, scaled to the [0,1] range.
+		 * @param[in] saturation	Saturation level, [0,1].
+		 * @param[in] brightness	Brightness level, [0,1].
+		 */
+		void setHSB(float hue, float saturation, float brightness);
+
+		/** 
+		 * Convert the current color to Hue, Saturation and Brightness values. 
+		 * 
+		 * @param[in] hue			Output hue value, scaled to the [0,1] range.
+		 * @param[in] saturation	Output saturation level, [0,1].
+		 * @param[in] brightness	Output brightness level, [0,1].
+		 */
+		void getHSB(float* hue, float* saturation, float* brightness) const;
+
+		float r, g, b, a;
+    };
+
+	/** @cond SPECIALIZATIONS */
+	BS_ALLOW_MEMCPY_SERIALIZATION(Color);
+	/** @endcond */
+}
+
+/** @cond SPECIALIZATIONS */
+
+/** Hash value generator for Color. */
+template<> 
+struct std::hash<BansheeEngine::Color>
+{
+	size_t operator()(const BansheeEngine::Color& color) const
+	{
+		size_t hash = 0;
+		BansheeEngine::hash_combine(hash, color.r);
+		BansheeEngine::hash_combine(hash, color.g);
+		BansheeEngine::hash_combine(hash, color.b);
+		BansheeEngine::hash_combine(hash, color.a);
+
+		return hash;
+	}
+};
+
+/** @endcond */
+/** @} */

+ 28 - 33
BansheeUtility/Include/BsCrashHandler.h

@@ -5,9 +5,12 @@
 
 namespace BansheeEngine
 {
-	/**
-	 * @brief	Saves crash data and notifies the user when a crash occurs.
+	/** @cond INTERNAL */
+	/** @addtogroup Error
+	 *  @{
 	 */
+
+	/** Saves crash data and notifies the user when a crash occurs. */
 	// TODO - Crashes are reported in the same process as the main application. This can be a problem if the crash was caused
 	// by heap. Any further use of the heap by the reporting methods will cause a silent crash, failing to log it. A more appropriate
 	// way of doing it should be to resume another process to actually handle the crash.
@@ -17,60 +20,51 @@ namespace BansheeEngine
 		CrashHandler();
 		~CrashHandler();
 
-		/**
-		 * @brief	Constructs and starts the module.
-		 */
+		/** Constructs and starts the module. */
 		static void startUp() { _instance() = bs_new<CrashHandler>(); }
 
-		/**
-		 * @brief	Shuts down this module and frees any resources it is using.
-		 */
+		/** Shuts down this module and frees any resources it is using. */
 		static void shutDown() { bs_delete(_instance()); }
 
-		/**
-		 * @brief	Returns a reference to the module instance.
-		 */
+		/** Returns a reference to the module instance. */
 		static CrashHandler& instance() { return *_instance(); }
 
 		/**
-		 * @brief	Records a crash with a custom error message.
+		 * Records a crash with a custom error message.
 		 * 			
-		 * @param	type		Type of the crash that occurred. e.g. "InvalidParameter".
-		 * @param	description	More detailed description of the issue that caused the crash.
-		 * @param	function	Optional name of the function where the error occurred.
-		 * @param	file		Optional name of the source code file in which the code that crashed the program exists.
-		 * @param	line		Optional source code line at which the crash was triggered at.
+		 * @param[in]	type		Type of the crash that occurred. e.g. "InvalidParameter".
+		 * @param[in]	description	More detailed description of the issue that caused the crash.
+		 * @param[in]	function	Optional name of the function where the error occurred.
+		 * @param[in]	file		Optional name of the source code file in which the code that crashed the program exists.
+		 * @param[in]	line		Optional source code line at which the crash was triggered at.
 		 */
 		void reportCrash(const String& type, const String& description, const String& function = StringUtil::BLANK,
 			const String& file = StringUtil::BLANK, UINT32 line = 0) const;
 
 #if BS_PLATFORM == BS_PLATFORM_WIN32
 		/**
-		 * @brief	Records a crash resulting from a Windows-specific SEH exception. 
+		 * Records a crash resulting from a Windows-specific SEH exception. 
 		 * 			
-		 * @param	exceptionData	Exception data returned from GetExceptionInformation()
-		 * 							
-		 * @returns	Code that signals the __except exception handler on how to proceed.
+		 * @param[in]	exceptionData	Exception data returned from GetExceptionInformation()
+		 * @return						Code that signals the __except exception handler on how to proceed.
+		 *
+		 * @note	Available in Windows builds only.
 		 */
 		int reportCrash(void* exceptionData) const;
 #endif
 
 		/**
-		 * @brief	Returns a string containing a current stack trace. If function can be found in the symbol
-		 * 			table its readable name will be present in the stack trace, otherwise just its address.
+		 * Returns a string containing a current stack trace. If function can be found in the symbol table its readable 
+		 * name will be present in the stack trace, otherwise just its address.
 		 * 						
-		 * @returns	String containing the call stack with each function on its own line.
+		 * @return	String containing the call stack with each function on its own line.
 		 */
 		static String getStackTrace();
 	private:
-		/**
-		 * @brief	Returns path to the folder into which to store the crash reports.
-		 */
+		/** Returns path to the folder into which to store the crash reports. */
 		Path getCrashFolder() const;
 
-		/**
-		 * @brief	Returns a singleton instance of this module. 
-		 */
+		/** Returns a singleton instance of this module. */
 		static CrashHandler*& _instance() { static CrashHandler* inst = nullptr; return inst; }
 
 		static const wchar_t* CrashReportFolder;
@@ -80,8 +74,9 @@ namespace BansheeEngine
 		Data* m;
 	};
 
-	/**
-	 * @brief	Returns an instance of the CrashHandler.
-	 */
+	/** Easier way of accessing the CrashHandler. */
 	BS_UTILITY_EXPORT CrashHandler& gCrashHandler();
+
+	/** @} */
+	/** @endcond */
 }

+ 278 - 332
BansheeUtility/Include/BsDataStream.h

@@ -1,332 +1,278 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include <istream>
-
-namespace BansheeEngine 
-{
-	/**
-	 * @brief	Supported encoding types for strings.
-	 */
-	enum class StringEncoding
-	{
-		UTF8 = 1,
-		UTF16 = 2
-	};
-
-	/**
-	 * @brief	General purpose class used for encapsulating the reading and writing of data from
-	 *			and to various sources using a common interface.
-	 */
-	class BS_UTILITY_EXPORT DataStream
-	{
-	public:
-		enum AccessMode
-		{
-			READ = 1, 
-			WRITE = 2
-		};
-
-	public:
-        /**
-         * @brief	Creates an unnamed stream.
-         */
-        DataStream(UINT16 accessMode = READ) 
-			:mSize(0), mAccess(accessMode) 
-		{ }
-
-        /**
-         * @brief	Creates a named stream.
-         */
-		DataStream(const String& name, UINT16 accessMode = READ) 
-			:mName(name), mSize(0), mAccess(accessMode) {}
-
-		virtual ~DataStream() {}
-
-		const String& getName(void) { return mName; }
-		UINT16 getAccessMode() const { return mAccess; }
-
-		virtual bool isReadable() const { return (mAccess & READ) != 0; }
-		virtual bool isWriteable() const { return (mAccess & WRITE) != 0; }
-       
-        /**
-         * @brief	Reads data from the buffer and copies it to the specified value.
-         */
-        template<typename T> DataStream& operator>>(T& val);
-
-		/**
-		 * @brief	Read the requisite number of bytes from the stream,
-		 *			stopping at the end of the file.
-		 *
-		 * @param	buf		Pre-allocated buffer to read the data into.
-		 * @param	count	Number of bytes to read.
-		 *
-		 * @return	Number of bytes actually read.
-		 * 			
-		 * @note	Stream must be created with READ access mode.
-		 */
-		virtual size_t read(void* buf, size_t count) = 0;
-
-		/**
-		 * @brief	Write the requisite number of bytes to the stream.
-		 *
-		 * @param	buf		Buffer containing bytes to write.
-		 * @param	count	Number of bytes to write.
-		 *
-		 * @return	Number of bytes actually written.
-		 * 			
-		 * @note	Stream must be created with WRITE access mode.
-		 */
-		virtual size_t write(const void* buf, size_t count) { return 0; }
-
-		/**
-		 * @brief	Writes the provided narrow string to the steam. String is convered to the required encoding before 
-		 * 			being written.
-		 * 			
-		 * @param	string		String containing narrow characters to write, encoded as UTF8.
-		 * @param	encoding	Encoding to convert the string to before writing.
-		 */
-		virtual void writeString(const String& string, StringEncoding encoding = StringEncoding::UTF8);
-
-		/**
-		 * @brief	Writes the provided wide string to the steam. String is convered to the required encoding before 
-		 * 			being written.
-		 * 			
-		 * @param	string		String containing wide characters to write, encoded as specified by platform for 
-		 * 						wide characters.
-		 * @param	encoding	Encoding to convert the string to before writing.
-		 */
-		virtual void writeString(const WString& string, StringEncoding encoding = StringEncoding::UTF16);
-
-	    /**
-	     * @brief	Returns a string containing the entire stream.
-	     *
-		 * @note	This is a convenience method for text streams only, allowing you to
-		 *			retrieve a String object containing all the data in the stream.
-		 *			
-		 * @returns	String data encoded as UTF-8. 
-	     */
-	    virtual String getAsString();
-
-	    /**
-	     * @brief	Returns a wide string containing the entire stream.
-	     *
-		 * @note	This is a convenience method for text streams only, allowing you to
-		 *			retrieve a WString object containing all the data in the stream.
-		 *			
-		 * @returns	Wide string encoded as specified by current platform.
-	     */
-	    virtual WString getAsWString();
-
-		/**
-		 * @brief	Skip a defined number of bytes. This can also be a negative value, in which case
-		 *			the file pointer rewinds a defined number of bytes.
-		 */
-		virtual void skip(size_t count) = 0;
-	
-	    /**
-	     * @brief	Repositions the read point to a specified byte.
-	     */
-	    virtual void seek(size_t pos) = 0;
-		
-	    /**
-	     * @brief	Returns the current byte offset from beginning
-	     */
-	    virtual size_t tell() const = 0;
-
-	    /**
-	     * @brief	Returns true if the stream has reached the end.
-	     */
-	    virtual bool eof() const = 0;
-
-        /**
-		 * @brief	Returns the total size of the data to be read from the stream,
-		 *			or 0 if this is indeterminate for this stream.
-         */
-        size_t size() const { return mSize; }
-
-        /**
-         * @brief	Close the stream. This makes further operations invalid.
-         */
-        virtual void close() = 0;
-		
-	protected:
-		static const UINT32 StreamTempSize;
-
-		String mName;		
-        size_t mSize;
-		UINT16 mAccess;
-	};
-
-	/**
-	 * @brief	Data stream for handling data from memory.
-	 */
-	class BS_UTILITY_EXPORT MemoryDataStream : public DataStream
-	{		
-	public:
-		/**
-		 * @brief	Wrap an existing memory chunk in a stream.
-		 *
-		 * @param 	memory		Memory to wrap the data stream around.
-		 * @param	size		Size of the memory chunk in bytes.
-		 */
-		MemoryDataStream(void* memory, size_t size);
-		
-		/**
-		 * @brief	Create a stream which pre-buffers the contents of another stream. Data
-		 * 			from the other buffer will be entirely read and stored in an internal buffer.
-		 *
-		 * @param [in]	sourceStream		Stream to read data from.
-		 */
-		MemoryDataStream(DataStream& sourceStream);
-		
-		/**
-		 * @brief	Create a stream which pre-buffers the contents of another stream. Data
-		 * 			from the other buffer will be entirely read and stored in an internal buffer.
-		 *
-		 * @param [in]	sourceStream		Stream to read data from.
-		 */
-		MemoryDataStream(const DataStreamPtr& sourceStream);
-
-		~MemoryDataStream();
-
-		/**
-		 * @brief	Get a pointer to the start of the memory block this stream holds.
-		 */
-		UINT8* getPtr() { return mData; }
-		
-		/**
-		 * @brief	Get a pointer to the current position in the memory block this stream holds.
-		 */
-		UINT8* getCurrentPtr() { return mPos; }
-		
-        /** 
-		 * @copydoc DataStream::read
-         */
-		size_t read(void* buf, size_t count) override;
-
-        /** 
-		 * @copydoc DataStream::write
-         */
-		size_t write(const void* buf, size_t count) override;
-
-        /** 
-		 * @copydoc DataStream::skip
-         */
-		void skip(size_t count) override;
-	
-        /** 
-		 * @copydoc DataStream::seek
-         */
-		void seek(size_t pos) override;
-		
-        /** 
-		 * @copydoc DataStream::tell
-         */
-		size_t tell() const override;
-
-        /** 
-		 * @copydoc DataStream::eof
-         */
-		bool eof() const override;
-
-        /** 
-		 * @copydoc DataStream::close
-         */
-		void close() override;
-
-	protected:
-		UINT8* mData;
-		UINT8* mPos;
-		UINT8* mEnd;
-
-		bool mFreeOnClose;
-	};
-
-	/**
-	 * @brief	Data stream for handling data from standard streams.
-	 */
-	class BS_UTILITY_EXPORT FileDataStream : public DataStream
-	{
-	public:
-		/**
-		 * @brief	Construct read-only stream from an standard stream.
-		 * 			
-		 *			If "freeOnClose" is true, the STL stream will be freed once the data stream is closed.
-		 */
-		FileDataStream(std::shared_ptr<std::ifstream> s, bool freeOnClose = true);
-
-		/**
-		 * @brief	Construct read-write stream from an standard stream.
-		 * 			
-		 *			If "freeOnClose" is true, the STL stream will be freed once the data stream is closed.
-		 */
-		FileDataStream(std::shared_ptr<std::fstream> s, bool freeOnClose = true);
-
-		/**
-		 * @brief	Construct read-only stream from an standard stream, and tell it the size.
-		 * 			
-		 *			Size parameter allows you to specify the size without requiring us to seek to the end of the stream
-		 *			to find the size.
-		 *			
-		 *			If "freeOnClose" is true, the STL stream will be freed once the data stream is closed.
-		 */
-		FileDataStream(std::shared_ptr<std::ifstream> s, size_t size, bool freeOnClose = true);
-
-		/**
-		 * @brief	Construct read-write stream from an standard stream, and tell it the size.
-		 * 			
-		 *			Size parameter allows you to specify the size without requiring us to seek to the end of the stream
-		 *			to find the size.
-		 *			
-		 *			If "freeOnClose" is true, the STL stream will be freed once the data stream is closed.
-		 */
-		FileDataStream(std::shared_ptr<std::fstream> s, size_t size, bool freeOnClose = true);
-
-		~FileDataStream();
-
-        /** 
-		 * @copydoc DataStream::read
-         */
-		size_t read(void* buf, size_t count) override;
-
-        /** 
-		 * @copydoc DataStream::write
-         */
-		size_t write(const void* buf, size_t count) override;
-
-        /** 
-		 * @copydoc DataStream::skip
-         */
-		void skip(size_t count) override;
-	
-        /** 
-		 * @copydoc DataStream::seek
-         */
-		void seek(size_t pos) override;
-
-        /** 
-		 * @copydoc DataStream::tell
-         */
-		size_t tell() const override;
-
-        /** 
-		 * @copydoc DataStream::eof
-         */
-		bool eof() const override;
-
-        /** 
-		 * @copydoc DataStream::close
-         */
-		void close() override;
-
-	protected:
-		std::shared_ptr<std::istream> mpInStream;
-		std::shared_ptr<std::ifstream> mpFStreamRO;
-		std::shared_ptr<std::fstream> mpFStream;
-		bool mFreeOnClose;	
-
-		void determineAccess();
-	};
-}
-
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include <istream>
+
+namespace BansheeEngine 
+{
+	/** @addtogroup Filesystem
+	 *  @{
+	 */
+
+	/** Supported encoding types for strings. */
+	enum class StringEncoding
+	{
+		UTF8 = 1,
+		UTF16 = 2
+	};
+
+	/**
+	 * General purpose class used for encapsulating the reading and writing of data from and to various sources using a 
+	 * common interface.
+	 */
+	class BS_UTILITY_EXPORT DataStream
+	{
+	public:
+		enum AccessMode
+		{
+			READ = 1, 
+			WRITE = 2
+		};
+
+	public:
+        /** Creates an unnamed stream. */
+        DataStream(UINT16 accessMode = READ) 
+			:mSize(0), mAccess(accessMode) 
+		{ }
+
+        /** Creates a named stream. */
+		DataStream(const String& name, UINT16 accessMode = READ) 
+			:mName(name), mSize(0), mAccess(accessMode) {}
+
+		virtual ~DataStream() {}
+
+		const String& getName(void) { return mName; }
+		UINT16 getAccessMode() const { return mAccess; }
+
+		virtual bool isReadable() const { return (mAccess & READ) != 0; }
+		virtual bool isWriteable() const { return (mAccess & WRITE) != 0; }
+       
+        /** Reads data from the buffer and copies it to the specified value. */
+        template<typename T> DataStream& operator>>(T& val);
+
+		/**
+		 * Read the requisite number of bytes from the stream, stopping at the end of the file.
+		 *
+		 * @param[in]	buf		Pre-allocated buffer to read the data into.
+		 * @param[in]	count	Number of bytes to read.
+		 * @return				Number of bytes actually read.
+		 * 			
+		 * @note	Stream must be created with READ access mode.
+		 */
+		virtual size_t read(void* buf, size_t count) = 0;
+
+		/**
+		 * Write the requisite number of bytes to the stream.
+		 *
+		 * @param[in]	buf		Buffer containing bytes to write.
+		 * @param[in]	count	Number of bytes to write.
+		 * @return				Number of bytes actually written.
+		 * 			
+		 * @note	Stream must be created with WRITE access mode.
+		 */
+		virtual size_t write(const void* buf, size_t count) { return 0; }
+
+		/**
+		 * Writes the provided narrow string to the steam. String is convered to the required encoding before being written.
+		 * 			
+		 * @param[in]	string		String containing narrow characters to write, encoded as UTF8.
+		 * @param[in]	encoding	Encoding to convert the string to before writing.
+		 */
+		virtual void writeString(const String& string, StringEncoding encoding = StringEncoding::UTF8);
+
+		/**
+		 * Writes the provided wide string to the steam. String is convered to the required encoding before being written.
+		 * 			
+		 * @param[in]	string		String containing wide characters to write, encoded as specified by platform for 
+		 * 							wide characters.
+		 * @param[in]	encoding	Encoding to convert the string to before writing.
+		 */
+		virtual void writeString(const WString& string, StringEncoding encoding = StringEncoding::UTF16);
+
+	    /**
+	     * Returns a string containing the entire stream.
+	     *
+		 * @return	String data encoded as UTF-8. 
+		 *
+		 * @note	This is a convenience method for text streams only, allowing you to retrieve a String object containing 
+		 *			all the data in the stream.
+	     */
+	    virtual String getAsString();
+
+	    /**
+	     * Returns a wide string containing the entire stream.
+	     *
+		 * @return	Wide string encoded as specified by current platform.
+		 *
+		 * @note	This is a convenience method for text streams only, allowing you to retrieve a WString object 
+		 *			containing all the data in the stream.
+	     */
+	    virtual WString getAsWString();
+
+		/**
+		 * Skip a defined number of bytes. This can also be a negative value, in which case the file pointer rewinds a 
+		 * defined number of bytes.
+		 */
+		virtual void skip(size_t count) = 0;
+	
+	    /** Repositions the read point to a specified byte. */
+	    virtual void seek(size_t pos) = 0;
+		
+	    /** Returns the current byte offset from beginning. */
+	    virtual size_t tell() const = 0;
+
+	    /** Returns true if the stream has reached the end. */
+	    virtual bool eof() const = 0;
+
+        /** Returns the total size of the data to be read from the stream, or 0 if this is indeterminate for this stream. */
+        size_t size() const { return mSize; }
+
+        /** Close the stream. This makes further operations invalid. */
+        virtual void close() = 0;
+		
+	protected:
+		static const UINT32 StreamTempSize;
+
+		String mName;		
+        size_t mSize;
+		UINT16 mAccess;
+	};
+
+	/** Data stream for handling data from memory. */
+	class BS_UTILITY_EXPORT MemoryDataStream : public DataStream
+	{		
+	public:
+		/**
+		 * Wrap an existing memory chunk in a stream.
+		 *
+		 * @param[in] 	memory		Memory to wrap the data stream around.
+		 * @param[in]	size		Size of the memory chunk in bytes.
+		 */
+		MemoryDataStream(void* memory, size_t size);
+		
+		/**
+		 * Create a stream which pre-buffers the contents of another stream. Data from the other buffer will be entirely 
+		 * read and stored in an internal buffer.
+		 *
+		 * @param[in]	sourceStream		Stream to read data from.
+		 */
+		MemoryDataStream(DataStream& sourceStream);
+		
+		/**
+		 * Create a stream which pre-buffers the contents of another stream. Data from the other buffer will be entirely 
+		 * read and stored in an internal buffer.
+		 *
+		 * @param[in]	sourceStream		Stream to read data from.
+		 */
+		MemoryDataStream(const DataStreamPtr& sourceStream);
+
+		~MemoryDataStream();
+
+		/** Get a pointer to the start of the memory block this stream holds. */
+		UINT8* getPtr() const { return mData; }
+		
+		/** Get a pointer to the current position in the memory block this stream holds. */
+		UINT8* getCurrentPtr() const { return mPos; }
+		
+        /** @copydoc DataStream::read */
+		size_t read(void* buf, size_t count) override;
+
+        /** @copydoc DataStream::write */
+		size_t write(const void* buf, size_t count) override;
+
+        /** @copydoc DataStream::skip */
+		void skip(size_t count) override;
+	
+        /** @copydoc DataStream::seek */
+		void seek(size_t pos) override;
+		
+        /** @copydoc DataStream::tell */
+		size_t tell() const override;
+
+        /** @copydoc DataStream::eof */
+		bool eof() const override;
+
+        /** @copydoc DataStream::close */
+		void close() override;
+
+	protected:
+		UINT8* mData;
+		UINT8* mPos;
+		UINT8* mEnd;
+
+		bool mFreeOnClose;
+	};
+
+	/** Data stream for handling data from standard streams. */
+	class BS_UTILITY_EXPORT FileDataStream : public DataStream
+	{
+	public:
+		/**
+		 * Construct read-only stream from an standard stream.
+		 *
+		 * If @p freeOnClose is true, the STL stream will be freed once the data stream is closed.
+		 */
+		FileDataStream(std::shared_ptr<std::ifstream> s, bool freeOnClose = true);
+
+		/**
+		 * Construct read-write stream from an standard stream.
+		 * 			
+		 * If @p freeOnClose is true, the STL stream will be freed once the data stream is closed.
+		 */
+		FileDataStream(std::shared_ptr<std::fstream> s, bool freeOnClose = true);
+
+		/**
+		 * Construct read-only stream from an standard stream, and tell it the size.
+		 * 			
+		 * Size parameter allows you to specify the size without requiring us to seek to the end of the stream to find 
+		 * the size.
+		 *			
+		 * If @p freeOnClose is true, the STL stream will be freed once the data stream is closed.
+		 */
+		FileDataStream(std::shared_ptr<std::ifstream> s, size_t size, bool freeOnClose = true);
+
+		/**
+		 * Construct read-write stream from an standard stream, and tell it the size.
+		 * 			
+		 * Size parameter allows you to specify the size without requiring us to seek to the end of the stream to find 
+		 * the size.
+		 *			
+		 * If @p freeOnClose is true, the STL stream will be freed once the data stream is closed.
+		 */
+		FileDataStream(std::shared_ptr<std::fstream> s, size_t size, bool freeOnClose = true);
+
+		~FileDataStream();
+
+        /** @copydoc DataStream::read */
+		size_t read(void* buf, size_t count) override;
+
+        /** @copydoc DataStream::write */
+		size_t write(const void* buf, size_t count) override;
+
+        /** @copydoc DataStream::skip */
+		void skip(size_t count) override;
+	
+        /** @copydoc DataStream::seek */
+		void seek(size_t pos) override;
+
+        /** @copydoc DataStream::tell */
+		size_t tell() const override;
+
+        /** @copydoc DataStream::eof */
+		bool eof() const override;
+
+        /** @copydoc DataStream::close */
+		void close() override;
+
+	protected:
+		std::shared_ptr<std::istream> mpInStream;
+		std::shared_ptr<std::ifstream> mpFStreamRO;
+		std::shared_ptr<std::fstream> mpFStream;
+		bool mFreeOnClose;	
+
+		void determineAccess();
+	};
+
+	/** @} */
+}
+

+ 71 - 79
BansheeUtility/Include/BsDynLib.h

@@ -1,79 +1,71 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-#if BS_PLATFORM == BS_PLATFORM_WIN32
-#    define DYNLIB_HANDLE hInstance
-#    define DYNLIB_LOAD( a ) LoadLibraryEx( a, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
-#    define DYNLIB_GETSYM( a, b ) GetProcAddress( a, b )
-#    define DYNLIB_UNLOAD( a ) !FreeLibrary( a )
-
-struct HINSTANCE__;
-typedef struct HINSTANCE__* hInstance;
-
-#elif BS_PLATFORM == BS_PLATFORM_LINUX
-#    define DYNLIB_HANDLE void*
-#    define DYNLIB_LOAD( a ) dlopen( a, RTLD_LAZY | RTLD_GLOBAL)
-#    define DYNLIB_GETSYM( a, b ) dlsym( a, b )
-#    define DYNLIB_UNLOAD( a ) dlclose( a )
-
-#elif BS_PLATFORM == BS_PLATFORM_APPLE
-#    define DYNLIB_HANDLE void*
-#    define DYNLIB_LOAD( a ) mac_loadDylib( a )
-#    define DYNLIB_GETSYM( a, b ) dlsym( a, b )
-#    define DYNLIB_UNLOAD( a ) dlclose( a )
-
-#endif
-
-namespace BansheeEngine 
-{
-    /** 
-	 * @brief	Class that holds data about a dynamic library.
-	 */
-	class BS_UTILITY_EXPORT DynLib
-    {
-    public:
-		/**
-		 * @brief	Constructs the dynamic library object and loads the library with the specified name.
-		 */
-		DynLib(const String& name);
-        ~DynLib();
-
-		/** 
-		 * @brief	Loads the library. Does nothing if library is already loaded.
-		 */
-        void load();
-
-		/**
-		 * @brief	Unloads the library. Does nothing if library is not loaded.
-		 */
-        void unload();
-
-		/** 
-		 * @brief	Get the name of the library.
-		 */
-		const String& getName() const { return mName; }
-
-        /**
-		 * @brief	Returns the address of the given symbol from the loaded library.
-		 *
-		 * @param strName	The name of the symbol to search for.
-		 *
-         * @returns		If the function succeeds, the returned value is a handle to
-		 *				the symbol. Otherwise null.
-         */
-        void* getSymbol(const String& strName) const;
-
-	protected:
-		friend class DynLibManager;
-
-		/** 
-		 * @brief	Gets the last loading error.
-		 */
-        String dynlibError();
-
-    protected:
-		String mName;
-        DYNLIB_HANDLE m_hInst; // Handle to the loaded library.
-    };
-}
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+/** @addtogroup General
+ *  @{
+ */
+
+#if BS_PLATFORM == BS_PLATFORM_WIN32
+#    define DYNLIB_HANDLE hInstance
+#    define DYNLIB_LOAD( a ) LoadLibraryEx( a, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
+#    define DYNLIB_GETSYM( a, b ) GetProcAddress( a, b )
+#    define DYNLIB_UNLOAD( a ) !FreeLibrary( a )
+
+struct HINSTANCE__;
+typedef struct HINSTANCE__* hInstance;
+
+#elif BS_PLATFORM == BS_PLATFORM_LINUX
+#    define DYNLIB_HANDLE void*
+#    define DYNLIB_LOAD( a ) dlopen( a, RTLD_LAZY | RTLD_GLOBAL)
+#    define DYNLIB_GETSYM( a, b ) dlsym( a, b )
+#    define DYNLIB_UNLOAD( a ) dlclose( a )
+
+#elif BS_PLATFORM == BS_PLATFORM_APPLE
+#    define DYNLIB_HANDLE void*
+#    define DYNLIB_LOAD( a ) mac_loadDylib( a )
+#    define DYNLIB_GETSYM( a, b ) dlsym( a, b )
+#    define DYNLIB_UNLOAD( a ) dlclose( a )
+
+#endif
+
+namespace BansheeEngine 
+{
+    /** Class that holds data about a dynamic library. */
+	class BS_UTILITY_EXPORT DynLib
+    {
+    public:
+		/** Constructs the dynamic library object and loads the library with the specified name. */
+		DynLib(const String& name);
+        ~DynLib();
+
+		/** Loads the library. Does nothing if library is already loaded. */
+        void load();
+
+		/** Unloads the library. Does nothing if library is not loaded. */
+        void unload();
+
+		/** 	Get the name of the library. */
+		const String& getName() const { return mName; }
+
+        /**
+		 * Returns the address of the given symbol from the loaded library.
+		 *
+		 * @param[in] strName	The name of the symbol to search for.
+         * @return				If the function succeeds, the returned value is a handle to the symbol. Otherwise null.
+         */
+        void* getSymbol(const String& strName) const;
+
+	protected:
+		friend class DynLibManager;
+
+		/** Gets the last loading error. */
+        String dynlibError();
+
+    protected:
+		String mName;
+        DYNLIB_HANDLE m_hInst; // Handle to the loaded library.
+    };
+}
+
+/** @} */

+ 41 - 37
BansheeUtility/Include/BsDynLibManager.h

@@ -1,38 +1,42 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsModule.h"
-
-namespace BansheeEngine 
-{
-    /**
-	 * @brief	This manager keeps a track of all the open dynamic-loading
-	 *			libraries, opens them and returns references to already-open
-	 *			libraries.
-	 *			
-	 * @note	Not thread safe.
-     */
-    class BS_UTILITY_EXPORT DynLibManager : public Module<DynLibManager>
-    {
-    public:
-        DynLibManager();
-        virtual ~DynLibManager();
-
-        /**
-         * @brief	Loads the given file as a dynamic library.
-         *
-         * @param	filename	The name of the library. The extension can be omitted
-         */
-        DynLib* load(const String& filename);
-
-		/**
-		 * @brief	Unloads the given library.
-		 */
-		void unload(DynLib* lib);
-
-	protected:
-		Map<String, DynLib*> mLoadedLibraries;
-    };
-
-	BS_UTILITY_EXPORT DynLibManager& gDynLibManager();
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+
+namespace BansheeEngine 
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+    /**
+	 * This manager keeps a track of all the open dynamic-loading libraries, opens them and returns references to 
+	 * already-open libraries.
+	 *			
+	 * @note	Not thread safe.
+     */
+    class BS_UTILITY_EXPORT DynLibManager : public Module<DynLibManager>
+    {
+    public:
+        DynLibManager();
+        virtual ~DynLibManager();
+
+        /**
+         * Loads the given file as a dynamic library.
+         *
+         * @param[in]	filename	The name of the library. The extension can be omitted.
+         */
+        DynLib* load(const String& filename);
+
+		/** Unloads the given library. */
+		void unload(DynLib* lib);
+
+	protected:
+		Map<String, DynLib*> mLoadedLibraries;
+    };
+
+	/** Easy way of accessing DynLibManager. */
+	BS_UTILITY_EXPORT DynLibManager& gDynLibManager();
+
+	/** @} */
 }

+ 334 - 357
BansheeUtility/Include/BsEvent.h

@@ -1,357 +1,334 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Data common to all event connections.
-	 */
-	class BaseConnectionData
-	{
-	public:
-		BaseConnectionData()
-			:prev(nullptr), next(nullptr), isActive(true),
-			handleLinks(0)
-		{
-			
-		}
-
-		virtual ~BaseConnectionData()
-		{
-			assert(!handleLinks && !isActive);
-		}
-
-		virtual void deactivate()
-		{
-			isActive = false;
-		}
-
-		BaseConnectionData* prev;
-		BaseConnectionData* next;
-		bool isActive;
-		UINT32 handleLinks;
-	};
-
-	/**
-	 * @brief	Internal data for an Event, storing all connections.
-	 */
-	struct EventInternalData
-	{
-		EventInternalData()
-			:mConnections(nullptr), mFreeConnections(nullptr)
-		{ }
-
-		~EventInternalData()
-		{
-			BaseConnectionData* conn = mConnections;
-			while (conn != nullptr)
-			{
-				BaseConnectionData* next = conn->next;
-				bs_free(conn);
-
-				conn = next;
-			}
-
-			conn = mFreeConnections;
-			while (conn != nullptr)
-			{
-				BaseConnectionData* next = conn->next;
-				bs_free(conn);
-
-				conn = next;
-			}
-		}
-
-		/**
-		 * @brief	Disconnects the connection with the specified data,
-		 *			ensuring the event doesn't call its callback again.
-		 *
-		 * @note	Only call this once.
-		 */
-		void disconnect(BaseConnectionData* conn)
-		{
-			BS_LOCK_RECURSIVE_MUTEX(mMutex);
-
-			conn->deactivate();
-			conn->handleLinks--;
-
-			if (conn->handleLinks == 0)
-				free(conn);
-		}
-
-		/**
-		 * @brief	Disconnects all connections in the event.
-		 */
-		void clear()
-		{
-			BS_LOCK_RECURSIVE_MUTEX(mMutex);
-
-			BaseConnectionData* conn = mConnections;
-			while (conn != nullptr)
-			{
-				BaseConnectionData* next = conn->next;
-				conn->deactivate();
-
-				if (conn->handleLinks == 0)
-					free(conn);
-
-				conn = next;
-			}
-		}
-
-		/**
-		 * @brief	Called when the event handle no longer keeps
-		 *			a reference to the connection data. This means
-		 *			we might be able to free (and reuse) its memory
-		 *			if the event is done with it too.
-		 */
-		void freeHandle(BaseConnectionData* conn)
-		{
-			BS_LOCK_RECURSIVE_MUTEX(mMutex);
-
-			conn->handleLinks--;
-
-			if (conn->handleLinks == 0 && !conn->isActive)
-				free(conn);
-		}
-
-		/**
-		 * @brief	Releases connection data and makes it
-		 *			available for re-use when next connection
-		 *			is formed.
-		 */
-		void free(BaseConnectionData* conn)
-		{
-			if (conn->prev != nullptr)
-				conn->prev->next = conn->next;
-			else
-				mConnections = conn->next;
-
-			if (conn->next != nullptr)
-				conn->next->prev = conn->prev;
-
-			conn->prev = nullptr;
-			conn->next = nullptr;
-
-			if (mFreeConnections != nullptr)
-			{
-				conn->next = mFreeConnections;
-				mFreeConnections->prev = conn;
-			}
-
-			mFreeConnections = conn;
-			mFreeConnections->~BaseConnectionData();
-		}
-
-		BaseConnectionData* mConnections;
-		BaseConnectionData* mFreeConnections;
-
-		BS_RECURSIVE_MUTEX(mMutex);
-	};
-
-	/**
-	 * @brief	Event handle. Allows you to track to which events you subscribed to and
-	 *			disconnect from them when needed.
-	 */
-	class HEvent
-	{
-	public:
-		HEvent()
-			:mConnection(nullptr)
-		{ }
-
-		explicit HEvent(const SPtr<EventInternalData>& eventData, BaseConnectionData* connection)
-			:mConnection(connection), mEventData(eventData)
-		{
-			connection->handleLinks++;
-		}
-
-		~HEvent()
-		{
-			if (mConnection != nullptr)
-				mEventData->freeHandle(mConnection);
-		}
-
-		/**
-		 * @brief	Disconnect from the event you are subscribed to.
-		 */
-		void disconnect()
-		{
-			if (mConnection != nullptr)
-			{
-				mEventData->disconnect(mConnection);
-				mConnection = nullptr;
-				mEventData = nullptr;
-			}
-		}
-
-		struct Bool_struct
-		{
-			int _Member;
-		};
-
-		/**
-		* @brief	Allows direct conversion of a handle to bool.
-		*
-		* @note		Additional struct is needed because we can't directly convert to bool
-		*			since then we can assign pointer to bool and that's wrong.
-		*/
-		operator int Bool_struct::*() const
-		{
-			return (mConnection != nullptr ? &Bool_struct::_Member : 0);
-		}
-
-		HEvent& operator=(const HEvent& rhs)
-		{
-			mConnection = rhs.mConnection;
-			mEventData = rhs.mEventData;
-
-			if (mConnection != nullptr)
-				mConnection->handleLinks++;
-
-			return *this;
-		}
-
-	private:
-		BaseConnectionData* mConnection;
-		SPtr<EventInternalData> mEventData;
-	};	
-
-	/**
-	 * @brief	Events allows you to register method callbacks that get notified
-	 *			when the event is triggered.
-	 *
-	 * @note	Callback method return value is ignored.
-	 */
-	// Note: I could create a policy template argument that allows creation of 
-	// lockable and non-lockable events in the case mutex is causing too much overhead.
-	template <class RetType, class... Args>
-	class TEvent
-	{
-		struct ConnectionData : BaseConnectionData
-		{
-		public:
-			void deactivate() override
-			{
-				func = nullptr;
-
-				BaseConnectionData::deactivate();
-			}
-
-			std::function<RetType(Args...)> func;
-		};
-
-	public:
-		TEvent()
-			:mInternalData(bs_shared_ptr_new<EventInternalData>())
-		{ }
-
-		~TEvent()
-		{
-			clear();
-		}
-
-		/**
-		 * @brief	Register a new callback that will get notified once
-		 *			the event is triggered.
-		 */
-		HEvent connect(std::function<RetType(Args...)> func)
-		{
-			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
-
-			ConnectionData* connData = nullptr;
-			if (mInternalData->mFreeConnections != nullptr)
-			{
-				connData = static_cast<ConnectionData*>(mInternalData->mFreeConnections);
-				mInternalData->mFreeConnections = connData->next;
-
-				new (connData)ConnectionData();
-				if (connData->next != nullptr)
-					connData->next->prev = nullptr;
-
-				connData->isActive = true;
-			}
-
-			if (connData == nullptr)
-				connData = bs_new<ConnectionData>();
-
-			connData->next = mInternalData->mConnections;
-
-			if (mInternalData->mConnections != nullptr)
-				mInternalData->mConnections->prev = connData;
-
-			mInternalData->mConnections = connData;
-			connData->func = func;
-
-			return HEvent(mInternalData, connData);
-		}
-
-		/**
-		 * @brief	Trigger the event, notifying all register callback methods.
-		 */
-		void operator() (Args... args)
-		{
-			// Increase ref count to ensure this event data isn't destroyed if one of the callbacks
-			// deletes the event itself.
-			std::shared_ptr<EventInternalData> internalData = mInternalData;
-
-			BS_LOCK_RECURSIVE_MUTEX(internalData->mMutex);
-
-			// Hidden dependency: If any new connections are made during these callbacks they must be
-			// inserted at the start of the linked list so that we don't trigger them here.
-			ConnectionData* conn = static_cast<ConnectionData*>(internalData->mConnections);
-			while (conn != nullptr)
-			{
-				// Save next here in case the callback itself disconnects this connection
-				ConnectionData* next = static_cast<ConnectionData*>(conn->next);
-				
-				if (conn->func != nullptr)
-					conn->func(std::forward<Args>(args)...);
-
-				conn = next;
-			}
-		}
-
-		/**
-		 * @brief	Clear all callbacks from the event.
-		 */
-		void clear()
-		{
-			mInternalData->clear();
-		}
-
-		/**
-		 * @brief	Check if event has any callbacks registered.
-		 *
-		 * @note	It is safe to trigger an event even if no callbacks are registered.
-		 */
-		bool empty() const
-		{
-			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
-
-			return mInternalData->mConnections == nullptr;
-		}
-
-	private:
-		SPtr<EventInternalData> mInternalData;
-	};
-
-	/************************************************************************/
-	/* 							SPECIALIZATIONS                      		*/
-	/* 	SO YOU MAY USE FUNCTION LIKE SYNTAX FOR DECLARING EVENT SIGNATURE   */
-	/************************************************************************/
-	
-	/**
-	 * @copydoc	TEvent
-	 */
-	template <typename Signature>
-	class Event;
-
-	/**
-	* @copydoc	TEvent
-	*/
-	template <class RetType, class... Args>
-	class Event<RetType(Args...) > : public TEvent <RetType, Args...>
-	{ };
-}
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+/** @addtogroup General
+ *  @{
+ */
+
+namespace BansheeEngine
+{
+	/** Data common to all event connections. */
+	class BaseConnectionData
+	{
+	public:
+		BaseConnectionData()
+			:prev(nullptr), next(nullptr), isActive(true),
+			handleLinks(0)
+		{
+			
+		}
+
+		virtual ~BaseConnectionData()
+		{
+			assert(!handleLinks && !isActive);
+		}
+
+		virtual void deactivate()
+		{
+			isActive = false;
+		}
+
+		BaseConnectionData* prev;
+		BaseConnectionData* next;
+		bool isActive;
+		UINT32 handleLinks;
+	};
+
+	/** Internal data for an Event, storing all connections. */
+	struct EventInternalData
+	{
+		EventInternalData()
+			:mConnections(nullptr), mFreeConnections(nullptr)
+		{ }
+
+		~EventInternalData()
+		{
+			BaseConnectionData* conn = mConnections;
+			while (conn != nullptr)
+			{
+				BaseConnectionData* next = conn->next;
+				bs_free(conn);
+
+				conn = next;
+			}
+
+			conn = mFreeConnections;
+			while (conn != nullptr)
+			{
+				BaseConnectionData* next = conn->next;
+				bs_free(conn);
+
+				conn = next;
+			}
+		}
+
+		/**
+		 * Disconnects the connection with the specified data, ensuring the event doesn't call its callback again.
+		 *
+		 * @note	Only call this once.
+		 */
+		void disconnect(BaseConnectionData* conn)
+		{
+			BS_LOCK_RECURSIVE_MUTEX(mMutex);
+
+			conn->deactivate();
+			conn->handleLinks--;
+
+			if (conn->handleLinks == 0)
+				free(conn);
+		}
+
+		/** Disconnects all connections in the event. */
+		void clear()
+		{
+			BS_LOCK_RECURSIVE_MUTEX(mMutex);
+
+			BaseConnectionData* conn = mConnections;
+			while (conn != nullptr)
+			{
+				BaseConnectionData* next = conn->next;
+				conn->deactivate();
+
+				if (conn->handleLinks == 0)
+					free(conn);
+
+				conn = next;
+			}
+		}
+
+		/**
+		 * Called when the event handle no longer keeps a reference to the connection data. This means we might be able to 
+		 * free (and reuse) its memory if the event is done with it too.
+		 */
+		void freeHandle(BaseConnectionData* conn)
+		{
+			BS_LOCK_RECURSIVE_MUTEX(mMutex);
+
+			conn->handleLinks--;
+
+			if (conn->handleLinks == 0 && !conn->isActive)
+				free(conn);
+		}
+
+		/** Releases connection data and makes it available for re-use when next connection is formed. */
+		void free(BaseConnectionData* conn)
+		{
+			if (conn->prev != nullptr)
+				conn->prev->next = conn->next;
+			else
+				mConnections = conn->next;
+
+			if (conn->next != nullptr)
+				conn->next->prev = conn->prev;
+
+			conn->prev = nullptr;
+			conn->next = nullptr;
+
+			if (mFreeConnections != nullptr)
+			{
+				conn->next = mFreeConnections;
+				mFreeConnections->prev = conn;
+			}
+
+			mFreeConnections = conn;
+			mFreeConnections->~BaseConnectionData();
+		}
+
+		BaseConnectionData* mConnections;
+		BaseConnectionData* mFreeConnections;
+
+		BS_RECURSIVE_MUTEX(mMutex);
+	};
+
+	/** Event handle. Allows you to track to which events you subscribed to and disconnect from them when needed. */
+	class HEvent
+	{
+	public:
+		HEvent()
+			:mConnection(nullptr)
+		{ }
+
+		explicit HEvent(const SPtr<EventInternalData>& eventData, BaseConnectionData* connection)
+			:mConnection(connection), mEventData(eventData)
+		{
+			connection->handleLinks++;
+		}
+
+		~HEvent()
+		{
+			if (mConnection != nullptr)
+				mEventData->freeHandle(mConnection);
+		}
+
+		/** Disconnect from the event you are subscribed to. */
+		void disconnect()
+		{
+			if (mConnection != nullptr)
+			{
+				mEventData->disconnect(mConnection);
+				mConnection = nullptr;
+				mEventData = nullptr;
+			}
+		}
+
+		struct Bool_struct
+		{
+			int _Member;
+		};
+
+		/**
+		* Allows direct conversion of a handle to bool.
+		*
+		* @note		
+		* Additional struct is needed because we can't directly convert to bool since then we can assign pointer to bool 
+		* and that's wrong.
+		*/
+		operator int Bool_struct::*() const
+		{
+			return (mConnection != nullptr ? &Bool_struct::_Member : 0);
+		}
+
+		HEvent& operator=(const HEvent& rhs)
+		{
+			mConnection = rhs.mConnection;
+			mEventData = rhs.mEventData;
+
+			if (mConnection != nullptr)
+				mConnection->handleLinks++;
+
+			return *this;
+		}
+
+	private:
+		BaseConnectionData* mConnection;
+		SPtr<EventInternalData> mEventData;
+	};	
+
+	/**
+	 * Events allows you to register method callbacks that get notified when the event is triggered.
+	 *
+	 * @note	Callback method return value is ignored.
+	 */
+	// Note: I could create a policy template argument that allows creation of 
+	// lockable and non-lockable events in the case mutex is causing too much overhead.
+	template <class RetType, class... Args>
+	class TEvent
+	{
+		struct ConnectionData : BaseConnectionData
+		{
+		public:
+			void deactivate() override
+			{
+				func = nullptr;
+
+				BaseConnectionData::deactivate();
+			}
+
+			std::function<RetType(Args...)> func;
+		};
+
+	public:
+		TEvent()
+			:mInternalData(bs_shared_ptr_new<EventInternalData>())
+		{ }
+
+		~TEvent()
+		{
+			clear();
+		}
+
+		/** Register a new callback that will get notified once the event is triggered. */
+		HEvent connect(std::function<RetType(Args...)> func)
+		{
+			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
+
+			ConnectionData* connData = nullptr;
+			if (mInternalData->mFreeConnections != nullptr)
+			{
+				connData = static_cast<ConnectionData*>(mInternalData->mFreeConnections);
+				mInternalData->mFreeConnections = connData->next;
+
+				new (connData)ConnectionData();
+				if (connData->next != nullptr)
+					connData->next->prev = nullptr;
+
+				connData->isActive = true;
+			}
+
+			if (connData == nullptr)
+				connData = bs_new<ConnectionData>();
+
+			connData->next = mInternalData->mConnections;
+
+			if (mInternalData->mConnections != nullptr)
+				mInternalData->mConnections->prev = connData;
+
+			mInternalData->mConnections = connData;
+			connData->func = func;
+
+			return HEvent(mInternalData, connData);
+		}
+
+		/** Trigger the event, notifying all register callback methods. */
+		void operator() (Args... args)
+		{
+			// Increase ref count to ensure this event data isn't destroyed if one of the callbacks
+			// deletes the event itself.
+			std::shared_ptr<EventInternalData> internalData = mInternalData;
+
+			BS_LOCK_RECURSIVE_MUTEX(internalData->mMutex);
+
+			// Hidden dependency: If any new connections are made during these callbacks they must be
+			// inserted at the start of the linked list so that we don't trigger them here.
+			ConnectionData* conn = static_cast<ConnectionData*>(internalData->mConnections);
+			while (conn != nullptr)
+			{
+				// Save next here in case the callback itself disconnects this connection
+				ConnectionData* next = static_cast<ConnectionData*>(conn->next);
+				
+				if (conn->func != nullptr)
+					conn->func(std::forward<Args>(args)...);
+
+				conn = next;
+			}
+		}
+
+		/** Clear all callbacks from the event. */
+		void clear()
+		{
+			mInternalData->clear();
+		}
+
+		/**
+		 * Check if event has any callbacks registered.
+		 *
+		 * @note	It is safe to trigger an event even if no callbacks are registered.
+		 */
+		bool empty() const
+		{
+			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
+
+			return mInternalData->mConnections == nullptr;
+		}
+
+	private:
+		SPtr<EventInternalData> mInternalData;
+	};
+
+	/************************************************************************/
+	/* 							SPECIALIZATIONS                      		*/
+	/* 	SO YOU MAY USE FUNCTION LIKE SYNTAX FOR DECLARING EVENT SIGNATURE   */
+	/************************************************************************/
+	
+	/** @copydoc TEvent */
+	template <typename Signature>
+	class Event;
+
+	/** @copydoc TEvent */
+	template <class RetType, class... Args>
+	class Event<RetType(Args...) > : public TEvent <RetType, Args...>
+	{ };
+}
+
+/** @} */

+ 29 - 44
BansheeUtility/Include/BsException.h

@@ -9,8 +9,14 @@
 
 namespace BansheeEngine
 {
+	/** @addtogroup Error
+	 *  @{
+	 */
+
 	/**
-	 * @brief	Base class for all Banshee exceptions.
+	 * Base class for all Banshee exceptions. 
+	 *
+	 * @note	Banshee doesn't perform exception handling, but these classes remain here in case others wish to enable them.
 	 */
 	class Exception : public std::exception
     {
@@ -40,12 +46,11 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Returns a string with the full description of the exception.
+		 * Returns a string with the full description of the exception.
 		 *
-		 * @note	The description contains the error number, the description
-		 *			supplied by the thrower, what routine threw the exception,
-		 *			and will also supply extra platform-specific information
-		 *			where applicable.
+		 * @note	
+		 * The description contains the error number, the description supplied by the thrower, what routine threw the 
+		 * exception, and will also supply extra platform-specific information where applicable.
 		 */
 		virtual const String& getFullDescription() const
 		{
@@ -68,29 +73,19 @@ namespace BansheeEngine
 			return mFullDesc;
 		}
 
-		/**
-		 * @brief	Gets the source function that threw the exception.
-		 */
+		/** Gets the source function that threw the exception. */
 		virtual const String& getSource() const { return mSource; }
 
-		/**
-		 * @brief	Gets the source file name in which the exception was thrown.
-		 */
+		/** Gets the source file name in which the exception was thrown. */
 		virtual const String& getFile() const { return mFile; }
 
-        /**
-         * @brief	Gets line number on which the exception was thrown.
-         */
+        /** Gets line number on which the exception was thrown. */
         virtual long getLine() const { return mLine; }
 
-		/**
-		 * @brief	Gets a short description about the exception.
-		 */
+		/** Gets a short description about the exception. */
 		virtual const String& getDescription(void) const { return mDescription; }
 
-		/**
-		 * @brief	Overriden std::exception::what. Returns the same value as "getFullDescription".
-		 */
+		/** Overriden std::exception::what. Returns the same value as getFullDescription(). */
 		const char* what() const override { return getFullDescription().c_str(); }
 
 	protected:
@@ -102,9 +97,7 @@ namespace BansheeEngine
 		mutable String mFullDesc;
     };
 
-	/**
-	 * @brief	Exception for signaling not implemented parts of the code.
-	 */
+	/** Exception for signaling not implemented parts of the code. */
 	class NotImplementedException : public Exception 
 	{
 	public:
@@ -112,9 +105,7 @@ namespace BansheeEngine
 			: Exception("NotImplementedException", inDescription, inSource, inFile, inLine) {}
 	};
 
-	/**
-	 * @brief	Exception for signaling file system errors when file could not be found.
-	 */
+	/** Exception for signaling file system errors when file could not be found. */
 	class FileNotFoundException : public Exception
 	{
 	public:
@@ -122,8 +113,7 @@ namespace BansheeEngine
 			: Exception("FileNotFoundException", inDescription, inSource, inFile, inLine) {}
 	};
 
-	/**
-	 * @brief	Exception for signaling general IO errors.
+	/** Exception for signaling general IO errors.
 	 * 			
 	 * @note	An example being failed to open a file or a network connection.
 	 */
@@ -134,9 +124,7 @@ namespace BansheeEngine
 			: Exception("IOException", inDescription, inSource, inFile, inLine) {}
 	};
 
-	/**
-	 * @brief	Exception for signaling not currently executing code in not in a valid state.
-	 */
+	/** Exception for signaling not currently executing code in not in a valid state. */
 	class InvalidStateException : public Exception
 	{
 	public:
@@ -144,9 +132,7 @@ namespace BansheeEngine
 			: Exception("InvalidStateException", inDescription, inSource, inFile, inLine) {}
 	};
 
-	/**
-	 * @brief	Exception for signaling not some parameters you have provided are not valid.
-	 */
+	/** Exception for signaling not some parameters you have provided are not valid. */
 	class InvalidParametersException : public Exception
 	{
 	public:
@@ -155,8 +141,8 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Exception for signaling an internal error, normally something that shouldn't have happened or
-	 * 			wasn't anticipated by the programmers of that system.
+	 * Exception for signaling an internal error, normally something that shouldn't have happened or wasn't anticipated by 
+	 * the programmers of that system.
 	 */
 	class InternalErrorException : public Exception
 	{
@@ -165,9 +151,7 @@ namespace BansheeEngine
 			: Exception("InternalErrorException", inDescription, inSource, inFile, inLine) {}
 	};
 
-	/**
-	 * @brief	Exception for signaling an error in a rendering API.
-	 */
+	/** Exception for signaling an error in a rendering API. */
 	class RenderingAPIException : public Exception
 	{
 	public:
@@ -175,9 +159,7 @@ namespace BansheeEngine
 			: Exception("RenderingAPIException", inDescription, inSource, inFile, inLine) {}
 	};
 
-	/**
-	 * @brief	Exception for signaling an error in an unit test.
-	 */
+	/** Exception for signaling an error in an unit test. */
 	class UnitTestException : public Exception
 	{
 	public:
@@ -186,7 +168,8 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Macro for throwing exceptions that will automatically fill out function name, file name and line number of the exception.
+	 * Macro for throwing exceptions that will automatically fill out function name, file name and line number of the 
+	 * exception.
 	 */
 	// The exception thrown at the end isn't actually ever getting executed, it is just to notify the compiler that execution
 	// won't continue past this point (e.g. if a function needs to return a value otherwise).
@@ -199,5 +182,7 @@ namespace BansheeEngine
 	throw type##(desc, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
 	}
 #endif
+
+	/** @} */
 }
 

+ 54 - 60
BansheeUtility/Include/BsFileSerializer.h

@@ -1,61 +1,55 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	// TODO - Low priority. Eventually I'll want to generalize BinarySerializer to Serializer class, then I can make this class accept
-	// a generic Serializer interface so it may write both binary, plain-text or some other form of data.
-
-	/**
-	 * @brief	Encodes the provided object to the specified file using the RTTI system.
-	 */
-	class BS_UTILITY_EXPORT FileEncoder
-	{
-	public:
-		FileEncoder(const Path& fileLocation);
-		~FileEncoder();
-
-		/**
-		 * @brief	Parses the provided object, serializes all of its data as specified by its
-		 *			RTTIType and saves the serialized data to the provided file location.
-		 */
-		void encode(IReflectable* object);
-
-	private:
-		/**
-		 * @brief	Called by the binary serializer whenever the buffer gets full.
-		 */
-		UINT8* flushBuffer(UINT8* bufferStart, UINT32 bytesWritten, UINT32& newBufferSize);
-
-		std::ofstream mOutputStream;
-		UINT8* mWriteBuffer;
-
-		static const UINT32 WRITE_BUFFER_SIZE = 2048;
-	};
-
-	/**
-	 * @brief	Decodes objects from the specified file using the RTTI system.
-	 */
-	class BS_UTILITY_EXPORT FileDecoder
-	{
-	public:
-		FileDecoder(const Path& fileLocation);
-		~FileDecoder();
-
-		/**
-		 * @brief	Deserializes an IReflectable object by reading the binary data at
-		 *			the provided file location.
-		 */
-		std::shared_ptr<IReflectable> decode();
-
-		/**
-		 * @brief	Skips over than object in the file. Calling "decode" will decode
-		 *			the next object.
-		 */
-		void skip();
-
-	private:
-		std::ifstream mInputStream;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	// TODO - Low priority. Eventually I'll want to generalize BinarySerializer to Serializer class, then I can make this class accept
+	// a generic Serializer interface so it may write both binary, plain-text or some other form of data.
+
+	/** Encodes the provided object to the specified file using the RTTI system. */
+	class BS_UTILITY_EXPORT FileEncoder
+	{
+	public:
+		FileEncoder(const Path& fileLocation);
+		~FileEncoder();
+
+		/**
+		 * Parses the provided object, serializes all of its data as specified by its RTTIType and saves the serialized 
+		 * data to the provided file location.
+		 */
+		void encode(IReflectable* object);
+
+	private:
+		/** Called by the binary serializer whenever the buffer gets full. */
+		UINT8* flushBuffer(UINT8* bufferStart, UINT32 bytesWritten, UINT32& newBufferSize);
+
+		std::ofstream mOutputStream;
+		UINT8* mWriteBuffer;
+
+		static const UINT32 WRITE_BUFFER_SIZE = 2048;
+	};
+
+	/** Decodes objects from the specified file using the RTTI system. */
+	class BS_UTILITY_EXPORT FileDecoder
+	{
+	public:
+		FileDecoder(const Path& fileLocation);
+		~FileDecoder();
+
+		/**	Deserializes an IReflectable object by reading the binary data at the provided file location. */
+		std::shared_ptr<IReflectable> decode();
+
+		/** Skips over than object in the file. Calling decode() will decode the next object. */
+		void skip();
+
+	private:
+		std::ifstream mInputStream;
+	};
+
+	/** @} */
 }

+ 133 - 137
BansheeUtility/Include/BsFileSystem.h

@@ -1,138 +1,134 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Utility class for dealing with files.
-	 */
-	class BS_UTILITY_EXPORT FileSystem
-	{
-	public:
-		/**
-		 * @brief	Opens a file and returns a data stream capable of reading or writing to that file.
-		 *
-		 * @param	fullPath	Full path to a file.
-		 * @param	readOnly	(optional) If true, returned stream will only be readable.
-		 */
-		static DataStreamPtr openFile(const Path& fullPath, bool readOnly = true);
-
-		/**
-		 * @brief	Opens a file and returns a data stream capable of reading and writing to that file.
-		 * 			If file doesn't exist new one will be created.
-		 *
-		 * @param	fullPath	Full path to a file.
-		 */
-		static DataStreamPtr createAndOpenFile(const Path& fullPath);
-
-		/**
-		 * @brief	Returns the size of a file in bytes.
-		 *
-		 * @param	fullPath	Full path to a file.
-		 */
-		static UINT64 getFileSize(const Path& fullPath);
-
-		/**
-		 * @brief	Deletes a file or a folder at the specified path.
-		 *
-		 * @param	fullPath   	Full path to a file or a folder..
-		 * @param	recursively	(optional) If true, folders will have their contents
-		 * 						deleted as well. Otherwise an exception will be
-		 * 						thrown for non-empty folders.
-		 */
-		static void remove(const Path& fullPath, bool recursively = true);
-
-		/**
-		 * @brief	Moves a file or a folder from one to another path. This
-		 * 			can also be used as a rename operation.
-		 *
-		 * @param	oldPath			 	Full path to the old file/folder.
-		 * @param	newPath			 	Full path to the new file/folder.
-		 * @param	overwriteExisting	(optional) If true, any existing file/folder at the new location will be overwritten,
-		 * 								otherwise an exception will be thrown if a file/folder already exists.
-		 */
-		static void move(const Path& oldPath, const Path& newPath, bool overwriteExisting = true);
-
-		/**
-		 * @brief	Makes a copy of a file or a folder in the specified path. 
-		 *
-		 * @param	oldPath			 	Full path to the old file/folder.
-		 * @param	newPath			 	Full path to the new file/folder.
-		 * @param	overwriteExisting	(optional) If true, any existing file/folder at the new location will be overwritten,
-		 * 								otherwise an exception will be thrown if a file/folder already exists.
-		 */
-		static void copy(const Path& oldPath, const Path& newPath, bool overwriteExisting = true);
-
-		/**
-		 * @brief	Creates a folder at the specified path.
-		 *
-		 * @param	fullPath	Full path to a full folder to create.
-		 */
-		static void createDir(const Path& fullPath);
-
-		/**
-		 * @brief	Returns true if a file or a folder exists at the specified path.
-		 *
-		 * @param	fullPath	Full path to a file or folder.
-		 */
-		static bool exists(const Path& fullPath);
-
-		/**
-		 * @brief	Returns true if a file exists at the specified path.
-		 *
-		 * @param	fullPath	Full path to a file or folder.
-		 */
-		static bool isFile(const Path& fullPath);
-
-		/**
-		 * @brief	Returns true if a folder exists at the specified path.
-		 *
-		 * @param	fullPath	Full path to a file or folder.
-		 */
-		static bool isDirectory(const Path& fullPath);
-
-		/**
-		 * @brief	Returns all files or folders located in the specified folder.
-		 *
-		 * @param	dirPath			   	Full path to the folder to retrieve children files/folders from.
-		 * @param [out]	files	   		Full paths to all files located directly in specified folder.
-		 * @param [out]	directories		Full paths to all folders located directly in specified folder.
-		 */
-		static void getChildren(const Path& dirPath, Vector<Path>& files, Vector<Path>& directories);
-
-		/**
-		 * @brief	Iterates over all files and directories in the specified folder and calls the provided callback
-		 *			when a file/folder is iterated over.
-		 *
-		 * @param	dirPath			Directory over which to iterate
-		 * @param	fileCallback	Callback to call whenever a file is found. If callback returns false iteration stops. Can be null.
-		 * @param	dirCallback		Callback to call whenever a directory is found. If callback returns false iteration stops. Can be null.
-		 * @param	recursive		If false then only the direct children of the provided folder
-		 *							will be iterated over, and if true then child directories will
-		 *							be recursively visited as well.
-		 *
-		 * @returns	True if iteration finished iterating over all files/folders, or false if it was interrupted
-		 *			by a callback returning false.
-		 */
-		static bool iterate(const Path& dirPath, std::function<bool(const Path&)> fileCallback,
-			std::function<bool(const Path&)> dirCallback = nullptr, bool recursive = true);
-
-		/**
-		 * @brief	Returns the last modified time of a file or a folder at the specified path.
-		 *
-		 * @param	fullPath	Full path to a file or a folder.
-		 */
-		static std::time_t getLastModifiedTime(const Path& fullPath);
-
-		/**
-		 * @brief	Returns the path to the currently working directory.
-		 */
-		static Path getWorkingDirectoryPath();
-
-		/**
-		 * @brief	Returns the path to a directory where temporary files may be stored.
-		 */
-		static Path getTempDirectoryPath();
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Filesystem
+	 *  @{
+	 */
+
+	/** Utility class for dealing with files. */
+	class BS_UTILITY_EXPORT FileSystem
+	{
+	public:
+		/**
+		 * Opens a file and returns a data stream capable of reading or writing to that file.
+		 *
+		 * @param[in]	fullPath	Full path to a file.
+		 * @param[in]	readOnly	(optional) If true, returned stream will only be readable.
+		 */
+		static DataStreamPtr openFile(const Path& fullPath, bool readOnly = true);
+
+		/**
+		 * Opens a file and returns a data stream capable of reading and writing to that file. If file doesn't exist new 
+		 * one will be created.
+		 *
+		 * @param[in]	fullPath	Full path to a file.
+		 */
+		static DataStreamPtr createAndOpenFile(const Path& fullPath);
+
+		/**
+		 * Returns the size of a file in bytes.
+		 *
+		 * @param[in]	fullPath	Full path to a file.
+		 */
+		static UINT64 getFileSize(const Path& fullPath);
+
+		/**
+		 * Deletes a file or a folder at the specified path.
+		 *
+		 * @param[in]	fullPath   	Full path to a file or a folder..
+		 * @param[in]	recursively	(optional) If true, folders will have their contents deleted as well. Otherwise an 
+		 *							exception will be thrown for non-empty folders.
+		 */
+		static void remove(const Path& fullPath, bool recursively = true);
+
+		/**
+		 * Moves a file or a folder from one to another path. This can also be used as a rename operation.
+		 *
+		 * @param[in]	oldPath			 	Full path to the old file/folder.
+		 * @param[in]	newPath			 	Full path to the new file/folder.
+		 * @param[in]	overwriteExisting	(optional) If true, any existing file/folder at the new location will be 
+		 *									overwritten, otherwise an exception will be thrown if a file/folder already exists.
+		 */
+		static void move(const Path& oldPath, const Path& newPath, bool overwriteExisting = true);
+
+		/**
+		 * Makes a copy of a file or a folder in the specified path. 
+		 *
+		 * @param[in]	oldPath			 	Full path to the old file/folder.
+		 * @param[in]	newPath			 	Full path to the new file/folder.
+		 * @param[in]	overwriteExisting	(optional) If true, any existing file/folder at the new location will be 
+		 *									overwritten, otherwise an exception will be thrown if a file/folder already exists.
+		 */
+		static void copy(const Path& oldPath, const Path& newPath, bool overwriteExisting = true);
+
+		/**
+		 * Creates a folder at the specified path.
+		 *
+		 * @param[in]	fullPath	Full path to a full folder to create.
+		 */
+		static void createDir(const Path& fullPath);
+
+		/**
+		 * Returns true if a file or a folder exists at the specified path.
+		 *
+		 * @param[in]	fullPath	Full path to a file or folder.
+		 */
+		static bool exists(const Path& fullPath);
+
+		/**
+		 * Returns true if a file exists at the specified path.
+		 *
+		 * @param[in]	fullPath	Full path to a file or folder.
+		 */
+		static bool isFile(const Path& fullPath);
+
+		/**
+		 * Returns true if a folder exists at the specified path.
+		 *
+		 * @param[in]	fullPath	Full path to a file or folder.
+		 */
+		static bool isDirectory(const Path& fullPath);
+
+		/**
+		 * Returns all files or folders located in the specified folder.
+		 *
+		 * @param[in]	dirPath			Full path to the folder to retrieve children files/folders from.
+		 * @param[out]	files	   		Full paths to all files located directly in specified folder.
+		 * @param[out]	directories		Full paths to all folders located directly in specified folder.
+		 */
+		static void getChildren(const Path& dirPath, Vector<Path>& files, Vector<Path>& directories);
+
+		/**
+		 * Iterates over all files and directories in the specified folder and calls the provided callback when a 
+		 * file/folder is iterated over.
+		 *
+		 * @param[in]	dirPath			Directory over which to iterate
+		 * @param[in]	fileCallback	Callback to call whenever a file is found. If callback returns false iteration stops. Can be null.
+		 * @param[in]	dirCallback		Callback to call whenever a directory is found. If callback returns false iteration stops. Can be null.
+		 * @param[in]	recursive		If false then only the direct children of the provided folder will be iterated over, 
+		 *								and if true then child directories will be recursively visited as well.
+		 * @return						True if iteration finished iterating over all files/folders, or false if it was 
+		 *								interrupted by a callback returning false.
+		 */
+		static bool iterate(const Path& dirPath, std::function<bool(const Path&)> fileCallback,
+			std::function<bool(const Path&)> dirCallback = nullptr, bool recursive = true);
+
+		/**
+		 * Returns the last modified time of a file or a folder at the specified path.
+		 *
+		 * @param[in]	fullPath	Full path to a file or a folder.
+		 */
+		static std::time_t getLastModifiedTime(const Path& fullPath);
+
+		/** Returns the path to the currently working directory. */
+		static Path getWorkingDirectoryPath();
+
+		/** Returns the path to a directory where temporary files may be stored. */
+		static Path getTempDirectoryPath();
+	};
+
+	/** @} */
 }

+ 43 - 56
BansheeUtility/Include/BsFrameAlloc.h

@@ -4,34 +4,32 @@
 
 namespace BansheeEngine
 {
+	/** @cond INTERNAL */
+	/** @addtogroup Memory
+	 *  @{
+	 */
+
 	/**
-	 * @brief	Frame allocator. Performs very fast allocations but can only free all of its memory at once.
-	 * 			Perfect for allocations that last just a single frame.
+	 * Frame allocator. Performs very fast allocations but can only free all of its memory at once. Perfect for allocations 
+	 * that last just a single frame.
 	 * 			
-	 * @note	Not thread safe with an exception. ::alloc and ::clear methods need to be called from the same thread.
-	 * 			::dealloc is thread safe and can be called from any thread.
+	 * @note	Not thread safe with an exception. alloc() and clear() methods need to be called from the same thread.
+	 * 			dealloc() is thread safe and can be called from any thread.
 	 */
 	class BS_UTILITY_EXPORT FrameAlloc
 	{
 	private:
-		/**
-		 * @brief	A single block of memory within a frame allocator.
-		 */
+		/** A single block of memory within a frame allocator. */
 		class MemBlock
 		{
 		public:
 			MemBlock(UINT32 size);
 			~MemBlock();
 
-			/**
-			 * @brief	Allocates a piece of memory within the block. Caller must ensure
-			 *			the block has enough empty space.
-			 */
+			/** Allocates a piece of memory within the block. Caller must ensure the block has enough empty space. */
 			UINT8* alloc(UINT32 amount);
 
-			/**
-			 * @brief	Releases all allocations within a block but doesn't actually free the memory.
-			 */
+			/** Releases all allocations within a block but doesn't actually free the memory. */
 			void clear();
 
 			UINT8* mData;
@@ -44,16 +42,16 @@ namespace BansheeEngine
 		~FrameAlloc();
 
 		/**
-		 * @brief	Allocates a new block of memory of the specified size.
+		 * Allocates a new block of memory of the specified size.
 		 *
-		 * @param	amount	Amount of memory to allocate, in bytes.
+		 * @param[in]	amount	Amount of memory to allocate, in bytes.
 		 * 					
 		 * @note	Not thread safe.
 		 */
 		UINT8* alloc(UINT32 amount);
 
 		/**
-		 * @brief	Allocates and constructs a new object.
+		 * Allocates and constructs a new object.
 		 *	
 		 * @note	Not thread safe.
 		 */
@@ -64,22 +62,24 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Deallocates a previously allocated block of memory.
+		 * Deallocates a previously allocated block of memory.
 		 *
-		 * @note	No deallocation is actually done here. This method is only used for debug purposes
-		 * 			so it is easier to track down memory leaks and corruption.
-		 * 			
-		 *			Thread safe.
+		 * @note
+		 * No deallocation is actually done here. This method is only used for debug purposes so it is easier to track 
+		 * down memory leaks and corruption.
+		 * @note
+		 * Thread safe.
 		 */
 		void dealloc(UINT8* data);
 
 		/**
-		 * @brief	Deallocates and destructs a previously allocated object.
+		 * Deallocates and destructs a previously allocated object.
 		 *
-		 * @note	No deallocation is actually done here. This method is only used to call the destructor
-		 *			and for debug purposes so it is easier to track down memory leaks and corruption.
-		 * 			
-		 *			Thread safe.
+		 * @note	
+		 * No deallocation is actually done here. This method is only used to call the destructor and for debug purposes 
+		 * so it is easier to track down memory leaks and corruption.
+		 * @note
+		 * Thread safe.
 		 */
 		template<class T>
 		void dealloc(T* obj)
@@ -90,23 +90,20 @@ namespace BansheeEngine
 			dealloc((UINT8*)obj);
 		}
 
-		/**
-		 * @brief	Starts a new frame. Next call to ::clear will only clear memory
-		 *			allocated past this point.
-		 */
+		/** Starts a new frame. Next call to ::clear will only clear memory allocated past this point. */
 		void markFrame();
 
 		/**
-		 * @brief	Deallocates all allocated memory since the last call to ::markFrame
-		 *			(or all the memory if there was no call to ::markFrame).
+		 * Deallocates all allocated memory since the last call to markFrame() (or all the memory if there was no call 
+		 * to markFrame()).
 		 * 			
 		 * @note	Not thread safe.
 		 */
 		void clear();
 
 		/**
-		 * @brief	Changes the frame allocator owner thread. After the owner
-		 *			thread has changed only allocations from that thread can be made.
+		 * Changes the frame allocator owner thread. After the owner thread has changed only allocations from that thread 
+		 * can be made.
 		 */
 		void setOwnerThread(BS_THREAD_ID_TYPE thread);
 
@@ -123,21 +120,16 @@ namespace BansheeEngine
 #endif
 
 		/**
-		 * @brief	Allocates a dynamic block of memory of the wanted size. The exact allocation size
-		 *			might be slightly higher in order to store block meta data.
+		 * Allocates a dynamic block of memory of the wanted size. The exact allocation size might be slightly higher in 
+		 * order to store block meta data.
 		 */
 		MemBlock* allocBlock(UINT32 wantedSize);
 
-		/**
-		 * @brief	Frees a memory block.
-		 */
+		/** Frees a memory block. */
 		void deallocBlock(MemBlock* block);
 	};
 
-	/**
-	 * @brief	Allocator for the standard library that internally uses a
-	 * 			frame allocator.
-	 */
+	/** Allocator for the standard library that internally uses a frame allocator. */
 	template <class T>
 	class StdFrameAlloc
 	{
@@ -159,9 +151,7 @@ namespace BansheeEngine
 		template<class T> bool operator==(const StdFrameAlloc<T>&) const noexcept { return true; }
 		template<class T> bool operator!=(const StdFrameAlloc<T>&) const noexcept { return false; }
 
-		/**
-		 * @brief	Allocate but don't initialize number elements of type T.
-		 */
+		/** Allocate but don't initialize number elements of type T.*/
 		T* allocate(const size_t num) const
 		{
 			if (num == 0)
@@ -177,9 +167,7 @@ namespace BansheeEngine
 			return static_cast<T*>(pv);
 		}
 
-		/**
-		 * @brief	Deallocate storage p of deleted elements.
-		 */
+		/** Deallocate storage p of deleted elements. */
 		void deallocate(T* p, size_t num) const noexcept
 		{
 			mFrameAlloc->dealloc((UINT8*)p);
@@ -188,21 +176,20 @@ namespace BansheeEngine
 		FrameAlloc* mFrameAlloc;
 	};
 
-	/**
-	 * @brief	Return that all specializations of this allocator are interchangeable.
-	 */
+	/** Return that all specializations of this allocator are interchangeable. */
 	template <class T1, class T2>
 	bool operator== (const StdFrameAlloc<T1>&,
 		const StdFrameAlloc<T2>&) throw() {
 		return true;
 	}
 
-	/**
-	 * @brief	Return that all specializations of this allocator are interchangeable.
-	 */
+	/** Return that all specializations of this allocator are interchangeable. */
 	template <class T1, class T2>
 	bool operator!= (const StdFrameAlloc<T1>&,
 		const StdFrameAlloc<T2>&) throw() {
 		return false;
 	}
+
+	/** @} */
+	/** @endcond */
 }

+ 181 - 173
BansheeUtility/Include/BsGlobalFrameAlloc.h

@@ -1,174 +1,182 @@
-#pragma once
-
-#include "BsStdHeaders.h"
-#include "BsThreadDefines.h"
-
-namespace BansheeEngine
-{
-	class FrameAlloc;
-
-	extern BS_THREADLOCAL FrameAlloc* _GlobalFrameAlloc;
-
-	/**
-	 * @brief	Returns a global, application wide frame allocator. Each thread
-	 *			gets its own frame allocator.
-	 *
-	 * @note	Thread safe.
-	 */
-	inline BS_UTILITY_EXPORT FrameAlloc& gFrameAlloc();
-
-	/**
-	 * @brief	Allocates some memory using the global frame allocator.
-	 *
-	 * @param	numBytes	Number of bytes to allocate.
-	 */
-	inline BS_UTILITY_EXPORT UINT8* bs_frame_alloc(UINT32 numBytes);
-
-	/**
-	 * @brief	Deallocates memory allocated with the global frame allocator.
-	 *
-	 * @note	Must be called on the same thread the memory was allocated on.
-	 */
-	inline BS_UTILITY_EXPORT void bs_frame_free(void* data);
-
-	/**
-	 * @brief	Allocates enough memory to hold the object of specified type using
-	 *			the global frame allocator, but does not construct the object. 
-	 */
-	template<class T>
-	T* bs_frame_alloc()
-	{
-		return (T*)bs_frame_alloc(sizeof(T));
-	}
-
-	/**
-	 * @brief	Allocates enough memory to hold N objects of specified type using
-	 *			the global frame allocator, but does not construct the object. 
-	 */
-	template<class T>
-	T* bs_frame_alloc(UINT32 count)
-	{
-		return (T*)bs_frame_alloc(sizeof(T) * count);
-	}
-
-	/**
-	 * @brief	Allocates enough memory to hold the object(s) of specified type using
-	 *			the global frame allocator, and constructs them.
-	 */
-	template<class T>
-	T* bs_frame_new(UINT32 count = 0)
-	{
-		T* data = bs_frame_alloc<T>(count);
-
-		for(unsigned int i = 0; i < count; i++)
-			new ((void*)&data[i]) T;
-
-		return data;
-	}
-
-	/**
-	 * @brief	Allocates enough memory to hold the object(s) of specified type using
-	 *			the global frame allocator, and constructs them.
-	 */
-	template<class T, class... Args>
-	T* bs_frame_new(Args &&...args, UINT32 count = 0)
-	{
-		T* data = bs_frame_alloc<T>(count);
-
-		for(unsigned int i = 0; i < count; i++)
-			new ((void*)&data[i]) T(std::forward<Args>(args)...);
-
-		return data;
-	}
-
-	/**
-	 * @brief	Destructs and deallocates an object allocated with the global frame allocator.
-	 *
-	 * @note	Must be called on the same thread the memory was allocated on.
-	 */
-	template<class T>
-	void bs_frame_delete(T* data)
-	{
-		data->~T();
-
-		bs_frame_free((UINT8*)data);
-	}
-
-	/**
-	 * @brief	Destructs and deallocates an array of objects 
-	 *			allocated with the global frame allocator.
-	 *
-	 * @note	Must be called on the same thread the memory was allocated on.
-	 */
-	template<class T>
-	void bs_frame_delete(T* data, UINT32 count)
-	{
-		for(unsigned int i = 0; i < count; i++)
-			data[i].~T();
-
-		bs_frame_free((UINT8*)data);
-	}
-
-	/**
-	 * @copydoc	FrameAlloc::markFrame
-	 */
-	inline BS_UTILITY_EXPORT void bs_frame_mark();
-
-	/**
-	 * @copydoc	FrameAlloc::clear
-	 */
-	inline BS_UTILITY_EXPORT void bs_frame_clear();
-
-	/**
-	* @brief	Specialized memory allocator implementations that allows use of a 
-	* 			global frame allocator in normal new/delete/free/dealloc operators.
-	*/
-	template<>
-	class MemoryAllocator<FrameAlloc> : public MemoryAllocatorBase
-	{
-	public:
-		static inline void* allocate(size_t bytes)
-		{
-			return bs_frame_alloc((UINT32)bytes);
-		}
-
-		static inline void* allocateArray(size_t bytes, UINT32 count)
-		{
-			return bs_frame_alloc((UINT32)(bytes * count));
-		}
-
-		static inline void free(void* ptr)
-		{
-			bs_frame_free(ptr);
-		}
-
-		static inline void freeArray(void* ptr, UINT32 count)
-		{
-			bs_frame_free(ptr);
-		}
-	};
-
-	/**
-	 * Implementations of various standard library constructs using the frame allocator.
-	 */
-	typedef std::basic_string<char, std::char_traits<char>, StdAlloc<char, FrameAlloc>> FrameString;
-	typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, StdAlloc<wchar_t, FrameAlloc>> FrameWString;
-
-	template <typename T, typename A = StdAlloc<T, FrameAlloc>>
-	using FrameVector = std::vector < T, A > ;
-
-	template <typename T, typename A = StdAlloc<T, FrameAlloc>>
-	using FrameStack = std::stack < T, std::deque<T, A> > ;
-
-	template <typename T, typename P = std::less<T>, typename A = StdAlloc<T, FrameAlloc>>
-	using FrameSet = std::set < T, P, A > ;
-
-	template <typename K, typename V, typename P = std::less<K>, typename A = StdAlloc<std::pair<const K, V>, FrameAlloc>>
-	using FrameMap = std::map < K, V, P, A >;
-
-	template <typename T, typename H = std::hash<T>, typename C = std::equal_to<T>, typename A = StdAlloc<T, FrameAlloc>>
-	using FrameUnorderedSet = std::unordered_set < T, H, C, A >;
-
-	template <typename K, typename V, typename H = std::hash<K>, typename C = std::equal_to<K>, typename A = StdAlloc<std::pair<const K, V>, FrameAlloc>>
-	using FrameUnorderedMap = std::unordered_map < K, V, H, C, A >;
+#pragma once
+
+#include "BsStdHeaders.h"
+#include "BsThreadDefines.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Memory
+	 *  @{
+	 */
+
+	class FrameAlloc;
+
+	/**
+	 * Returns a global, application wide frame allocator. Each thread gets its own frame allocator.
+	 *
+	 * @note	Thread safe.
+	 */
+	inline BS_UTILITY_EXPORT FrameAlloc& gFrameAlloc();
+
+	/**
+	 * Allocates some memory using the global frame allocator.
+	 *
+	 * @param[in]	numBytes	Number of bytes to allocate.
+	 */
+	inline BS_UTILITY_EXPORT UINT8* bs_frame_alloc(UINT32 numBytes);
+
+	/**
+	 * Deallocates memory allocated with the global frame allocator.
+	 *
+	 * @note	Must be called on the same thread the memory was allocated on.
+	 */
+	inline BS_UTILITY_EXPORT void bs_frame_free(void* data);
+
+	/**
+	 * Allocates enough memory to hold the object of specified type using the global frame allocator, but does not 
+	 * construct the object. 
+	 */
+	template<class T>
+	T* bs_frame_alloc()
+	{
+		return (T*)bs_frame_alloc(sizeof(T));
+	}
+
+	/**
+	 * Allocates enough memory to hold N objects of specified type using the global frame allocator, but does not 
+	 * construct the object. 
+	 */
+	template<class T>
+	T* bs_frame_alloc(UINT32 count)
+	{
+		return (T*)bs_frame_alloc(sizeof(T) * count);
+	}
+
+	/**
+	 * Allocates enough memory to hold the object(s) of specified type using the global frame allocator, 
+	 * and constructs them.
+	 */
+	template<class T>
+	T* bs_frame_new(UINT32 count = 0)
+	{
+		T* data = bs_frame_alloc<T>(count);
+
+		for(unsigned int i = 0; i < count; i++)
+			new ((void*)&data[i]) T;
+
+		return data;
+	}
+
+	/**
+	 * Allocates enough memory to hold the object(s) of specified type using the global frame allocator, and constructs them.
+	 */
+	template<class T, class... Args>
+	T* bs_frame_new(Args &&...args, UINT32 count = 0)
+	{
+		T* data = bs_frame_alloc<T>(count);
+
+		for(unsigned int i = 0; i < count; i++)
+			new ((void*)&data[i]) T(std::forward<Args>(args)...);
+
+		return data;
+	}
+
+	/**
+	 * Destructs and deallocates an object allocated with the global frame allocator.
+	 *
+	 * @note	Must be called on the same thread the memory was allocated on.
+	 */
+	template<class T>
+	void bs_frame_delete(T* data)
+	{
+		data->~T();
+
+		bs_frame_free((UINT8*)data);
+	}
+
+	/**
+	 * Destructs and deallocates an array of objects allocated with the global frame allocator.
+	 *
+	 * @note	Must be called on the same thread the memory was allocated on.
+	 */
+	template<class T>
+	void bs_frame_delete(T* data, UINT32 count)
+	{
+		for(unsigned int i = 0; i < count; i++)
+			data[i].~T();
+
+		bs_frame_free((UINT8*)data);
+	}
+
+	/** @copydoc FrameAlloc::markFrame */
+	inline BS_UTILITY_EXPORT void bs_frame_mark();
+
+	/** @copydoc FrameAlloc::clear */
+	inline BS_UTILITY_EXPORT void bs_frame_clear();
+
+	/** String allocated with a frame allocator. */
+	typedef std::basic_string<char, std::char_traits<char>, StdAlloc<char, FrameAlloc>> FrameString;
+
+	/** WString allocated with a frame allocator. */
+	typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, StdAlloc<wchar_t, FrameAlloc>> FrameWString;
+
+	/** Vector allocated with a frame allocator. */
+	template <typename T, typename A = StdAlloc<T, FrameAlloc>>
+	using FrameVector = std::vector < T, A > ;
+
+	/** Stack allocated with a frame allocator. */
+	template <typename T, typename A = StdAlloc<T, FrameAlloc>>
+	using FrameStack = std::stack < T, std::deque<T, A> > ;
+
+	/** Set allocated with a frame allocator. */
+	template <typename T, typename P = std::less<T>, typename A = StdAlloc<T, FrameAlloc>>
+	using FrameSet = std::set < T, P, A > ;
+
+	/** Map allocated with a frame allocator. */
+	template <typename K, typename V, typename P = std::less<K>, typename A = StdAlloc<std::pair<const K, V>, FrameAlloc>>
+	using FrameMap = std::map < K, V, P, A >;
+
+	/** UnorderedSet allocated with a frame allocator. */
+	template <typename T, typename H = std::hash<T>, typename C = std::equal_to<T>, typename A = StdAlloc<T, FrameAlloc>>
+	using FrameUnorderedSet = std::unordered_set < T, H, C, A >;
+
+	/** UnorderedMap allocated with a frame allocator. */
+	template <typename K, typename V, typename H = std::hash<K>, typename C = std::equal_to<K>, typename A = StdAlloc<std::pair<const K, V>, FrameAlloc>>
+	using FrameUnorderedMap = std::unordered_map < K, V, H, C, A >;
+
+	/** @cond INTERNAL */
+
+	extern BS_THREADLOCAL FrameAlloc* _GlobalFrameAlloc;
+
+	/**
+	 * Specialized memory allocator implementations that allows use of a global frame allocator in normal 
+	 * new/delete/free/dealloc operators.
+	 */
+	template<>
+	class MemoryAllocator<FrameAlloc> : public MemoryAllocatorBase
+	{
+	public:
+		static void* allocate(size_t bytes)
+		{
+			return bs_frame_alloc((UINT32)bytes);
+		}
+
+		static void* allocateArray(size_t bytes, UINT32 count)
+		{
+			return bs_frame_alloc((UINT32)(bytes * count));
+		}
+
+		static void free(void* ptr)
+		{
+			bs_frame_free(ptr);
+		}
+
+		static void freeArray(void* ptr, UINT32 count)
+		{
+			bs_frame_free(ptr);
+		}
+	};
+
+	/** @endcond */
+	/** @} */
 }

+ 82 - 79
BansheeUtility/Include/BsIReflectable.h

@@ -1,80 +1,83 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsAny.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Interface implemented by classes that provide run time type information.
-	 * 			
-	 * @note	Any class implementing this interface must implement the "getRTTI" method, as well as
-	 * 			a static "getRTTIStatic" method, returning the same value as "getRTTI". Object returned by those
-	 * 			methods is used for retrieving actual RTTI data about the class.
-	 */
-	class BS_UTILITY_EXPORT IReflectable
-	{
-	public:
-		virtual ~IReflectable() {}
-
-		/**
-		 * @brief	Returns an interface you can use to access class' Run Time Type Information.
-		 *
-		 * @note	You must derive your own version of RTTITypeBase, in which you
-		 * 			may encapsulate all reflection specific operations. 
-		 */
-		virtual RTTITypeBase* getRTTI() const = 0;
-
-		/**
-		 * @brief	Returns all classes deriving directly from IReflectable.
-		 */
-		static Vector<RTTITypeBase*>& getDerivedClasses()
-		{
-			static Vector<RTTITypeBase*> mRTTIDerivedClasses;
-			return mRTTIDerivedClasses;
-		}
-
-		/**
-		 * @brief	Returns true if current RTTI class is derived from "base".
-		 * 			(Or if it is the same type as base)
-		 */
-		bool isDerivedFrom(RTTITypeBase* base);
-
-		/**
-		 * @brief	Returns an unique type identifier of the class.
-		 */
-		UINT32 getTypeId() const;
-
-		/**
-		 * @brief	Returns the type name of the class.
-		 *
-		 * @note	Name is not necessarily unique.
-		 */
-		const String& getTypeName() const;
-
-		/**
-		 * @brief	Creates an empty instance of a class from a type identifier.
-		 */
-		static std::shared_ptr<IReflectable> createInstanceFromTypeId(UINT32 rttiTypeId);
-
-		/**
-		 * @brief	Internal method. Called by each type deriving from IReflectable,
-		 * 			on program load.
-		 */
-		static void _registerDerivedClass(RTTITypeBase* derivedClass);
-
-		/**
-		* @brief	Internal method. Returns class' RTTI type from type id.
-		*/
-		static RTTITypeBase* _getRTTIfromTypeId(UINT32 rttiTypeId);
-
-		/**
-		 * @brief	Internal method. Checks if the provided type id is unique.
-		 */
-		static bool _isTypeIdDuplicate(UINT32 typeId);
-
-	protected:
-		Any mRTTIData; // Temporary per-instance data storage used during various RTTI operations.
-					   // Needed since there is one RTTI class instance per type and sometimes we need per-instance data.
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsAny.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup RTTI
+	 *  @{
+	 */
+
+	/**
+	 * Interface implemented by classes that provide run time type information.
+	 * 			
+	 * @note	
+	 * Any class implementing this interface must implement the getRTTI() method, as well as a static getRTTIStatic() 
+	 * method, returning the same value as getRTTI(). Object returned by those methods is used for retrieving actual RTTI 
+	 * data about the class.
+	 */
+	class BS_UTILITY_EXPORT IReflectable
+	{
+	public:
+		virtual ~IReflectable() {}
+
+		/**
+		 * Returns an interface you can use to access class' Run Time Type Information.
+		 *
+		 * @note	
+		 * You must derive your own version of RTTITypeBase, in which you may encapsulate all reflection specific operations. 
+		 */
+		virtual RTTITypeBase* getRTTI() const = 0;
+
+		/** Returns all classes deriving directly from IReflectable. */
+		static Vector<RTTITypeBase*>& getDerivedClasses()
+		{
+			static Vector<RTTITypeBase*> mRTTIDerivedClasses;
+			return mRTTIDerivedClasses;
+		}
+
+		/** Returns true if current RTTI class is derived from @p base (Or if it is the same type as base). */
+		bool isDerivedFrom(RTTITypeBase* base);
+
+		/** Returns an unique type identifier of the class. */
+		UINT32 getTypeId() const;
+
+		/**
+		 * Returns the type name of the class.
+		 *
+		 * @note	Name is not necessarily unique.
+		 */
+		const String& getTypeName() const;
+
+		/** Creates an empty instance of a class from a type identifier. */
+		static std::shared_ptr<IReflectable> createInstanceFromTypeId(UINT32 rttiTypeId);
+
+		/**
+		 * Called by each type deriving from IReflectable, on program load.
+		 *
+		 * @note	Internal method.
+		 */
+		static void _registerDerivedClass(RTTITypeBase* derivedClass);
+
+		/**
+		 * Returns class' RTTI type from type id.
+		 *
+		 * @note	Internal method.
+		 */
+		static RTTITypeBase* _getRTTIfromTypeId(UINT32 rttiTypeId);
+
+		/**
+		 * Checks if the provided type id is unique.
+		 *
+		 * @note	Internal method.
+		 */
+		static bool _isTypeIdDuplicate(UINT32 typeId);
+
+	protected:
+		Any mRTTIData; /**< Temporary per-instance data storage used during various RTTI operations.
+					    Needed since there is one RTTI class instance per type and sometimes we need per-instance data. */
+	};
+
+	/** @} */
 }

+ 54 - 49
BansheeUtility/Include/BsManagedDataBlock.h

@@ -1,50 +1,55 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Data block holding an array of bytes, usually used in serialization.
-	 * 			
-	 *			Ownership of the data blocked is passed to the latest copy of the ManagedDataBlock.
-	 *			Data will be automatically freed once the last copy is destroyed.
-	 */
-	class BS_UTILITY_EXPORT ManagedDataBlock
-	{
-	public:
-		/**
-		 * @brief	Constructor
-		 *
-		 * @param 	data			Array of bytes to store. Direct pointer to the provided
-		 * 							array will be stored, no copying will be done. 
-		 * @param	size			Size of the array, in bytes.
-		 * @param	deallocator		Deallocator that will be used for freeing the data. If null, the default
-		 * 							deallocator will be used.	
-		 */
-		ManagedDataBlock(UINT8* data, UINT32 size, std::function<void(UINT8*)> deallocator = nullptr); 
-
-		/**
-		 * @brief	Constructor that will automatically allocate an internal buffer of the specified size.
-		 * 			Copying ManagedDataBlock transfers ownership of the buffer to the copy of the buffer.
-		 * 			Buffer is deleted when the latest copy is deleted.
-		 *
-		 * @param	size	The size of the data in bytes.
-		 */
-		ManagedDataBlock(UINT32 size);
-
-		ManagedDataBlock(const ManagedDataBlock& source);
-
-		~ManagedDataBlock();
-
-		UINT8* getData() { return mData; }
-		UINT32 getSize() { return mData ? mSize : 0; }
-
-	private:
-		UINT8* mData;
-		UINT32 mSize;
-		bool mManaged;
-		std::function<void(UINT8*)> mDeallocator;
-		mutable bool mIsDataOwner;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	/**
+	 * Data block holding an array of bytes, usually used in serialization.
+	 * 			
+	 * Ownership of the data blocked is passed to the latest copy of the ManagedDataBlock. Data will be automatically 
+	 * freed once the last copy is destroyed.
+	 */
+	class BS_UTILITY_EXPORT ManagedDataBlock
+	{
+	public:
+		/**
+		 * Constructor
+		 *
+		 * @param[in] 	data			Array of bytes to store. Direct pointer to the provided array will be stored, 
+		 *								no copying will be done. 
+		 * @param[in]	size			Size of the array, in bytes.
+		 * @param[in]	deallocator		Deallocator that will be used for freeing the data. If null, the default deallocator 
+		 *								will be used.	
+		 */
+		ManagedDataBlock(UINT8* data, UINT32 size, std::function<void(UINT8*)> deallocator = nullptr); 
+
+		/**
+		 * Constructor that will automatically allocate an internal buffer of the specified size. Copying ManagedDataBlock 
+		 * transfers ownership of the buffer to the copy of the buffer. Buffer is deleted when the latest copy is deleted.
+		 *
+		 * @param[in]	size	The size of the data in bytes.
+		 */
+		ManagedDataBlock(UINT32 size);
+
+		ManagedDataBlock(const ManagedDataBlock& source);
+
+		~ManagedDataBlock();
+
+		UINT8* getData() { return mData; }
+		UINT32 getSize() { return mData ? mSize : 0; }
+
+	private:
+		UINT8* mData;
+		UINT32 mSize;
+		bool mManaged;
+		std::function<void(UINT8*)> mDeallocator;
+		mutable bool mIsDataOwner;
+	};
+
+	/** @} */
 }

+ 50 - 52
BansheeUtility/Include/BsMemAllocProfiler.h

@@ -1,53 +1,51 @@
-#pragma once
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Specialized allocator for profiler so we can avoid tracking internal profiler memory allocations
-	 * 			which would skew profiler results.
-	 */
-	class ProfilerAlloc
-	{};
-
-	/**
-	 * @brief	Memory allocator providing a generic implementation. 
-	 * 			Specialize for specific categories as needed.
-	 */
-	template<>
-	class MemoryAllocator<ProfilerAlloc> : public MemoryAllocatorBase
-	{
-	public:
-		/**
-		 * @brief	Allocates the given number of bytes.
-		 */
-		static inline void* allocate(size_t bytes)
-		{
-			return malloc(bytes);
-		}
-
-		/**
-		 * @brief	Allocates the given a number of objects, each of the given number of bytes.
-		 */
-		static inline void* allocateArray(size_t bytes, UINT32 count)
-		{
-			return malloc(bytes * count);
-		}
-
-		/**
-		 * @brief	Frees memory previously allocated with "allocate".
-		 */
-		static inline void free(void* ptr)
-		{
-			::free(ptr);
-		}
-
-		/**
-		 * @brief	Frees memory previously allocated with "freeArray". "count" must match the
-		 * 			original value when array was allocated.
-		 */
-		static inline void freeArray(void* ptr, UINT32 count)
-		{
-			::free(ptr);
-		}
-	};
+#pragma once
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Memory
+	 *  @{
+	 */
+
+	/**
+	 * Specialized allocator for profiler so we can avoid tracking internal profiler memory allocations which would skew 
+	 * profiler results.
+	 */
+	class ProfilerAlloc
+	{};
+
+	/** Memory allocator providing a generic implementation. Specialize for specific categories as needed. */
+	template<>
+	class MemoryAllocator<ProfilerAlloc> : public MemoryAllocatorBase
+	{
+	public:
+		/** Allocates the given number of bytes. */
+		static void* allocate(size_t bytes)
+		{
+			return malloc(bytes);
+		}
+
+		/** Allocates the given a number of objects, each of the given number of bytes. */
+		static void* allocateArray(size_t bytes, UINT32 count)
+		{
+			return malloc(bytes * count);
+		}
+
+		/** Frees memory previously allocated with allocate(). */
+		static void free(void* ptr)
+		{
+			::free(ptr);
+		}
+
+		/**
+		 * Frees memory previously allocated with freeArray(). @p count must match the original value when array was allocated.
+		 */
+		static void freeArray(void* ptr, UINT32 count)
+		{
+			::free(ptr);
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 78 - 85
BansheeUtility/Include/BsMemStack.h

@@ -7,21 +7,25 @@
 
 namespace BansheeEngine
 {
+	/** @addtogroup Memory
+	 *  @{
+	 */
+
+	 /** @cond INTERNAL */
+
 	/**
-	 * @brief	Describes a memory stack of a certain block capacity. See ::MemStack for more information.
+	 * Describes a memory stack of a certain block capacity. See ::MemStack for more information.
 	 *
-	 *  @tparam	BlockCapacity Minimum size of a block. Larger blocks mean less memory allocations, but also potentially
-	 * 			more wasted memory. If an allocation requests more bytes than BlockCapacity, first largest multiple is
-	 * 			used instead.
+	 * @tparam	BlockCapacity Minimum size of a block. Larger blocks mean less memory allocations, but also potentially
+	 *						  more wasted memory. If an allocation requests more bytes than BlockCapacity, first largest 
+	 *						  multiple is used instead.
 	 */
 	template <int BlockCapacity = 1024 * 1024>
 	class MemStackInternal
 	{
 	private:
-
-		/**
-		 * @brief	A single block of memory of "BlockCapacity" size. A pointer to the first
-		 * 			free address is stored, and a remaining size. 
+		/** A single block of memory of BlockCapacity size. A pointer to the first free address is stored, and a remaining 
+		 *  size. 
 		 */
 		class MemBlock
 		{
@@ -35,9 +39,8 @@ namespace BansheeEngine
 			{ }
 
 			/**
-			 * @brief	Returns the first free address and increments the free pointer.
-			 * 			Caller needs to ensure the remaining block size is adequate before
-			 * 			calling.
+			 * Returns the first free address and increments the free pointer. Caller needs to ensure the remaining block 
+			 * size is adequate before calling.
 			 */
 			UINT8* alloc(UINT32 amount)
 			{
@@ -48,10 +51,10 @@ namespace BansheeEngine
 			}
 
 			/**
-			 * @brief	Deallocates the provided pointer. Deallocation must happen in opposite order
-			 * 			from allocation otherwise corruption will occur.
+			 * Deallocates the provided pointer. Deallocation must happen in opposite order from allocation otherwise 
+			 * corruption will occur.
 			 * 			
-			 * @note	Pointer to "data" isn't actually needed, but is provided for debug purposes in order to more
+			 * @note	Pointer to @p data isn't actually needed, but is provided for debug purposes in order to more
 			 * 			easily track out-of-order deallocations.
 			 */
 			void dealloc(UINT8* data, UINT32 amount)
@@ -89,16 +92,16 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allocates the given amount of memory on the stack.
+		 * Allocates the given amount of memory on the stack.
 		 *
-		 * @param	amount	The amount to allocate in bytes.
+		 * @param[in]	amount	The amount to allocate in bytes.
 		 *
-		 * @note	Allocates the memory in the currently active block if it is large enough,
-		 * 			otherwise a new block is allocated. If the allocation is larger than
-		 * 			default block size a separate block will be allocated only for that allocation,
-		 * 			making it essentially a slower heap allocator.
-		 * 			
-		 *			Each allocation comes with a 4 byte overhead.
+		 * @note	
+		 * Allocates the memory in the currently active block if it is large enough, otherwise a new block is allocated. 
+		 * If the allocation is larger than default block size a separate block will be allocated only for that allocation,
+		 * making it essentially a slower heap allocator.
+		 * @note			
+		 * Each allocation comes with a 4 byte overhead.
 		 */
 		UINT8* alloc(UINT32 amount)
 		{
@@ -116,10 +119,7 @@ namespace BansheeEngine
 			return data + sizeof(UINT32);
 		}
 
-		/**
-		 * @brief	Deallocates the given memory. Data must be deallocated in opposite
-		 * 			order then when it was allocated.
-		 */
+		/** Deallocates the given memory. Data must be deallocated in opposite order then when it was allocated. */
 		void dealloc(UINT8* data)
 		{
 			data -= sizeof(UINT32);
@@ -155,9 +155,9 @@ namespace BansheeEngine
 	private:
 		MemBlock* mFreeBlock;
 
-		/**
-		 * @brief	Allocates a new block of memory using a heap allocator. Block will never be 
-		 * 			smaller than "BlockCapacity" no matter the "wantedSize".
+		/** 
+		 * Allocates a new block of memory using a heap allocator. Block will never be smaller than BlockCapacity no matter 
+		 * the @p wantedSize.
 		 */
 		MemBlock* allocBlock(UINT32 wantedSize)
 		{
@@ -197,9 +197,7 @@ namespace BansheeEngine
 			return newBlock;
 		}
 
-		/**
-		 * @brief	Deallocates a block of memory.
-		 */
+		/** Deallocates a block of memory. */
 		void deallocBlock(MemBlock* block)
 		{
 			block->~MemBlock();
@@ -208,56 +206,52 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	One of the fastest, but also very limiting type of allocator. All deallocations
-	 * 			must happen in opposite order from allocations. 
+	 * One of the fastest, but also very limiting type of allocator. All deallocations must happen in opposite order from 
+	 * allocations. 
 	 * 			
-	 * @note	It's mostly useful when you need to allocate something temporarily on the heap,
-	 * 			usually something that gets allocated and freed within the same method.
-	 * 			
-	 *			Each allocation comes with a pretty hefty 4 byte memory overhead, so don't use it for small allocations. 
-	 *			
-	 *			Thread safe. But you cannot allocate on one thread and deallocate on another. Threads will keep
-	 *			separate stacks internally. Make sure to call beginThread/endThread for any thread this stack is used on.
+	 * @note	
+	 * It's mostly useful when you need to allocate something temporarily on the heap, usually something that gets 
+	 * allocated and freed within the same method.
+	 * @note
+	 * Each allocation comes with a pretty hefty 4 byte memory overhead, so don't use it for small allocations. 
+	 * @note
+	 * Thread safe. But you cannot allocate on one thread and deallocate on another. Threads will keep
+	 * separate stacks internally. Make sure to call beginThread()/endThread() for any thread this stack is used on.
 	 */
 	class MemStack
 	{
 	public:
 		/**
-		 * @brief	Sets up the stack with the currently active thread. You need to call this
-		 * 			on any thread before doing any allocations or deallocations 
+		 * Sets up the stack with the currently active thread. You need to call this on any thread before doing any 
+		 * allocations or deallocations.
 		 */
 		static BS_UTILITY_EXPORT void beginThread();
 
 		/**
-		 * @brief	Cleans up the stack for the current thread. You may not perform any allocations or deallocations
-		 * 			after this is called, unless you call beginThread again.
+		 * Cleans up the stack for the current thread. You may not perform any allocations or deallocations after this is 
+		 * called, unless you call beginThread again.
 		 */
 		static BS_UTILITY_EXPORT void endThread();
 
-		/**
-		 * @copydoc	MemoryStackInternal::alloc
-		 */
+		/** @copydoc MemoryStackInternal::alloc() */
 		static BS_UTILITY_EXPORT UINT8* alloc(UINT32 numBytes);
 
-		/**
-		 * @copydoc	MemoryStackInternal::dealloc
-		 */
+		/** @copydoc MemoryStackInternal::dealloc() */
 		static BS_UTILITY_EXPORT void deallocLast(UINT8* data);
 
 	private:
 		static BS_THREADLOCAL MemStackInternal<1024 * 1024>* ThreadMemStack;
 	};
 
-	/**
-	 * @copydoc	MemoryStackInternal::alloc
-	 */
+	/** @endcond */
+
+	/** @copydoc MemoryStackInternal::alloc() */
 	BS_UTILITY_EXPORT inline void* bs_stack_alloc(UINT32 numBytes);
 
 	/**
-	 * @brief	Allocates enough memory to hold the specified type, on the stack, but
-	 * 			does not initialize the object. 
+	 * Allocates enough memory to hold the specified type, on the stack, but does not initialize the object. 
 	 *
-	 * @see		MemoryStackInternal::alloc()
+	 * @see	MemoryStackInternal::alloc()
 	 */
 	template<class T>
 	T* bs_stack_alloc()
@@ -266,10 +260,9 @@ namespace BansheeEngine
 	}
 
 	/**
-	 * @brief	Allocates enough memory to hold N objects of the specified type, 
-	 * 			on the stack, but does not initialize the objects. 
+	 * Allocates enough memory to hold N objects of the specified type, on the stack, but does not initialize the objects. 
 	 *
-	 * @see		MemoryStackInternal::alloc()
+	 * @see	MemoryStackInternal::alloc()
 	 */
 	template<class T>
 	T* bs_stack_alloc(UINT32 count)
@@ -278,10 +271,9 @@ namespace BansheeEngine
 	}
 
 	/**
-	 * @brief	Allocates enough memory to hold the specified type, on the stack, 
-	 * 			and constructs the object.
+	 * Allocates enough memory to hold the specified type, on the stack, and constructs the object.
 	 *
-	 * @see		MemoryStackInternal::alloc()
+	 * @see	MemoryStackInternal::alloc()
 	 */
 	template<class T>
 	T* bs_stack_new(UINT32 count = 0)
@@ -295,10 +287,9 @@ namespace BansheeEngine
 	}
 
 	/**
-	 * @brief	Allocates enough memory to hold the specified type, on the stack, 
-	 * 			and constructs the object.
+	 * Allocates enough memory to hold the specified type, on the stack, and constructs the object.
 	 *
-	 * @see		MemoryStackInternal::alloc()
+	 * @see MemoryStackInternal::alloc()
 	 */
 	template<class T, class... Args>
 	T* bs_stack_new(Args &&...args, UINT32 count = 0)
@@ -312,9 +303,9 @@ namespace BansheeEngine
 	}
 
 	/**
-	 * @brief	Destructs and deallocates last allocated entry currently located on stack.
+	 * Destructs and deallocates last allocated entry currently located on stack.
 	 *
-	 * @see		MemoryStackInternal::dealloc()
+	 * @see MemoryStackInternal::dealloc()
 	 */
 	template<class T>
 	void bs_stack_delete(T* data)
@@ -325,10 +316,9 @@ namespace BansheeEngine
 	}
 
 	/**
-	 * @brief	Destructs an array of objects and deallocates last allocated 
-	 * 			entry currently located on stack.
+	 * Destructs an array of objects and deallocates last allocated entry currently located on stack.
 	 *
-	 * @see		MemoryStackInternal::dealloc()
+	 * @see	MemoryStackInternal::dealloc()
 	 */
 	template<class T>
 	void bs_stack_delete(T* data, UINT32 count)
@@ -339,47 +329,50 @@ namespace BansheeEngine
 		MemStack::deallocLast((UINT8*)data);
 	}
 
-	/**
-	 * @copydoc	MemoryStackInternal::dealloc()
-	 */
+	/** @copydoc MemoryStackInternal::dealloc() */
 	BS_UTILITY_EXPORT inline void bs_stack_free(void* data);
 
+	/** @cond INTERNAL */
+
 	/**
-	* @brief	Allows use of a stack allocator by using normal new/delete/free/dealloc operators.
-	* 			
-	* @see		MemStack
-	*/
+	 * Allows use of a stack allocator by using normal new/delete/free/dealloc operators.
+	 * 			
+	 * @see	MemStack
+	 */
 	class StackAlloc
 	{ };
 
 	/**
-	* @brief	Specialized memory allocator implementations that allows use of a 
-	* 			stack allocator in normal new/delete/free/dealloc operators.
+	* Specialized memory allocator implementations that allows use of a stack allocator in normal new/delete/free/dealloc 
+	* operators.
 	* 			
-	* @see		MemStack
+	* @see MemStack
 	*/
 	template<>
 	class MemoryAllocator<StackAlloc> : public MemoryAllocatorBase
 	{
 	public:
-		static inline void* allocate(size_t bytes)
+		static void* allocate(size_t bytes)
 		{
 			return bs_stack_alloc((UINT32)bytes);
 		}
 
-		static inline void* allocateArray(size_t bytes, UINT32 count)
+		static void* allocateArray(size_t bytes, UINT32 count)
 		{
 			return bs_stack_alloc((UINT32)(bytes * count));
 		}
 
-		static inline void free(void* ptr)
+		static void free(void* ptr)
 		{
 			bs_stack_free(ptr);
 		}
 
-		static inline void freeArray(void* ptr, UINT32 count)
+		static void freeArray(void* ptr, UINT32 count)
 		{
 			bs_stack_free(ptr);
 		}
 	};
+
+	/** @endcond */
+	/** @} */
 }

+ 40 - 63
BansheeUtility/Include/BsMemoryAllocator.h

@@ -5,13 +5,19 @@
 
 #include <atomic>
 
+/** @addtogroup Memory
+ *  @{
+ */
+
 namespace BansheeEngine
 {
 	class MemoryAllocatorBase;
 
+	/** @cond INTERNAL */
+
 	/**
-	 * @brief	Thread safe class used for storing total number of memory allocations and deallocations,
-	 * 			primarily for statistic purposes.
+	 * Thread safe class used for storing total number of memory allocations and deallocations, primarily for statistic 
+	 * purposes.
 	 */
 	class MemoryCounter
 	{
@@ -37,10 +43,7 @@ namespace BansheeEngine
 		static BS_THREADLOCAL UINT64 Frees;
 	};
 
-	/**
-	 * @brief	Base class all memory allocators need to inherit. Provides
-	 * 			allocation and free counting.
-	 */
+	/** Base class all memory allocators need to inherit. Provides allocation and free counting. */
 	class MemoryAllocatorBase
 	{
 	protected:
@@ -49,8 +52,7 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Memory allocator providing a generic implementation. 
-	 * 			Specialize for specific categories as needed.
+	 * Memory allocator providing a generic implementation. Specialize for specific categories as needed.
 	 * 			
 	 * @note	For example you might implement a pool allocator for specific types in order
 	 * 			to reduce allocation overhead. By default standard malloc/free are used.
@@ -59,7 +61,7 @@ namespace BansheeEngine
 	class MemoryAllocator : public MemoryAllocatorBase
 	{
 	public:
-		static inline void* allocate(size_t bytes)
+		static void* allocate(size_t bytes)
 		{
 #if BS_PROFILING_ENABLED
 			incAllocCount();
@@ -68,7 +70,7 @@ namespace BansheeEngine
 			return malloc(bytes);
 		}
 
-		static inline void* allocateArray(size_t bytes, UINT32 count)
+		static void* allocateArray(size_t bytes, UINT32 count)
 		{
 #if BS_PROFILING_ENABLED
 			incAllocCount();
@@ -77,7 +79,7 @@ namespace BansheeEngine
 			return malloc(bytes * count);
 		}
 
-		static inline void free(void* ptr)
+		static void free(void* ptr)
 		{
 #if BS_PROFILING_ENABLED
 			incFreeCount();
@@ -86,7 +88,7 @@ namespace BansheeEngine
 			::free(ptr);
 		}
 
-		static inline void freeArray(void* ptr, UINT32 count)
+		static void freeArray(void* ptr, UINT32 count)
 		{
 #if BS_PROFILING_ENABLED
 			incFreeCount();
@@ -97,33 +99,29 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	General allocator provided by the OS. Use for persistent long term allocations,
-	 * 			and allocations that don't happen often.
+	 * General allocator provided by the OS. Use for persistent long term allocations, and allocations that don't 
+	 * happen often.
 	 */
 	class GenAlloc
 	{ };
 
-	/**
-	 * @brief	Allocates the specified number of bytes.
-	 */
+	/** @endcond */
+
+	/** Allocates the specified number of bytes. */
 	template<class Alloc> 
 	inline void* bs_alloc(UINT32 count)
 	{
 		return MemoryAllocator<Alloc>::allocate(count);
 	}
 
-	/**
-	 * @brief	Allocates enough bytes to hold the specified type, but doesn't construct it.
-	 */
+	/** Allocates enough bytes to hold the specified type, but doesn't construct it. */
 	template<class T, class Alloc> 
 	inline T* bs_alloc()
 	{
 		return (T*)MemoryAllocator<Alloc>::allocate(sizeof(T));
 	}
 
-	/**
-	 * @brief	Creates and constructs an array of "count" elements.
-	 */
+	/** Creates and constructs an array of @p count elements. */
 	template<class T, class Alloc> 
 	inline T* bs_newN(UINT32 count)
 	{
@@ -135,27 +133,21 @@ namespace BansheeEngine
 		return ptr;
 	}
 
-	/**
-	 * @brief	Create a new object with the specified allocator and the specified parameters.
-	 */
+	/** Create a new object with the specified allocator and the specified parameters. */
 	template<class Type, class Alloc, class... Args>
 	Type* bs_new(Args &&...args)
 	{
 		return new (bs_alloc<Alloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
 	}
 
-	/**
-	 * @brief	Frees all the bytes allocated at the specified location.
-	 */
+	/** Frees all the bytes allocated at the specified location. */
 	template<class Alloc> 
 	inline void bs_free(void* ptr)
 	{
 		MemoryAllocator<Alloc>::free(ptr);
 	}
 
-	/**
-	 * @brief	Destructs and frees the specified object.
-	 */
+	/** Destructs and frees the specified object. */
 	template<class T, class Alloc = GenAlloc>
 	inline void bs_delete(T* ptr)
 	{
@@ -164,9 +156,7 @@ namespace BansheeEngine
 		MemoryAllocator<Alloc>::free(ptr);
 	}
 
-	/**
-	 * @brief	Destructs and frees the specified array of objects.
-	 */
+	/** Destructs and frees the specified array of objects. */
 	template<class T, class Alloc = GenAlloc>
 	inline void bs_deleteN(T* ptr, UINT32 count)
 	{
@@ -180,35 +170,27 @@ namespace BansheeEngine
 	/* Default versions of all alloc/free/new/delete methods which call GenAlloc */
 	/*****************************************************************************/
 
-	/**
-	 * @brief	Allocates the specified number of bytes.
-	 */
+	/** Allocates the specified number of bytes. */
 	inline void* bs_alloc(UINT32 count)
 	{
 		return MemoryAllocator<GenAlloc>::allocate(count);
 	}
 
-	/**
-	 * @brief	Allocates enough bytes to hold the specified type, but doesn't construct it.
-	 */
+	/** Allocates enough bytes to hold the specified type, but doesn't construct it. */
 	template<class T> 
 	inline T* bs_alloc()
 	{
 		return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
 	}
 
-	/**
-	 * @brief	Allocates enough bytes to hold an array of \p count elements the specified type, but doesn't construct them.
-	 */
+	/** Allocates enough bytes to hold an array of @p count elements the specified type, but doesn't construct them. */
 	template<class T> 
 	inline T* bs_allocN(UINT32 count)
 	{
 		return (T*)MemoryAllocator<GenAlloc>::allocate(count * sizeof(T));
 	}
 
-	/**
-	 * @brief	Creates and constructs an array of \p count elements.
-	 */
+	/** Creates and constructs an array of @p count elements. */
 	template<class T> 
 	inline T* bs_newN(UINT32 count)
 	{
@@ -220,18 +202,14 @@ namespace BansheeEngine
 		return ptr;
 	}
 
-	/**
-	 * @brief	Create a new object with the specified allocator and the specified parameters.
-	 */
+	/** Create a new object with the specified allocator and the specified parameters. */
 	template<class Type, class... Args>
 	Type* bs_new(Args &&...args)
 	{
 		return new (bs_alloc<GenAlloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
 	}
 
-	/**
-	 * @brief	Frees all the bytes allocated at the specified location.
-	 */
+	/** Frees all the bytes allocated at the specified location. */
 	inline void bs_free(void* ptr)
 	{
 		MemoryAllocator<GenAlloc>::free(ptr);
@@ -254,10 +232,9 @@ namespace BansheeEngine
 
 namespace BansheeEngine
 {
-    /**
-     * @brief	Allocator for the standard library that internally uses Banshee
-     * 			memory allocator.
-     */
+	/** @cond INTERNAL */
+
+    /** Allocator for the standard library that internally uses Banshee memory allocator. */
     template <class T, class Alloc = GenAlloc>
 	class StdAlloc 
 	{
@@ -268,9 +245,7 @@ namespace BansheeEngine
 		template<class T, class Alloc> bool operator==(const StdAlloc<T, Alloc>&) const noexcept { return true; }
 		template<class T, class Alloc> bool operator!=(const StdAlloc<T, Alloc>&) const noexcept { return false; }
 
-		/**
-		 * @brief	Allocate but don't initialize number elements of type T.
-		 */
+		/** Allocate but don't initialize number elements of type T. */
 		T* allocate(const size_t num) const
 		{
 			if (num == 0)
@@ -286,16 +261,18 @@ namespace BansheeEngine
 			return static_cast<T*>(pv);
 		}
 
-		/**
-		 * @brief	Deallocate storage p of deleted elements.
-		 */
+		/** Deallocate storage p of deleted elements. */
 		void deallocate(T* p, size_t num) const noexcept
 		{
 			bs_free<Alloc>((void*)p);
 		}
 	};
+
+	/** @endcond */
 }
 
+/** @} */
+
 #include "BsMemStack.h"
 #include "BsGlobalFrameAlloc.h"
 #include "BsMemAllocProfiler.h"

+ 57 - 58
BansheeUtility/Include/BsMemorySerializer.h

@@ -1,59 +1,58 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	  * @brief	Encodes/decodes an IReflectable object from/to memory. 
-	  */
-	class BS_UTILITY_EXPORT MemorySerializer
-	{
-		struct BufferPiece
-		{
-			UINT8* buffer;
-			UINT32 size;
-		};
-
-	public:
-		MemorySerializer();
-		~MemorySerializer();
-
-		/**
-		 * @brief	Parses the provided object, serializes all of its data as specified by its
-		 *			RTTIType and returns the data in the form of raw memory.
-		 *
-		 * @param	object			Object to encode.
-		 * @param	bytesWritten	Output value containing the total number of bytes it took to encode the object.
-		 * @param	allocator		Determines how is memory allocated. If not specified the default allocator is used.
-		 * @param	shallow			Determines how to handle referenced objects. If true then references will not be encoded
-		 *							and will be set to null. If false then references will be encoded as well and restored
-		 *							upon decoding.
-		 *
-		 * @return	A buffer containing the encoded object. It is up to the user to release the buffer memory when
-		 *			no longer needed.
-		 */
-		UINT8* encode(IReflectable* object, UINT32& bytesWritten, std::function<void*(UINT32)> allocator = nullptr, 
-			bool shallow = false);
-
-		/**
-		 * @brief	Deserializes an IReflectable object by reading the binary data from the provided
-		 *			memory location.
-		 */
-		std::shared_ptr<IReflectable> decode(UINT8* buffer, UINT32 bufferSize);
-
-	private:
-		Vector<BufferPiece> mBufferPieces;
-
-		/**
-		 * @brief	Called by the binary serializer whenever the buffer gets full.
-		 */
-		UINT8* flushBuffer(UINT8* bufferStart, UINT32 bytesWritten, UINT32& newBufferSize);
-
-		/************************************************************************/
-		/* 								CONSTANTS	                     		*/
-		/************************************************************************/
-	private:
-		static const UINT32 WRITE_BUFFER_SIZE = 16384;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	/**	Encodes/decodes an IReflectable object from/to memory. */
+	class BS_UTILITY_EXPORT MemorySerializer
+	{
+		struct BufferPiece
+		{
+			UINT8* buffer;
+			UINT32 size;
+		};
+
+	public:
+		MemorySerializer();
+		~MemorySerializer();
+
+		/**
+		 * Parses the provided object, serializes all of its data as specified by its RTTIType and returns the data in the 
+		 * form of raw memory.
+		 *
+		 * @param[in]	object			Object to encode.
+		 * @param[in]	bytesWritten	Output value containing the total number of bytes it took to encode the object.
+		 * @param[in]	allocator		Determines how is memory allocated. If not specified the default allocator is used.
+		 * @param[in]	shallow			Determines how to handle referenced objects. If true then references will not be 
+		 *								encoded and will be set to null. If false then references will be encoded as well 
+		 *								and restored upon decoding.
+		 *
+		 * @return						A buffer containing the encoded object. It is up to the user to release the buffer 
+		 *								memory when no longer needed.
+		 */
+		UINT8* encode(IReflectable* object, UINT32& bytesWritten, std::function<void*(UINT32)> allocator = nullptr, 
+			bool shallow = false);
+
+		/** Deserializes an IReflectable object by reading the binary data from the provided memory location. */
+		std::shared_ptr<IReflectable> decode(UINT8* buffer, UINT32 bufferSize);
+
+	private:
+		Vector<BufferPiece> mBufferPieces;
+
+		/** Called by the binary serializer whenever the buffer gets full. */
+		UINT8* flushBuffer(UINT8* bufferStart, UINT32 bytesWritten, UINT32& newBufferSize);
+
+		/************************************************************************/
+		/* 								CONSTANTS	                     		*/
+		/************************************************************************/
+	private:
+		static const UINT32 WRITE_BUFFER_SIZE = 16384;
+	};
+
+	/** @} */
 }

+ 49 - 48
BansheeUtility/Include/BsMessageHandler.h

@@ -1,49 +1,50 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsModule.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Allows you to transparently pass messages
-	 *			between different systems.
-	 *
-	 * @note		Sim thread only.
-	 */
-	class BS_UTILITY_EXPORT MessageHandler : public Module<MessageHandler>
-	{
-		struct MessageHandlerData
-		{
-			UINT32 id;
-			std::function<void()> callback;
-		};
-
-	public:
-		MessageHandler();
-
-		/**
-		 * @brief	Sends a message to all subscribed listeners.
-		 */
-		void send(MessageId message);
-
-		/**
-		 * @brief	Subscribes a message listener for the specified message.
-		 *			Provided callback will be triggered whenever that message
-		 *			gets sent.
-		 *
-		 * @returns	A handle to the message subscription that you can use to
-		 *			unsubscribe from listening.
-		 */
-		HMessage listen(MessageId message, std::function<void()> callback);
-
-	private:
-		friend class HMessage;
-		void unsubscribe(UINT32 handleId);
-
-		Map<UINT32, Vector<MessageHandlerData>> mMessageHandlers;
-		Map<UINT32, UINT32> mHandlerIdToMessageMap;
-
-		UINT32 mNextCallbackId;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/**
+	 * Allows you to transparently pass messages between different systems.
+	 *
+	 * @note Sim thread only.
+	 */
+	class BS_UTILITY_EXPORT MessageHandler : public Module<MessageHandler>
+	{
+		struct MessageHandlerData
+		{
+			UINT32 id;
+			std::function<void()> callback;
+		};
+
+	public:
+		MessageHandler();
+
+		/** Sends a message to all subscribed listeners. */
+		void send(MessageId message);
+
+		/**
+		 * Subscribes a message listener for the specified message. Provided callback will be triggered whenever that 
+		 * message gets sent.
+		 *
+		 * @return	A handle to the message subscription that you can use to unsubscribe from listening.
+		 */
+		HMessage listen(MessageId message, std::function<void()> callback);
+
+	private:
+		friend class HMessage;
+		void unsubscribe(UINT32 handleId);
+
+		Map<UINT32, Vector<MessageHandlerData>> mMessageHandlers;
+		Map<UINT32, UINT32> mHandlerIdToMessageMap;
+
+		UINT32 mNextCallbackId;
+	};
+
+	/** @} */
 }

+ 64 - 63
BansheeUtility/Include/BsMessageHandlerFwd.h

@@ -1,64 +1,65 @@
-#pragma once
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Identifier for message used with the global messaging system.
-	 *
-	 * @note	Primary purpose of this class is to avoid expensive string compare (i.e. button names),
-	 * 			and instead use a unique message identifier for compare. Generally you want to create
-	 * 			one of these using the message name, and then store it for later use.
-	 *
-	 *			This class is not thread safe and should only be used on the sim thread.
-	 */
-	class BS_UTILITY_EXPORT MessageId
-	{
-	public:
-		MessageId();
-		MessageId(const String& name);
-
-		bool operator== (const MessageId& rhs) const
-		{
-			return (mMsgIdentifier == rhs.mMsgIdentifier);
-		}
-	private:
-		friend class MessageHandler;
-
-		static Map<String, UINT32> UniqueMessageIds;
-		static UINT32 NextMessageId;
-
-		UINT32 mMsgIdentifier;
-	};
-
-	/**
-	 * @brief	Handle to a subscription for a specific message
-	 *			in the global messaging system.
-	 */
-	class BS_UTILITY_EXPORT HMessage
-	{
-	public:
-		HMessage();
-
-		/**
-		* @brief	Disconnects the message listener so it will no longer
-		*			receive events from the messaging system.
-		*/
-		void disconnect();
-
-	private:
-		friend class MessageHandler;
-
-		HMessage(UINT32 id);
-
-		UINT32 mId;
-	};
-
-	/**
-	 * @brief	Sends a message using the global messaging system.
-	 *
-	 * @note	Sim thread only.
-	 */
-	void BS_UTILITY_EXPORT sendMessage(MessageId message);
-
-	class MessageHandler;
+#pragma once
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/**
+	 * Identifier for message used with the global messaging system.
+	 *
+	 * @note	
+	 * Primary purpose of this class is to avoid expensive string compare (i.e. button names), and instead use a unique 
+	 * message identifier for compare. Generally you want to create one of these using the message name, and then store it 
+	 * for later use.
+	 * @note
+	 * This class is not thread safe and should only be used on the sim thread.
+	 */
+	class BS_UTILITY_EXPORT MessageId
+	{
+	public:
+		MessageId();
+		MessageId(const String& name);
+
+		bool operator== (const MessageId& rhs) const
+		{
+			return (mMsgIdentifier == rhs.mMsgIdentifier);
+		}
+	private:
+		friend class MessageHandler;
+
+		static Map<String, UINT32> UniqueMessageIds;
+		static UINT32 NextMessageId;
+
+		UINT32 mMsgIdentifier;
+	};
+
+	/** Handle to a subscription for a specific message in the global messaging system. */
+	class BS_UTILITY_EXPORT HMessage
+	{
+	public:
+		HMessage();
+
+		/** Disconnects the message listener so it will no longer receive events from the messaging system. */
+		void disconnect();
+
+	private:
+		friend class MessageHandler;
+
+		HMessage(UINT32 id);
+
+		UINT32 mId;
+	};
+
+	/**
+	 * Sends a message using the global messaging system.
+	 *
+	 * @note	Sim thread only.
+	 */
+	void BS_UTILITY_EXPORT sendMessage(MessageId message);
+
+	class MessageHandler;
+
+	/** @} */
 }

+ 170 - 174
BansheeUtility/Include/BsModule.h

@@ -1,175 +1,171 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Represents one engine module. Essentially it is a specialized type of singleton.
-	 * 			Module must be manually started up and shut down before and after use.
-	 */
-	template <class T>
-	class Module
-	{
-		public:
-		/**
-		 * @brief	Returns a reference to the module instance. Module has to have been started up
-		 * 			first otherwise an exception will be thrown.
-		 */
-		static T& instance()
-		{
-			if(isShutDown())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Trying to access a module but it hasn't been started up yet.");
-			}
-
-			if (isDestroyed())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Trying to access a destroyed module.");
-			}
-
-			return *_instance();
-		}
-
-		/**
-		 * @brief	Returns a pointer to the module instance. Module has to have been started up
-		 * 			first otherwise an exception will be thrown.
-		 */
-		static T* instancePtr()
-		{
-			if (isShutDown())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Trying to access a module but it hasn't been started up yet.");
-			}
-
-			if (isDestroyed())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Trying to access a destroyed module.");
-			}
-
-			return _instance();
-		}
-		
-		/**
-		 * @brief	Constructs and starts the module using the specified parameters.
-		 */
-		template<class ...Args>
-		static void startUp(Args &&...args)
-		{
-			if (!isShutDown())
-				BS_EXCEPT(InternalErrorException, "Trying to start an already started module.");
-
-			_instance() = bs_new<T>(std::forward<Args>(args)...);
-			isShutDown() = false;
-
-			((Module*)_instance())->onStartUp();
-		}
-
-		/**
-		 * @brief	Constructs and starts a specialized type of the module. Provided type
-		 *			must derive from type the Module is initialized with.
-		 */
-		template<class SubType, class ...Args>
-		static void startUp(Args &&...args)
-		{
-			static_assert(std::is_base_of<T, SubType>::value, "Provided type is not derived from type the Module is initialized with.");
-
-			if (!isShutDown())
-				BS_EXCEPT(InternalErrorException, "Trying to start an already started module.");
-
-			_instance() = bs_new<SubType>(std::forward<Args>(args)...);
-			isShutDown() = false;
-
-			((Module*)_instance())->onStartUp();
-		}
-
-		/**
-		 * @brief	Shuts down this module and frees any resources it is using.
-		 */
-		static void shutDown()
-		{
-			if (isShutDown() || isDestroyed())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Trying to shut down an already shut down module.");
-			}
-
-			((Module*)_instance())->onShutDown();
-
-			bs_delete(_instance());
-			isDestroyed() = true;
-		}
-
-		/**
-		 * @brief	Query if the module has been started.
-		 */
-		static bool isStarted()
-		{
-			return !isShutDown() && !isDestroyed();
-		}
-
-	protected:
-		Module() 
-		{ 
-		}
-
-		virtual ~Module()
-		{ 
-			_instance() = nullptr;
-			isDestroyed() = true;
-		}
-
-		Module(const Module&) { }
-		Module& operator=(const Module&) { return *this; }
-
-		/**
-		 * @brief	Override if you want your module to be notified once it has been constructed and started.
-		 * 			
-		 * @note	Useful when your module is polymorphic and you cannot perform 
-		 * 			some implementation specific initialization in constructor itself.
-		 */
-		virtual void onStartUp() {}
-
-		/**
-		 * @brief	Override if you want your module to be notified just before it is deleted.
-		 * 			
-		 * @note	Useful when your module is polymorphic and you might want to perform some 
-		 * 			kind of clean up perhaps overriding that of a base class.
-		 */
-		virtual void onShutDown() {}
-
-		/**
-		 * @brief	Returns a singleton instance of this module. 
-		 */
-		static T*& _instance()
-		{
-			static T* inst = nullptr;
-			return inst;
-		}
-
-		/**
-		 * @brief	Checks has the Module been shut down.
-		 *			
-		 * @note	If module was never even started, this will return false.
-		 */
-		static bool& isDestroyed()
-		{
-			static bool inst = false;
-			return inst;
-		}
-
-		/**
-		 * @brief	Checks has the Module been started up.
-		 */
-		static bool& isShutDown()
-		{
-			static bool inst = true;
-			return inst;
-		}
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/**
+	 * Represents one engine module. Essentially it is a specialized type of singleton. Module must be manually started up 
+	 * and shut down before and after use.
+	 */
+	template <class T>
+	class Module
+	{
+		public:
+		/**
+		 * Returns a reference to the module instance. Module has to have been started up first otherwise an exception will
+		 * be thrown.
+		 */
+		static T& instance()
+		{
+			if(isShutDown())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Trying to access a module but it hasn't been started up yet.");
+			}
+
+			if (isDestroyed())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Trying to access a destroyed module.");
+			}
+
+			return *_instance();
+		}
+
+		/**
+		 * Returns a pointer to the module instance. Module has to have been started up first otherwise an exception will 
+		 * be thrown.
+		 */
+		static T* instancePtr()
+		{
+			if (isShutDown())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Trying to access a module but it hasn't been started up yet.");
+			}
+
+			if (isDestroyed())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Trying to access a destroyed module.");
+			}
+
+			return _instance();
+		}
+		
+		/** Constructs and starts the module using the specified parameters. */
+		template<class ...Args>
+		static void startUp(Args &&...args)
+		{
+			if (!isShutDown())
+				BS_EXCEPT(InternalErrorException, "Trying to start an already started module.");
+
+			_instance() = bs_new<T>(std::forward<Args>(args)...);
+			isShutDown() = false;
+
+			((Module*)_instance())->onStartUp();
+		}
+
+		/**
+		 * Constructs and starts a specialized type of the module. Provided type must derive from type the Module is 
+		 * initialized with.
+		 */
+		template<class SubType, class ...Args>
+		static void startUp(Args &&...args)
+		{
+			static_assert(std::is_base_of<T, SubType>::value, "Provided type is not derived from type the Module is initialized with.");
+
+			if (!isShutDown())
+				BS_EXCEPT(InternalErrorException, "Trying to start an already started module.");
+
+			_instance() = bs_new<SubType>(std::forward<Args>(args)...);
+			isShutDown() = false;
+
+			((Module*)_instance())->onStartUp();
+		}
+
+		/** Shuts down this module and frees any resources it is using. */
+		static void shutDown()
+		{
+			if (isShutDown() || isDestroyed())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Trying to shut down an already shut down module.");
+			}
+
+			((Module*)_instance())->onShutDown();
+
+			bs_delete(_instance());
+			isDestroyed() = true;
+		}
+
+		/** Query if the module has been started. */
+		static bool isStarted()
+		{
+			return !isShutDown() && !isDestroyed();
+		}
+
+	protected:
+		Module() 
+		{ 
+		}
+
+		virtual ~Module()
+		{ 
+			_instance() = nullptr;
+			isDestroyed() = true;
+		}
+
+		Module(const Module&) { }
+		Module& operator=(const Module&) { return *this; }
+
+		/**
+		 * Override if you want your module to be notified once it has been constructed and started.
+		 * 			
+		 * @note	Useful when your module is polymorphic and you cannot perform some implementation specific 
+		 *			initialization in constructor itself.
+		 */
+		virtual void onStartUp() {}
+
+		/**
+		 * Override if you want your module to be notified just before it is deleted.
+		 * 			
+		 * @note	Useful when your module is polymorphic and you might want to perform some kind of clean up perhaps 
+		 *			overriding that of a base class.
+		 */
+		virtual void onShutDown() {}
+
+		/** Returns a singleton instance of this module. */
+		static T*& _instance()
+		{
+			static T* inst = nullptr;
+			return inst;
+		}
+
+		/**
+		 * Checks has the Module been shut down.
+		 *			
+		 * @note	If module was never even started, this will return false.
+		 */
+		static bool& isDestroyed()
+		{
+			static bool inst = false;
+			return inst;
+		}
+
+		/** Checks has the Module been started up. */
+		static bool& isShutDown()
+		{
+			static bool inst = true;
+			return inst;
+		}
+	};
+
+	/** @} */
 }

+ 623 - 712
BansheeUtility/Include/BsPath.h

@@ -1,712 +1,623 @@
-#pragma once
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	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();
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path string. 
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path null terminated string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path null terminated string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	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); }
-
-		/**
-		 * @brief	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); }
-
-		/**
-		* @brief	Gets a directory name with the specified index from the path.
-		*/
-		const WString& operator[] (UINT32 idx) const { return getWDirectory(idx); }
-
-		/**
-		 * @brief	Swap internal data with another Path object.
-		 */
-		void swap(Path& path);
-
-		/**
-		 * @brief	Create a path from another Path object.
-		 */
-		void assign(const Path& path);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path null terminated string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Constructs a path by parsing the provided path null terminated string.
-		 *			Throws exception if provided path is not valid.
-		 *
-		 * @param	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);
-
-		/**
-		 * @brief	Converts the path in a string according to platform path rules.
-		 *
-		 * @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;
-
-		/**
-		 * @brief	Converts the path in a string according to platform path rules.
-		 *
-		 * @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;
-
-		/**
-		 * @brief	Checks is the path a directory (contains no file-name).
-		 */
-		bool isDirectory() const { return mFilename.empty(); }
-
-		/**
-		 * @brief	Checks does the path point to a file.
-		 */
-		bool isFile() const { return !mFilename.empty(); }
-
-		/**
-		 * @brief	Checks is the contained path absolute.
-		 */
-		bool isAbsolute() const { return mIsAbsolute; }
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	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();
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	Appends another path to the end of this path.
-		 */
-		Path& append(const Path& path);
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	Change or set the filename in the path.
-		 */
-		void setFilename(const WString& filename) { mFilename = filename; }
-
-		/**
-		 * @brief	Change or set the filename in the path.
-		 */
-		void setFilename(const String& filename) { mFilename = BansheeEngine::toWString(filename); }
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @brief	Change or set the extension of the filename in the path.
-		 *
-		 * @param	extension	Extension with a leading ".".
-		 */
-		void setExtension(const WString& extension);
-
-		/**
-		 * @brief	Change or set the extension of the filename in the path.
-		 *
-		 * @param	extension	Extension with a leading ".".
-		 */
-		void setExtension(const String& extension);
-
-		/**
-		 * @brief	Returns a filename in the path.
-		 *
-		 * @param	extension	If true, returned filename will contain an extension.
-		 */
-		WString getWFilename(bool extension = true) const;
-
-		/**
-		 * @brief	Returns a filename in the path.
-		 *
-		 * @param	extension	If true, returned filename will contain an extension.
-		 */
-		String getFilename(bool extension = true) const;
-
-		/**
-		 * @brief	Returns file extension with the leading ".".
-		 */
-		WString getWExtension() const;
-
-		/**
-		 * @brief	Returns file extension with the leading ".".
-		 */
-		String getExtension() const;
-
-		/**
-		 * @brief	Gets the number of directories in the path.
-		 */
-		UINT32 getNumDirectories() const { return (UINT32)mDirectories.size(); }
-
-		/**
-		 * @brief	Gets a directory name with the specified index from the path.
-		 */
-		const WString& getWDirectory(UINT32 idx) const;
-
-		/**
-		 * @brief	Gets a directory name with the specified index from the path.
-		 */
-		String getDirectory(UINT32 idx) const;
-
-		/**
-		 * @brief	Returns path device (e.g. drive, volume, etc.) if one exists in the path.
-		 */
-		const WString& getWDevice() const { return mDevice; }
-
-		/**
-		 * @brief	Returns path device (e.g. drive, volume, etc.) if one exists in the path.
-		 */
-		String getDevice() const { return BansheeEngine::toString(mDevice); }
-
-		/**
-		 * @brief	Returns path node (e.g. network name) if one exists in the path.
-		 */
-		const WString& getWNode() const { return mNode; }
-
-		/**
-		 * @brief	Returns path node (e.g. network name) if one exists in the path.
-		 */
-		String getNode() const { return BansheeEngine::toString(mNode); }
-
-		/**
-		 * @brief	Gets last element in the path, filename if it exists, otherwise the last directory.
-		 *			If no directories exist returns device or node.
-		 *
-		 * @param	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;
-
-		/**
-		 * @brief	Gets last element in the path, filename if it exists, otherwise the last directory.
-		 *			If no directories exist returns device or node.
-		 *
-		 * @param	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;
-
-		/**
-		 * @brief	Clears the path to nothing.
-		 */
-		void clear();
-
-		/**
-		 * @brief	Returns true if no path has been set.
-		 */
-		bool isEmpty() const { return mDirectories.empty() && mFilename.empty() && mDevice.empty() && mNode.empty(); }
-
-		/**
-		 * @brief	Concatenates two paths.
-		 */
-		Path operator+ (const Path& rhs) const;
-
-		/**
-		 * @brief	Concatenates two paths.
-		 */
-		Path& operator+= (const Path& rhs);
-
-		/**
-		 * @brief	Compares two path elements (i.e. filenames, directory names, etc.)
-		 */
-		static bool comparePathElem(const WString& left, const WString& right);
-
-		/**
-		 * @brief	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:
-		/**
-		* @brief	Constructs a path by parsing the provided raw string data.
-		*			Throws exception if provided path is not valid.
-		*
-		* @param	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);
-
-		/**
-		* @brief	Constructs a path by parsing the provided raw string data.
-		*			Throws exception if provided path is not valid.
-		*
-		* @param	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);
-
-		/**
-		 * @brief	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++;
-				}
-			}
-		}
-
-		/**
-		* @brief	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); }
-
-		/**
-		 * @brief	Build a Windows path string from internal path data.
-		 */
-		WString buildWindows() const;
-
-		/**
-		* @brief	Build a Unix path string from internal path data.
-		*/
-		WString buildUnix() const;
-
-		/**
-		 * @brief	Add new directory to the end of the path. 
-		 */
-		void pushDirectory(const WString& dir);
-
-		/**
-		* @brief	Add new directory to the end of the path.
-		*/
-		void pushDirectory(const String& dir);
-
-		/**
-		 * @brief	Helper method that throws invalid path exception. 
-		 */
-		void throwInvalidPathException(const WString& path) const;
-
-		/**
-		* @brief	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;
-	};
-
-	/**
-	* @brief	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;
-		}
-	};
-}
-
-/**
-* @brief	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;
-	}
-};
+#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 */
+
+/** @} */

+ 104 - 107
BansheeUtility/Include/BsPlatformUtility.h

@@ -1,108 +1,105 @@
-#pragma once
-
-namespace BansheeEngine
-{
-	struct MACAddress;
-
-	/**
-	 * @brief	Possible type of platform file dialogs.
-	 */
-	enum class FileDialogType
-	{
-		OpenFile = 0x0, 
-		OpenFolder = 0x1, 
-		Save = 0x2,
-		Multiselect = 0x10000,
-		TypeMask = 0xFFFF
-	};
-
-	/**
-	 * @brief	Provides access to various operating system specific utility functions.
-	 */
-	class BS_UTILITY_EXPORT PlatformUtility
-	{
-	public:
-		/**
-		 * @brief	Terminates the current process.
-		 * 			
-		 * @param	force	True if the process should be forcefully terminated with no cleanup.
-		 */
-		static void terminate(bool force = false);
-
-		/**
-		 * @brief	Queries the internal system performance counter you can use for very precise time
-		 * 			measurements. Value is in milliseconds.
-		 *
-		 * @note	Thread safe.
-		 */
-		static double queryPerformanceTimerMs();
-
-		/**
-		 * @brief	Adds a string to the clipboard.
-		 *
-		 * @note	Thread safe.
-		 */
-		static void copyToClipboard(const WString& string);
-
-		/**
-		 * @brief	Reads a string from the clipboard and returns it. If there is no
-		 * 			string in the clipboard it returns an empty string.
-		 *
-		 * @note	Both wide and normal strings will be read, but normal strings will be converted to
-		 * 			a wide string before returning.
-		 *
-		 *			Thread safe.
-		 */
-		static WString copyFromClipboard();
-
-		/**
-		 * @brief	Converts a keyboard key-code to a Unicode character.
-		 *
-		 * @note	Normally this will output a single character, but it can happen it outputs multiple 
-		 *			in case a accent/diacritic character could not be combined with the virtual key into 
-		 *			a single character.
-		 */
-		static WString keyCodeToUnicode(UINT32 keyCode);
-
-		/**
-		 * @brief	Populates the provided buffer with a MAC address of the first available
-		 *			adapter, if one exists. If no adapters exist, returns false.
-		 */
-		static bool getMACAddress(MACAddress& address);
-
-		/**
-		 * @brief	Creates a new universally unique identifier and returns it as a string.
-		 */
-		static String generateUUID();
-
-		/**
-		 * @brief	Opens the provided file or folder using the default application for that file type, as specified
-		 * 			by the operating system.
-		 *
-		 * @param	path	Absolute path to the file or folder to open.
-		 */
-		static void open(const Path& path);
-
-		/**
-		 * @brief	Displays a platform specific file/folder open/save dialog.
-		 *
-		 * @param	type		Type of dialog to open.
-		 * @param	defaultPath	Initial path the dialog will be set to once opened.
-		 * @param	filterList	Semi-colon separated list of file names or types to display in the dialog, e.g. "exe;txt;png".
-		 *						Ignored if dialog is to display folders instead of files.
-		 * @param	paths		Output list of selected file or folder paths (if any).
-		 *
-		 * @return	True if file was selected and false if selection was canceled.
-		 */
-		static bool openBrowseDialog(FileDialogType type, const Path& defaultPath, const WString& filterList,
-			Vector<Path>& paths);
-	};
-
-	/**
-	 * @brief Represents a MAC (ethernet) address.
-	 */
-	struct MACAddress
-	{
-		UINT8 value[6];
-	};
+#pragma once
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	struct MACAddress;
+
+	/** Possible type of platform file dialogs. */
+	enum class FileDialogType
+	{
+		OpenFile = 0x0, 
+		OpenFolder = 0x1, 
+		Save = 0x2,
+		Multiselect = 0x10000,
+		TypeMask = 0xFFFF
+	};
+
+	/** Provides access to various operating system specific utility functions. */
+	class BS_UTILITY_EXPORT PlatformUtility
+	{
+	public:
+		/**
+		 * Terminates the current process.
+		 * 			
+		 * @param[in]	force	True if the process should be forcefully terminated with no cleanup.
+		 */
+		static void terminate(bool force = false);
+
+		/**
+		 * Queries the internal system performance counter you can use for very precise time measurements. Value is in 
+		 * milliseconds.
+		 *
+		 * @note	Thread safe.
+		 */
+		static double queryPerformanceTimerMs();
+
+		/**
+		 * Adds a string to the clipboard.
+		 *
+		 * @note	Thread safe.
+		 */
+		static void copyToClipboard(const WString& string);
+
+		/**
+		 * Reads a string from the clipboard and returns it. If there is no string in the clipboard it returns an empty 
+		 * string.
+		 *
+		 * @note	
+		 * Both wide and normal strings will be read, but normal strings will be converted to a wide string before returning.
+		 * @note
+		 * Thread safe.
+		 */
+		static WString copyFromClipboard();
+
+		/**
+		 * Converts a keyboard key-code to a Unicode character.
+		 *
+		 * @note	
+		 * Normally this will output a single character, but it can happen it outputs multiple in case a accent/diacritic 
+		 * character could not be combined with the virtual key into a single character.
+		 */
+		static WString keyCodeToUnicode(UINT32 keyCode);
+
+		/**
+		 * Populates the provided buffer with a MAC address of the first available adapter, if one exists. If no adapters 
+		 * exist, returns false.
+		 */
+		static bool getMACAddress(MACAddress& address);
+
+		/** Creates a new universally unique identifier and returns it as a string. */
+		static String generateUUID();
+
+		/**
+		 * Opens the provided file or folder using the default application for that file type, as specified by the operating 
+		 * system.
+		 *
+		 * @param[in]	path	Absolute path to the file or folder to open.
+		 */
+		static void open(const Path& path);
+
+		/**
+		 * Displays a platform specific file/folder open/save dialog.
+		 *
+		 * @param[in]	type		Type of dialog to open.
+		 * @param[in]	defaultPath	Initial path the dialog will be set to once opened.
+		 * @param[in]	filterList	Semi-colon separated list of file names or types to display in the dialog, e.g. "exe;txt;png".
+		 *							Ignored if dialog is to display folders instead of files.
+		 * @param[out]	paths		Output list of selected file or folder paths (if any).
+		 * @return					True if file was selected and false if selection was canceled.
+		 */
+		static bool openBrowseDialog(FileDialogType type, const Path& defaultPath, const WString& filterList,
+			Vector<Path>& paths);
+	};
+
+	/** Represents a MAC (ethernet) address. */
+	struct MACAddress
+	{
+		UINT8 value[6];
+	};
+
+	/** @} */
 }

+ 20 - 0
BansheeUtility/Include/BsPrerequisitesUtil.h

@@ -16,6 +16,10 @@
  *  A set of systems for defining and using run-time type information.
  */
 
+ /** @defgroup Serialization Serialization
+ *  A set of systems for serializing and deserializing native objects.
+ */
+
 /** @defgroup Memory Memory
  *  A set of methods and classes meant to manipulate memory.
  */
@@ -28,6 +32,22 @@
  *  Contains various functionality used to help with debugging.
  */
 
+/** @defgroup Error Error handling
+ *  Contains various functionality used for handling and reporting errors.
+ */
+
+/** @defgroup Filesystem File system
+ *  Contains various functionality used for manipulating, reading and writing files.
+ */
+
+/** @defgroup General General
+ *  Contains general utility functionality that doesn't fit in any other category.
+ */
+
+/** @defgroup Image Image
+ *  Contains various utility methods for manipulating images.
+ */
+
 /** @} */
 
 // 0 - No thread support

+ 187 - 185
BansheeUtility/Include/BsRTTIField.h

@@ -1,186 +1,188 @@
-#pragma once
-
-#include <string>
-
-#include <type_traits>
-
-#include "BsPrerequisitesUtil.h"
-#include "BsIReflectable.h"
-#include "BsManagedDataBlock.h"
-#include "BsException.h"
-#include "BsAny.h"
-
-namespace BansheeEngine
-{
-	class RTTITypeBase;
-
-	/**
-	 * @brief	Types of fields we can serialize:
-	 * 			
-	 * - Plain - Native data types, POD (Plain old data) structures, or in general types we don't want to (or can't) inherit from IReflectable.   
-	 *			 Type must be copyable by memcpy.
-	 *			  
-	 * - DataBlock - Array of bytes of a certain size. When returning a data block you may specify if its managed or unmanaged.  
-	 *				 Managed data blocks have their buffers deleted after they go out of scope. This is useful if you need to return some
-	 *				 temporary data. On the other hand if the data in the block belongs to your class, and isn't temporary, keep the data unmanaged.
-	 *				 
-	 * - Reflectable - Field that is of IReflectable type. Cannot be a pointer to IReflectable and must be actual value type.   
-	 *				   Type and its fields are serialized recursively. Supports versioning so you may add/remove fields from the type
-	 *				   without breaking previously serialized data.
-	 * 
-	 * - ReflectablePtr - A pointer to IReflectable. Same as "Reflectable" except that data isn't serialized as a value type,  
-	 *					  but as a pointer, which may be referenced by multiple other instances. All references are saved upon
-	 *					  serialization and restored upon deserialization.
-	 */
-	enum SerializableFieldType
-	{
-		SerializableFT_Plain,
-		SerializableFT_DataBlock,
-		SerializableFT_Reflectable,
-		SerializableFT_ReflectablePtr
-	};
-
-	/**
-	 * @brief	Various flags you can assign to RTTI fields.
-	 */
-	enum RTTIFieldFlag
-	{
-		// This flag is only used on field types of ReflectablePtr type, and it is used
-		// to solve circular references. Circular references cause an issue when deserializing, 
-		// as the algorithm doesn't know which object to deserialize first. By making one of 
-		// the references weak, you tell the algorithm that it doesn't have to guarantee 
-		// the object will be fully deserialized before being assigned to the field.
-		//
-		// In short: If you make a reference weak, when "set" method of that field is called,
-		// it is not guaranteed the value provided is fully initialized, so you should not access any of its
-		// data until deserialization is fully complete. You only need to use this flag if the RTTI system
-		// complains that is has found a circular reference.
-		RTTI_Flag_WeakRef = 0x01,
-		// This flags signals various systems that the flagged field should not be searched when looking for 
-		// object references. This normally means the value of this field will no be retrieved during reference
-		// searches but it will likely still be retrieved during other operations (e.g. serialization).
-		// This is used as an optimization to avoid retrieving values of potentially very expensive fields that
-		// would not contribute to the reference search anyway. Whether or not a field contributes to the reference
-		// search depends on the search and should be handled on a case by case basis.
-		RTTI_Flag_SkipInReferenceSearch = 0x02
-	};
-
-	/**
-	 * @brief	Structure that keeps meta-data concerning a single class field. You can use
-	 * 			this data for setting and getting values for that field on a specific class instance.
-	 * 			
-	 *			Class also contains an unique field name, and an unique field ID. Fields may contain
-	 *			single types or an array of types. See "SerializableFieldType" for information about 
-	 *			specific field types.
-	 * 			
-	 * @note	Most of the methods for retrieving and setting data accept "void *" for both
-	 * 			the data and the owning class instance. It is up to the caller to ensure that
-	 * 			pointer is of proper type.
-	 */
-	struct BS_UTILITY_EXPORT RTTIField
-	{
-		Any valueGetter;
-		Any valueSetter;
-
-		Any arraySizeGetter;
-		Any arraySizeSetter;
-
-		String mName;
-		UINT16 mUniqueId;
-		bool mIsVectorType;
-		SerializableFieldType mType;
-		UINT64 mFlags;
-
-		bool isPlainType() { return mType == SerializableFT_Plain; }
-		bool isDataBlockType() { return mType == SerializableFT_DataBlock; }
-		bool isReflectableType() { return mType == SerializableFT_Reflectable; }
-		bool isReflectablePtrType() { return mType == SerializableFT_ReflectablePtr; }
-		bool isArray() const { return mIsVectorType; }
-
-		/**
-		 * @brief	Returns flags that were set in the field meta-data.
-		 */
-		UINT64 getFlags() const { return mFlags; }
-
-		/**
-		 * @brief	Gets the size of an array contained by the field, if the field
-		 * 			represents an array. Throws exception if field is not an array.
-		 */
-		virtual UINT32 getArraySize(void* object) = 0;
-
-		/**
-		 * @brief	Changes the size of an array contained by the field, if the field
-		 * 			represents an array. Throws exception if field is not an array.
-		 */
-		virtual void setArraySize(void* object, UINT32 size) = 0;
-
-		/**
-		 * @brief	Returns the type id for the type used in this field.
-		 */
-		virtual UINT32 getTypeSize() = 0;
-
-		/**
-		 * @brief	Query if the field has dynamic size. 
-		 *
-		 * @note	Field should have dynamic size if:
-		 * 			 - The field can have varying size  
-		 * 			 - The field size is over 255  
-		 * 			 
-		 * 			Types like integers, floats, bools, POD structs dont have dynamic size.
-		 * 			Types like strings, vectors, maps do.
-		 * 			
-		 *			If your type has a static size but that size exceeds 255 bytes you also need to
-		 *			use dynamic field size. (You will be warned during compilation if you don't follow this rule)
-		 */
-		virtual bool hasDynamicSize() = 0;
-
-		/**
-		 * @brief	Throws an exception if this field doesn't contain a plain value.
-		 *
-		 * @param	array	If true then the field must support plain array type.
-		 */
-		void checkIsPlain(bool array);
-
-		/**
-		 * @brief	Throws an exception if this field doesn't contain a complex value.
-		 *
-		 * @param	array	If true then the field must support complex array type.
-		 */
-		void checkIsComplex(bool array);
-
-		/**
-		 * @brief	Throws an exception if this field doesn't contain a complex pointer value.
-		 *
-		 * @param	array	If true then the field must support complex pointer array type.
-		 */
-		void checkIsComplexPtr(bool array);
-
-		/**
-		 * @brief	Throws an exception depending if the field is or isn't an array.
-		 *
-		 * @param	array	If true, then exception will be thrown if field is not an array.
-		 * 					If false, then it will be thrown if field is an array.
-		 */
-		void checkIsArray(bool array);
-
-		/**
-		 * @brief	Throws an exception if this field doesn't contain a data block value.
-		 */
-		void checkIsDataBlock();
-
-	protected:
-		void initAll(Any valueGetter, Any valueSetter, Any arraySizeGetter, Any arraySizeSetter,
-			String mName, UINT16 mUniqueId, bool mIsVectorType, SerializableFieldType type, UINT64 flags)
-		{
-			this->valueGetter = valueGetter;
-			this->valueSetter = valueSetter;
-			this->arraySizeGetter = arraySizeGetter;
-			this->arraySizeSetter = arraySizeSetter;
-			this->mName = mName;
-			this->mUniqueId = mUniqueId;
-			this->mIsVectorType = mIsVectorType;
-			this->mType = type;
-			this->mFlags = flags;
-		}
-	};
+#pragma once
+
+#include <string>
+
+#include <type_traits>
+
+#include "BsPrerequisitesUtil.h"
+#include "BsIReflectable.h"
+#include "BsManagedDataBlock.h"
+#include "BsException.h"
+#include "BsAny.h"
+
+namespace BansheeEngine
+{
+	class RTTITypeBase;
+
+	/** @cond INTERNAL */
+	/** @addtogroup RTTI
+	 *  @{
+	 */
+
+	/**
+	 * Types of fields we can serialize:
+	 * 			
+	 * - Plain - Native data types, POD (Plain old data) structures, or in general types we don't want to (or can't) inherit from IReflectable.   
+	 *			 Type must be copyable by memcpy.
+	 *			  
+	 * - DataBlock - Array of bytes of a certain size. When returning a data block you may specify if its managed or unmanaged.  
+	 *				 Managed data blocks have their buffers deleted after they go out of scope. This is useful if you need to return some
+	 *				 temporary data. On the other hand if the data in the block belongs to your class, and isn't temporary, keep the data unmanaged.
+	 *				 
+	 * - Reflectable - Field that is of IReflectable type. Cannot be a pointer to IReflectable and must be actual value type.   
+	 *				   Type and its fields are serialized recursively. Supports versioning so you may add/remove fields from the type
+	 *				   without breaking previously serialized data.
+	 * 
+	 * - ReflectablePtr - A pointer to IReflectable. Same as "Reflectable" except that data isn't serialized as a value type,  
+	 *					  but as a pointer, which may be referenced by multiple other instances. All references are saved upon
+	 *					  serialization and restored upon deserialization.
+	 */
+	enum SerializableFieldType
+	{
+		SerializableFT_Plain,
+		SerializableFT_DataBlock,
+		SerializableFT_Reflectable,
+		SerializableFT_ReflectablePtr
+	};
+
+	/** Various flags you can assign to RTTI fields. */
+	enum RTTIFieldFlag
+	{
+		/** This flag is only used on field types of ReflectablePtr type, and it is used
+		 * to solve circular references. Circular references cause an issue when deserializing, 
+		 * as the algorithm doesn't know which object to deserialize first. By making one of 
+		 * the references weak, you tell the algorithm that it doesn't have to guarantee 
+		 * the object will be fully deserialized before being assigned to the field.
+		 *
+		 * In short: If you make a reference weak, when "set" method of that field is called,
+		 * it is not guaranteed the value provided is fully initialized, so you should not access any of its
+		 * data until deserialization is fully complete. You only need to use this flag if the RTTI system
+		 * complains that is has found a circular reference.
+		 */
+		RTTI_Flag_WeakRef = 0x01,
+		/** This flags signals various systems that the flagged field should not be searched when looking for 
+		 * object references. This normally means the value of this field will no be retrieved during reference
+		 * searches but it will likely still be retrieved during other operations (e.g. serialization).
+		 * This is used as an optimization to avoid retrieving values of potentially very expensive fields that
+		 * would not contribute to the reference search anyway. Whether or not a field contributes to the reference
+		 * search depends on the search and should be handled on a case by case basis.
+		 */
+		RTTI_Flag_SkipInReferenceSearch = 0x02
+	};
+
+	/**
+	 * Structure that keeps meta-data concerning a single class field. You can use this data for setting and getting values 
+	 * for that field on a specific class instance.
+	 * 			
+	 * Class also contains an unique field name, and an unique field ID. Fields may contain single types or an array of types. 
+	 * See SerializableFieldType for information about specific field types.
+	 * 			
+	 * @note	
+	 * Most of the methods for retrieving and setting data accept "void *" for both the data and the owning class instance. 
+	 * It is up to the caller to ensure that pointer is of proper type.
+	 */
+	struct BS_UTILITY_EXPORT RTTIField
+	{
+		Any valueGetter;
+		Any valueSetter;
+
+		Any arraySizeGetter;
+		Any arraySizeSetter;
+
+		String mName;
+		UINT16 mUniqueId;
+		bool mIsVectorType;
+		SerializableFieldType mType;
+		UINT64 mFlags;
+
+		bool isPlainType() const { return mType == SerializableFT_Plain; }
+		bool isDataBlockType() const { return mType == SerializableFT_DataBlock; }
+		bool isReflectableType() const { return mType == SerializableFT_Reflectable; }
+		bool isReflectablePtrType() const { return mType == SerializableFT_ReflectablePtr; }
+		bool isArray() const { return mIsVectorType; }
+
+		/** Returns flags that were set in the field meta-data. */
+		UINT64 getFlags() const { return mFlags; }
+
+		/**
+		 * Gets the size of an array contained by the field, if the field represents an array. Throws exception if field 
+		 * is not an array.
+		 */
+		virtual UINT32 getArraySize(void* object) = 0;
+
+		/**
+		 * Changes the size of an array contained by the field, if the field represents an array. Throws exception if field 
+		 * is not an array.
+		 */
+		virtual void setArraySize(void* object, UINT32 size) = 0;
+
+		/** Returns the type id for the type used in this field. */
+		virtual UINT32 getTypeSize() = 0;
+
+		/**
+		 * Query if the field has dynamic size. 
+		 *
+		 * @note	
+		 * Field should have dynamic size if:
+		 *  - The field can have varying size  
+		 * 	- The field size is over 255  
+		 * @note			 
+		 * Types like integers, floats, bools, POD structs dont have dynamic size.
+		 * Types like strings, vectors, maps do.
+		 * @note		
+		 * If your type has a static size but that size exceeds 255 bytes you also need to
+		 * use dynamic field size. (You will be warned during compilation if you don't follow this rule)
+		 */
+		virtual bool hasDynamicSize() = 0;
+
+		/**
+		 * Throws an exception if this field doesn't contain a plain value.
+		 *
+		 * @param[in]	array	If true then the field must support plain array type.
+		 */
+		void checkIsPlain(bool array);
+
+		/**
+		 * Throws an exception if this field doesn't contain a complex value.
+		 *
+		 * @param[in]	array	If true then the field must support complex array type.
+		 */
+		void checkIsComplex(bool array);
+
+		/**
+		 * Throws an exception if this field doesn't contain a complex pointer value.
+		 *
+		 * @param[in]	array	If true then the field must support complex pointer array type.
+		 */
+		void checkIsComplexPtr(bool array);
+
+		/**
+		 * Throws an exception depending if the field is or isn't an array.
+		 *
+		 * @param[in]	array	If true, then exception will be thrown if field is not an array.
+		 * 						If false, then it will be thrown if field is an array.
+		 */
+		void checkIsArray(bool array);
+
+		/** Throws an exception if this field doesn't contain a data block value. */
+		void checkIsDataBlock();
+
+	protected:
+		void initAll(Any valueGetter, Any valueSetter, Any arraySizeGetter, Any arraySizeSetter,
+			String mName, UINT16 mUniqueId, bool mIsVectorType, SerializableFieldType type, UINT64 flags)
+		{
+			this->valueGetter = valueGetter;
+			this->valueSetter = valueSetter;
+			this->arraySizeGetter = arraySizeGetter;
+			this->arraySizeSetter = arraySizeSetter;
+			this->mName = mName;
+			this->mUniqueId = mUniqueId;
+			this->mIsVectorType = mIsVectorType;
+			this->mType = type;
+			this->mFlags = flags;
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 117 - 130
BansheeUtility/Include/BsRTTIManagedDataBlockField.h

@@ -1,131 +1,118 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsRTTIField.h"
-#include "BsManagedDataBlock.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Base class containing common functionality for a managed data block class field. 
-	 * 			
-	 * @note	Managed data blocks are just blocks of memory that may, or may not be released
-	 * 			automatically when they are no longer referenced. They are useful when wanting to
-	 * 			return some temporary data only for serialization purposes.
-	 */
-	struct RTTIManagedDataBlockFieldBase : public RTTIField
-	{
-		Any mCustomAllocator;
-
-		/**
-		 * @brief	Retrieves a managed data block from the specified instance.
-		 */
-		virtual ManagedDataBlock getValue(void* object) = 0;
-
-		/**
-		 * @brief	Sets a managed data block on the specified instance.
-		 */
-		virtual void setValue(void* object, ManagedDataBlock value) = 0;
-
-		/**
-		 * @brief	Allocate memory for the managed data block. Used primarily
-		 * 			to allocate memory before sending it to "setValue" method.
-		 */
-		virtual UINT8* allocate(void* object, UINT32 bytes) = 0;
-	};
-
-	/**
-	 * @brief	Class containing a managed data block field containing a specific type.
-	 */
-	template <class DataType, class ObjectType>
-	struct RTTIManagedDataBlockField : public RTTIManagedDataBlockFieldBase
-	{
-		/**
-		 * @brief	Initializes a field that returns a block of bytes. Can be used for serializing pretty much anything.
-		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: SerializableDataBlock(ObjectType*)
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, SerializableDataBlock)	
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See "RTTIFieldFlag".
-		 * @param	customAllocator (optional) Custom allocator that will be used when de-serializing DataBlock memory.
-		 */
-		void initSingle(const String& name, UINT16 uniqueId, Any getter, Any setter, UINT64 flags, Any customAllocator = Any())
-		{
-			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_DataBlock, flags);
-			mCustomAllocator = customAllocator;
-		}
-
-		/**
-		 * @copydoc RTTIField::getTypeSize
-		 */
-		virtual UINT32 getTypeSize() override
-		{
-			return 0; // Data block types don't store size the conventional way
-		}
-
-		/**
-		 * @copydoc RTTIField::hasDynamicSize
-		 */
-		virtual bool hasDynamicSize() override
-		{
-			return true;
-		}
-
-		/**
-		 * @copydoc RTTIField::getArraySize
-		 */
-		virtual UINT32 getArraySize(void* object) override
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Data block types don't support arrays.");
-		}
-
-		/**
-		 * @copydoc RTTIField::setArraySize
-		 */
-		virtual void setArraySize(void* object, UINT32 size) override
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Data block types don't support arrays.");
-		}
-
-		/**
-		 * @copydoc RTTIManagedDataBlockFieldBase::getValue
-		 */
-		virtual ManagedDataBlock getValue(void* object) override
-		{
-			ObjectType* castObj = static_cast<ObjectType*>(object);
-			std::function<ManagedDataBlock(ObjectType*)> f = any_cast<std::function<ManagedDataBlock(ObjectType*)>>(valueGetter);
-			return f(castObj);
-		}
-
-		/**
-		 * @copydoc RTTIManagedDataBlockFieldBase::setValue
-		 */
-		virtual void setValue(void* object, ManagedDataBlock value) override
-		{
-			ObjectType* castObj = static_cast<ObjectType*>(object);
-			std::function<void(ObjectType*, ManagedDataBlock)> f = any_cast<std::function<void(ObjectType*, ManagedDataBlock)>>(valueSetter);
-			f(castObj, value);
-		}
-
-		/**
-		 * @copydoc RTTIManagedDataBlockFieldBase::allocate
-		 */
-		virtual UINT8* allocate(void* object, UINT32 bytes) override
-		{
-			if(mCustomAllocator.empty())
-				return (UINT8*)bs_alloc(bytes);
-			else
-			{
-				ObjectType* castObj = static_cast<ObjectType*>(object);
-				std::function<UINT8*(ObjectType*, UINT32)> f = any_cast<std::function<UINT8*(ObjectType*, UINT32)>>(mCustomAllocator);
-				return f(castObj, bytes);
-			}
-		}
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsRTTIField.h"
+#include "BsManagedDataBlock.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup RTTI
+	 *  @{
+	 */
+
+	/**
+	 * Base class containing common functionality for a managed data block class field. 
+	 * 			
+	 * @note	
+	 * Managed data blocks are just blocks of memory that may, or may not be released automatically when they are no longer 
+	 * referenced. They are useful when wanting to return some temporary data only for serialization purposes.
+	 */
+	struct RTTIManagedDataBlockFieldBase : public RTTIField
+	{
+		Any mCustomAllocator;
+
+		/** Retrieves a managed data block from the specified instance. */
+		virtual ManagedDataBlock getValue(void* object) = 0;
+
+		/** Sets a managed data block on the specified instance. */
+		virtual void setValue(void* object, ManagedDataBlock value) = 0;
+
+		/**
+		 * Allocate memory for the managed data block. Used primarily to allocate memory before sending it to 
+		 * setValue() method.
+		 */
+		virtual UINT8* allocate(void* object, UINT32 bytes) = 0;
+	};
+
+	/** Class containing a managed data block field containing a specific type. */
+	template <class DataType, class ObjectType>
+	struct RTTIManagedDataBlockField : public RTTIManagedDataBlockFieldBase
+	{
+		/**
+		 * Initializes a field that returns a block of bytes. Can be used for serializing pretty much anything.
+		 *
+		 * @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: SerializableDataBlock(ObjectType*)
+		 * @param[in]	setter  		The setter method for the field. Must be a specific signature: void(ObjectType*, SerializableDataBlock)	
+		 * @param[in]	flags			Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @param[in]	customAllocator (optional) Custom allocator that will be used when de-serializing DataBlock memory.
+		 */
+		void initSingle(const String& name, UINT16 uniqueId, Any getter, Any setter, UINT64 flags, Any customAllocator = Any())
+		{
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_DataBlock, flags);
+			mCustomAllocator = customAllocator;
+		}
+
+		/** @copydoc RTTIField::getTypeSize */
+		virtual UINT32 getTypeSize() override
+		{
+			return 0; // Data block types don't store size the conventional way
+		}
+
+		/** @copydoc RTTIField::hasDynamicSize */
+		virtual bool hasDynamicSize() override
+		{
+			return true;
+		}
+
+		/** @copydoc RTTIField::getArraySize */
+		virtual UINT32 getArraySize(void* object) override
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Data block types don't support arrays.");
+		}
+
+		/** @copydoc RTTIField::setArraySize */
+		virtual void setArraySize(void* object, UINT32 size) override
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Data block types don't support arrays.");
+		}
+
+		/** @copydoc RTTIManagedDataBlockFieldBase::getValue */
+		virtual ManagedDataBlock getValue(void* object) override
+		{
+			ObjectType* castObj = static_cast<ObjectType*>(object);
+			std::function<ManagedDataBlock(ObjectType*)> f = any_cast<std::function<ManagedDataBlock(ObjectType*)>>(valueGetter);
+			return f(castObj);
+		}
+
+		/** @copydoc RTTIManagedDataBlockFieldBase::setValue */
+		virtual void setValue(void* object, ManagedDataBlock value) override
+		{
+			ObjectType* castObj = static_cast<ObjectType*>(object);
+			std::function<void(ObjectType*, ManagedDataBlock)> f = any_cast<std::function<void(ObjectType*, ManagedDataBlock)>>(valueSetter);
+			f(castObj, value);
+		}
+
+		/** @copydoc RTTIManagedDataBlockFieldBase::allocate */
+		virtual UINT8* allocate(void* object, UINT32 bytes) override
+		{
+			if(mCustomAllocator.empty())
+				return (UINT8*)bs_alloc(bytes);
+			else
+			{
+				ObjectType* castObj = static_cast<ObjectType*>(object);
+				std::function<UINT8*(ObjectType*, UINT32)> f = any_cast<std::function<UINT8*(ObjectType*, UINT32)>>(mCustomAllocator);
+				return f(castObj, bytes);
+			}
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 287 - 315
BansheeUtility/Include/BsRTTIPlainField.h

@@ -1,316 +1,288 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsRTTIField.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Base class containing common functionality for a plain class field. 
-	 * 			
-	 * @note	Plain fields are considered those that may be serialized directly by copying their memory.
-	 * 			(All built-in types, strings, etc.)
-	 */
-	struct RTTIPlainFieldBase : public RTTIField
-	{
-		/**
-		 * @brief	Throws an exception if the current field type and provided template types don't match.
-		 */
-		template<class DataType>
-		void checkType()
-		{
-			// TODO: Low priority. Because I wanted to get rid of SerializableType I have no way of checking the actual
-			// type of the field and the type provided to get/set methods matches
-
-			/*if(mType.id != SerializableType<DataType>().id)
-			{
-				BS_EXCEPT(InternalErrorException,
-					"Invalid field type.",
-					"SerializableSimpleTypeFieldBase::checkType()");
-			}*/
-		}
-		
-		/**
-		 * @copydoc RTTIField::getTypeId
-		 */
-		virtual UINT32 getTypeId()
-		{
-			return 0;
-		}
-
-		/**
-		 * @copydoc RTTIField::hasDynamicSize
-		 */
-		virtual bool hasDynamicSize()
-		{
-			return false;
-		}
-
-		/**
-		 * @brief	Gets the dynamic size of the object. If object has no dynamic size,
-		 * 			static size of the object is returned.
-		 */
-		virtual UINT32 getDynamicSize(void* object)
-		{
-			return 0;
-		}
-
-		/**
-		 * @brief	Gets the dynamic size of an array element. If the element has no dynamic size,
-		 * 			static size of the element is returned.
-		 */
-		virtual UINT32 getArrayElemDynamicSize(void* object, int index)
-		{
-			return 0;
-		}
-
-		/**
-		 * @brief	Retrieves the value from the provided field of the provided object, and copies
-		 * 			it into the buffer. WARNING - It does not check if buffer is large enough.
-		 */
-		virtual void toBuffer(void* object, void* buffer) = 0;
-
-		/**
-		 * @brief	Retrieves the value at the specified array index on the provided field of the
-		 * 			provided object, and copies it into the buffer. WARNING - It does not check if buffer
-		 * 			is large enough.
-		 */
-		virtual void arrayElemToBuffer(void* object, int index, void* buffer) = 0;
-
-		/**
-		 * @brief	Sets the value on the provided field of the provided object. Value is copied from the buffer. 
-		 * 			WARNING - It does not check the value in the buffer in any way. You must make sure buffer points
-		 * 			to the proper location and contains the proper type.
-		 */
-		virtual void fromBuffer(void* object, void* buffer) = 0;
-
-		/**
-		 * @brief	Sets the value at the specified array index on the provided field of the provided
-		 * 			object. Value is copied from the buffer. WARNING - It does not check the value in the
-		 * 			buffer in any way. You must make sure buffer points to the proper location and
-		 * 			contains the proper type.
-		 */
-		virtual void arrayElemFromBuffer(void* object, int index, void* buffer) = 0;
-	};
-
-	/**
-	 * @brief	Represents a plain class field containing a specific type.
-	 */
-	template <class DataType, class ObjectType>
-	struct RTTIPlainField : public RTTIPlainFieldBase
-	{
-		/**
-		 * @brief	Initializes a plain field containing a single value.
-		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: DataType(ObjectType*).
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, DataType)
-		 * @param	flags		Various flags you can use to specialize how outside systems handle this field. See "RTTIFieldFlag".
-		 */
-		void initSingle(const String& name, UINT16 uniqueId, Any getter, Any setter, UINT64 flags)
-		{
-			int typeId = RTTIPlainType<DataType>::id; // Just making sure provided type has a type ID
-
-			static_assert((RTTIPlainType<DataType>::hasDynamicSize != 0 || (sizeof(DataType) <= 255)), 
-				"Trying to create a plain RTTI field with size larger than 255. In order to use larger sizes for plain types please specialize " \
-				" RTTIPlainType, set hasDynamicSize to true.");
-
-			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_Plain, flags);
-		}
-
-		/**
-		 * @brief	Initializes a plain field containing multiple values in an array. 
-		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: DataType(ObjectType*, UINT32)
-		 * @param	getSize 	Getter method that returns the size of an array. Must be a specific signature: UINT32(ObjectType*)
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, UINT32, DataType)
-		 * @param	setSize 	Setter method that allows you to resize an array. Can be null. Must be a specific signature: void(ObjectType*, UINT32)
-		 * @param	flags		Various flags you can use to specialize how outside systems handle this field. See "RTTIFieldFlag".
-		 */
-		void initArray(const String& name, UINT16 uniqueId, Any getter,
-			Any getSize, Any setter, Any setSize, UINT64 flags)
-		{
-			int typeId = RTTIPlainType<DataType>::id; // Just making sure provided type has a type ID
-
-			static_assert((RTTIPlainType<DataType>::hasDynamicSize != 0 || (sizeof(DataType) <= 255)), 
-				"Trying to create a plain RTTI field with size larger than 255. In order to use larger sizes for plain types please specialize " \
-				" RTTIPlainType, set hasDynamicSize to true.");
-
-			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_Plain, flags);
-		}
-
-		/**
-		 * @copydoc RTTIField::getTypeSize
-		 */
-		virtual UINT32 getTypeSize()
-		{
-			return sizeof(DataType);
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::getTypeId
-		 */
-		virtual UINT32 getTypeId()
-		{
-			return RTTIPlainType<DataType>::id;
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::hasDynamicSize
-		 */
-		virtual bool hasDynamicSize()
-		{
-			return RTTIPlainType<DataType>::hasDynamicSize != 0;
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::getDynamicSize
-		 */
-		virtual UINT32 getDynamicSize(void* object)
-		{
-			checkIsArray(false);
-			checkType<DataType>();
-
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-
-			std::function<DataType&(ObjectType*)> f = any_cast<std::function<DataType&(ObjectType*)>>(valueGetter);
-			DataType value = f(castObject);
-
-			return RTTIPlainType<DataType>::getDynamicSize(value);
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::getArrayElemDynamicSize
-		 */
-		virtual UINT32 getArrayElemDynamicSize(void* object, int index)
-		{
-			checkIsArray(true);
-			checkType<DataType>();
-
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-
-			std::function<DataType&(ObjectType*, UINT32)> f = any_cast<std::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
-			DataType value = f(castObject, index);
-
-			return RTTIPlainType<DataType>::getDynamicSize(value);
-		}
-
-		/**
-		 * @copydoc RTTIPlainField::getArraySize
-		 */
-		virtual UINT32 getArraySize(void* object)
-		{
-			checkIsArray(true);
-
-			std::function<UINT32(ObjectType*)> f = any_cast<std::function<UINT32(ObjectType*)>>(arraySizeGetter);
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-			return f(castObject);
-		}
-
-		/**
-		 * @copydoc RTTIPlainField::setArraySize
-		 */
-		virtual void setArraySize(void* object, UINT32 size)
-		{
-			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 RTTIPlainFieldBase::toBuffer
-		 */
-		virtual void toBuffer(void* object, void* buffer)
-		{
-			checkIsArray(false);
-			checkType<DataType>();
-
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-
-			std::function<DataType&(ObjectType*)> f = any_cast<std::function<DataType&(ObjectType*)>>(valueGetter);
-			DataType value = f(castObject);
-
-			RTTIPlainType<DataType>::toMemory(value, (char*)buffer);
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::arrayElemToBuffer
-		 */
-		virtual void arrayElemToBuffer(void* object, int index, void* buffer)
-		{
-			checkIsArray(true);
-			checkType<DataType>();
-
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-
-			std::function<DataType&(ObjectType*, UINT32)> f = any_cast<std::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
-			DataType value = f(castObject, index);
-
-			RTTIPlainType<DataType>::toMemory(value, (char*)buffer);
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::fromBuffer
-		 */
-		virtual void fromBuffer(void* object, void* buffer)
-		{
-			checkIsArray(false);
-			checkType<DataType>();
-
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-
-			DataType value;
-			RTTIPlainType<DataType>::fromMemory(value, (char*)buffer);
-
-			if(valueSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException,
-					"Specified field (" + mName + ") has no setter.");
-			}
-
-			std::function<void(ObjectType*, DataType&)> f = any_cast<std::function<void(ObjectType*, DataType&)>>(valueSetter);
-			f(castObject, value);
-		}
-
-		/**
-		 * @copydoc RTTIPlainFieldBase::arrayElemFromBuffer
-		 */
-		virtual void arrayElemFromBuffer(void* object, int index, void* buffer)
-		{
-			checkIsArray(true);
-			checkType<DataType>();
-
-			ObjectType* castObject = static_cast<ObjectType*>(object);
-
-			DataType value;
-			RTTIPlainType<DataType>::fromMemory(value, (char*)buffer);
-
-			if(valueSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Specified field (" + mName + ") has no setter.");
-			}
-
-			std::function<void(ObjectType*, UINT32, DataType&)> f = any_cast<std::function<void(ObjectType*, UINT32, DataType&)>>(valueSetter);
-			f(castObject, index, value);
-		}
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsRTTIField.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup RTTI
+	 *  @{
+	 */
+
+	/**
+	 * Base class containing common functionality for a plain class field. 
+	 * 			
+	 * @note	
+	 * Plain fields are considered those that may be serialized directly by copying their memory. (All built-in types, 
+	 * strings, etc.)
+	 */
+	struct RTTIPlainFieldBase : public RTTIField
+	{
+		/** Throws an exception if the current field type and provided template types don't match. */
+		template<class DataType>
+		void checkType()
+		{
+			// TODO: Low priority. Because I wanted to get rid of SerializableType I have no way of checking the actual
+			// type of the field and the type provided to get/set methods matches
+
+			/*if(mType.id != SerializableType<DataType>().id)
+			{
+				BS_EXCEPT(InternalErrorException,
+					"Invalid field type.",
+					"SerializableSimpleTypeFieldBase::checkType()");
+			}*/
+		}
+		
+		/** @copydoc RTTIField::getTypeId */
+		virtual UINT32 getTypeId()
+		{
+			return 0;
+		}
+
+		/** @copydoc RTTIField::hasDynamicSize */
+		bool hasDynamicSize() override
+		{
+			return false;
+		}
+
+		/** Gets the dynamic size of the object. If object has no dynamic size, static size of the object is returned. */
+		virtual UINT32 getDynamicSize(void* object)
+		{
+			return 0;
+		}
+
+		/**
+		 * Gets the dynamic size of an array element. If the element has no dynamic size, static size of the element 
+		 * is returned.
+		 */
+		virtual UINT32 getArrayElemDynamicSize(void* object, int index)
+		{
+			return 0;
+		}
+
+		/**
+		 * Retrieves the value from the provided field of the provided object, and copies it into the buffer. It does not 
+		 * check if buffer is large enough.
+		 */
+		virtual void toBuffer(void* object, void* buffer) = 0;
+
+		/**
+		 * Retrieves the value at the specified array index on the provided field of the provided object, and copies it into
+		 * the buffer. It does not check if buffer is large enough.
+		 */
+		virtual void arrayElemToBuffer(void* object, int index, void* buffer) = 0;
+
+		/**
+		 * Sets the value on the provided field of the provided object. Value is copied from the buffer. It does not check 
+		 * the value in the buffer in any way. You must make sure buffer points to the proper location and contains the 
+		 * proper type.
+		 */
+		virtual void fromBuffer(void* object, void* buffer) = 0;
+
+		/**
+		 * Sets the value at the specified array index on the provided field of the provided object. Value is copied from 
+		 * the buffer. It does not check the value in the buffer in any way. You must make sure buffer points to the proper 
+		 * location and contains the proper type.
+		 */
+		virtual void arrayElemFromBuffer(void* object, int index, void* buffer) = 0;
+	};
+
+	/** Represents a plain class field containing a specific type. */
+	template <class DataType, class ObjectType>
+	struct RTTIPlainField : public RTTIPlainFieldBase
+	{
+		/**
+		 * Initializes a plain field containing a single value.
+		 *
+		 * @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 outside systems handle this field. See "RTTIFieldFlag".
+		 */
+		void initSingle(const String& name, UINT16 uniqueId, Any getter, Any setter, UINT64 flags)
+		{
+			int typeId = RTTIPlainType<DataType>::id; // Just making sure provided type has a type ID
+
+			static_assert((RTTIPlainType<DataType>::hasDynamicSize != 0 || (sizeof(DataType) <= 255)), 
+				"Trying to create a plain RTTI field with size larger than 255. In order to use larger sizes for plain types please specialize " \
+				" RTTIPlainType, set hasDynamicSize to true.");
+
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_Plain, flags);
+		}
+
+		/**
+		 * Initializes a plain field containing multiple values in an array. 
+		 *
+		 * @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. Can be null. Must be a specific signature: void(ObjectType*, UINT32)
+		 * @param[in]	flags		Various flags you can use to specialize how outside systems handle this field. See "RTTIFieldFlag".
+		 */
+		void initArray(const String& name, UINT16 uniqueId, Any getter,
+			Any getSize, Any setter, Any setSize, UINT64 flags)
+		{
+			int typeId = RTTIPlainType<DataType>::id; // Just making sure provided type has a type ID
+
+			static_assert((RTTIPlainType<DataType>::hasDynamicSize != 0 || (sizeof(DataType) <= 255)), 
+				"Trying to create a plain RTTI field with size larger than 255. In order to use larger sizes for plain types please specialize " \
+				" RTTIPlainType, set hasDynamicSize to true.");
+
+			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_Plain, flags);
+		}
+
+		/** @copydoc RTTIField::getTypeSize */
+		UINT32 getTypeSize() override
+		{
+			return sizeof(DataType);
+		}
+
+		/** @copydoc RTTIPlainFieldBase::getTypeId */
+		UINT32 getTypeId() override
+		{
+			return RTTIPlainType<DataType>::id;
+		}
+
+		/** @copydoc RTTIPlainFieldBase::hasDynamicSize */
+		bool hasDynamicSize() override
+		{
+			return RTTIPlainType<DataType>::hasDynamicSize != 0;
+		}
+
+		/** @copydoc RTTIPlainFieldBase::getDynamicSize */
+		UINT32 getDynamicSize(void* object) override
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			std::function<DataType&(ObjectType*)> f = any_cast<std::function<DataType&(ObjectType*)>>(valueGetter);
+			DataType value = f(castObject);
+
+			return RTTIPlainType<DataType>::getDynamicSize(value);
+		}
+
+		/** @copydoc RTTIPlainFieldBase::getArrayElemDynamicSize */
+		UINT32 getArrayElemDynamicSize(void* object, int index) override
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			std::function<DataType&(ObjectType*, UINT32)> f = any_cast<std::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
+			DataType value = f(castObject, index);
+
+			return RTTIPlainType<DataType>::getDynamicSize(value);
+		}
+
+		/*** @copydoc RTTIPlainField::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 RTTIPlainField::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 RTTIPlainFieldBase::toBuffer */
+		void toBuffer(void* object, void* buffer) override
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			std::function<DataType&(ObjectType*)> f = any_cast<std::function<DataType&(ObjectType*)>>(valueGetter);
+			DataType value = f(castObject);
+
+			RTTIPlainType<DataType>::toMemory(value, (char*)buffer);
+		}
+
+		/** @copydoc RTTIPlainFieldBase::arrayElemToBuffer */
+		void arrayElemToBuffer(void* object, int index, void* buffer) override
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			std::function<DataType&(ObjectType*, UINT32)> f = any_cast<std::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
+			DataType value = f(castObject, index);
+
+			RTTIPlainType<DataType>::toMemory(value, (char*)buffer);
+		}
+
+		/** @copydoc RTTIPlainFieldBase::fromBuffer */
+		void fromBuffer(void* object, void* buffer) override
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			DataType value;
+			RTTIPlainType<DataType>::fromMemory(value, (char*)buffer);
+
+			if(valueSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException,
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			std::function<void(ObjectType*, DataType&)> f = any_cast<std::function<void(ObjectType*, DataType&)>>(valueSetter);
+			f(castObject, value);
+		}
+
+		/** @copydoc RTTIPlainFieldBase::arrayElemFromBuffer */
+		void arrayElemFromBuffer(void* object, int index, void* buffer) override
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			DataType value;
+			RTTIPlainType<DataType>::fromMemory(value, (char*)buffer);
+
+			if(valueSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			std::function<void(ObjectType*, UINT32, DataType&)> f = any_cast<std::function<void(ObjectType*, UINT32, DataType&)>>(valueSetter);
+			f(castObject, index, value);
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 204 - 226
BansheeUtility/Include/BsRTTIReflectableField.h

@@ -1,227 +1,205 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsRTTIField.h"
-#include "BsIReflectable.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	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
-	{
-		/**
-		 * @brief	Retrieves the IReflectable value from the provided instance.
-		 * 			
-		 * @note	Field type must not be an array.
-		 */
-		virtual IReflectable& getValue(void* object) = 0;
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	Sets the IReflectable value in the provided instance.
-		 * 			
-		 * @note	Field type must not be an array.
-		 */
-		virtual void setValue(void* object, IReflectable& value) = 0;
-
-		/**
-		 * @brief	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;
-
-		/**
-		 * @brief	Creates a new object of the field type.
-		 */
-		virtual std::shared_ptr<IReflectable> newObject() = 0;
-
-		/**
-		 * @copydoc RTTIField::hasDynamicSize
-		 */
-		virtual bool hasDynamicSize() { return true; }
-
-		/**
-		 * @brief	Retrieves the RTTI object for the type the field contains.
-		 */
-		virtual RTTITypeBase* getType() = 0;
-	};
-
-	/**
-	 * @brief	Class containing a reflectable field containing a specific type.
-	 */
-	template <class DataType, class ObjectType>
-	struct RTTIReflectableField : public RTTIReflectableFieldBase
-	{
-		/**
-		 * @brief	Initializes a field containing a single data type implementing IReflectable interface. 
-		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: DataType&(ObjectType*)
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, DataType)
-		 * @param	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	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: DataType&(ObjectType*, UINT32)
-		 * @param	getSize 	Getter method that returns the size of an array. Must be a specific signature: UINT32(ObjectType*)
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, UINT32, DataType)
-		 * @param	setSize 	Setter method that allows you to resize an array. Must be a specific signature: void(ObjectType*, UINT32)
-		 * @param	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
-		 */
-		virtual UINT32 getTypeSize()
-		{
-			return 0; // Complex types don't store size the conventional way
-		}
-
-		/**
-		 * @copydoc RTTIReflectableFieldBase::getValue
-		 */
-		virtual IReflectable& getValue(void* object)
-		{
-			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
-		 */
-		virtual IReflectable& getArrayValue(void* object, UINT32 index)
-		{
-			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
-		 */
-		virtual void setValue(void* object, IReflectable& value)
-		{
-			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
-		 */
-		virtual void setArrayValue(void* object, UINT32 index, IReflectable& value)
-		{
-			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
-		 */
-		virtual UINT32 getArraySize(void* object)
-		{
-			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
-		 */
-		virtual void setArraySize(void* object, UINT32 size)
-		{
-			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
-		 */
-		virtual std::shared_ptr<IReflectable> newObject()
-		{
-			return DataType::getRTTIStatic()->newRTTIObject();
-		}
-
-		/**
-		 * @copydoc RTTIReflectableFieldBase::getType
-		 */
-		virtual RTTITypeBase* getType()
-		{
-			return DataType::getRTTIStatic();
-		}
-	};
+#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 */
 }

+ 226 - 257
BansheeUtility/Include/BsRTTIReflectablePtrField.h

@@ -1,258 +1,227 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsRTTIField.h"
-#include "BsIReflectable.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Base class containing common functionality for a reflectable pointer 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.
-	 * 			
-	 *			ReflectablePtr field are different from Reflectable fields because other types may reference
-	 *			the same Reflectable object using a ReflectablePtr, while normal Reflectable fields are only
-	 *			referenced by a single field they're declared on.
-	 */
-	struct RTTIReflectablePtrFieldBase : public RTTIField
-	{
-		/**
-		 * @brief	Retrieves the IReflectable value from the provided instance.
-		 * 			
-		 * @note	Field type must not be an array.
-		 */
-		virtual std::shared_ptr<IReflectable> getValue(void* object) = 0;
-
-		/**
-		 * @brief	Retrieves the IReflectable value from an array on the provided instance
-		 * 			and index.
-		 * 			
-		 * @note	Field type must be an array.
-		 */
-		virtual std::shared_ptr<IReflectable> getArrayValue(void* object, UINT32 index) = 0;
-
-		/**
-		 * @brief	Sets the IReflectable value in the provided instance.
-		 * 			
-		 * @note	Field type must not be an array.
-		 */
-		virtual void setValue(void* object, std::shared_ptr<IReflectable> value) = 0;
-
-		/**
-		 * @brief	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, std::shared_ptr<IReflectable> value) = 0;
-
-		/**
-		 * @brief	Creates a new object of the field type.
-		 */
-		virtual std::shared_ptr<IReflectable> newObject() = 0;
-
-		/**
-		 * @brief	Returns the RTTI identifier of the class owning the field.
-		 */
-		virtual UINT32 getRTTIId() = 0;
-
-		/**
-		 * @brief	Returns the name of the class owning the field.
-		 */
-		virtual const String& getRTTIName() = 0;
-
-		/**
-		 * @copydoc RTTIField::hasDynamicSize
-		 */
-		virtual bool hasDynamicSize() { return true; }
-
-		/**
-		 * @brief	Retrieves the RTTI object for the type the field contains.
-		 */
-		virtual RTTITypeBase* getType() = 0;
-	};
-
-	/**
-	 * @brief	Class containing a reflectable pointer field containing a specific type.
-	 */
-	template <class DataType, class ObjectType>
-	struct RTTIReflectablePtrField : public RTTIReflectablePtrFieldBase
-	{
-		/**
-		 * @brief	Initializes a field pointing to a single data type implementing IReflectable interface.
-		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: DataType*(ObjectType*)
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, DataType*)
-		 * @param	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_ReflectablePtr, flags);
-		}
-
-		/**
-		 * @brief	Initializes a field containing an array of pointers to data types implementing IReflectable interface.
-		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	The getter method for the field. Must be a specific signature: DataType*(ObjectType*, UINT32)
-		 * @param	getSize 	Getter method that returns the size of an array. Must be a specific signature: UINT32(ObjectType*)
-		 * @param	setter  	The setter method for the field. Must be a specific signature: void(ObjectType*, UINT32, DataType*)
-		 * @param	setSize 	Setter method that allows you to resize an array. Can be null. Must be a specific signature: void(ObjectType*, UINT32)
-		 * @param	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_ReflectablePtr, flags);
-		}
-
-		/**
-		 * @copydoc RTTIField::getTypeSize
-		 */
-		virtual UINT32 getTypeSize()
-		{
-			return 0; // Complex types don't store size the conventional way
-		}
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::getValue
-		 */
-		virtual std::shared_ptr<IReflectable> getValue(void* object)
-		{
-			checkIsArray(false);
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			std::function<std::shared_ptr<DataType>(ObjectType*)> f = any_cast<std::function<std::shared_ptr<DataType>(ObjectType*)>>(valueGetter);
-			std::shared_ptr<IReflectable> castDataType = f(castObjType);
-
-			return castDataType;
-		}
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::getArrayValue
-		 */
-		virtual std::shared_ptr<IReflectable> getArrayValue(void* object, UINT32 index)
-		{
-			checkIsArray(true);
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			std::function<std::shared_ptr<DataType>(ObjectType*, UINT32)> f = any_cast<std::function<std::shared_ptr<DataType>(ObjectType*, UINT32)>>(valueGetter);
-
-			std::shared_ptr<IReflectable> castDataType = f(castObjType, index);
-			return castDataType;
-		}
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::setValue
-		 */
-		virtual void setValue(void* object, std::shared_ptr<IReflectable> value)
-		{
-			checkIsArray(false);
-
-			if(valueSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException,
-					"Specified field (" + mName + ") has no setter.");
-			}
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			std::shared_ptr<DataType> castDataObj = std::static_pointer_cast<DataType>(value);
-			std::function<void(ObjectType*, std::shared_ptr<DataType>)> f = any_cast<std::function<void(ObjectType*, std::shared_ptr<DataType>)>>(valueSetter);
-			f(castObjType, castDataObj);
-		}
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::setArrayValue
-		 */
-		virtual void setArrayValue(void* object, UINT32 index, std::shared_ptr<IReflectable> value)
-		{
-			checkIsArray(true);
-
-			if(valueSetter.empty())
-			{
-				BS_EXCEPT(InternalErrorException, 
-					"Specified field (" + mName + ") has no setter.");
-			}
-
-			ObjectType* castObjType = static_cast<ObjectType*>(object);
-			std::shared_ptr<DataType> castDataObj = std::static_pointer_cast<DataType>(value);
-			std::function<void(ObjectType*, UINT32, std::shared_ptr<DataType>)> f = any_cast<std::function<void(ObjectType*, UINT32, std::shared_ptr<DataType>)>>(valueSetter);
-			f(castObjType, index, castDataObj);
-		}
-
-		/**
-		 * @copydoc RTTIField::setArraySize
-		 */
-		virtual UINT32 getArraySize(void* object)
-		{
-			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
-		 */
-		virtual void setArraySize(void* object, UINT32 size)
-		{
-			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 RTTIReflectablePtrFieldBase::newObject
-		 */
-		virtual std::shared_ptr<IReflectable> newObject()
-		{
-			return std::shared_ptr<IReflectable>(DataType::getRTTIStatic()->newRTTIObject());
-		}
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::getRTTIId
-		 */
-		virtual UINT32 getRTTIId()
-		{
-			return DataType::getRTTIStatic()->getRTTIId();
-		}
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::getRTTIName
-		 */
-		virtual const String& getRTTIName()
-		{
-			return DataType::getRTTIStatic()->getRTTIName();
-		}
-
-
-		/**
-		 * @copydoc RTTIReflectablePtrFieldBase::getType
-		 */
-		virtual RTTITypeBase* getType()
-		{
-			return DataType::getRTTIStatic();
-		}
-	};
+#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 pointer 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.
+	 * @note
+	 * ReflectablePtr fields are different from Reflectable fields because other types may reference the same Reflectable 
+	 * object using a ReflectablePtr, while normal Reflectable fields are only referenced by a single field they're declared on.
+	 */
+	struct RTTIReflectablePtrFieldBase : public RTTIField
+	{
+		/**
+		 * Retrieves the IReflectable value from the provided instance.
+		 * 			
+		 * @note	Field type must not be an array.
+		 */
+		virtual std::shared_ptr<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 std::shared_ptr<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, std::shared_ptr<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, std::shared_ptr<IReflectable> value) = 0;
+
+		/** Creates a new object of the field type. */
+		virtual std::shared_ptr<IReflectable> newObject() = 0;
+
+		/** Returns the RTTI identifier of the class owning the field. */
+		virtual UINT32 getRTTIId() = 0;
+
+		/** Returns the name of the class owning the field. */
+		virtual const String& getRTTIName() = 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 pointer to a specific type with RTTI implemented.  */
+	template <class DataType, class ObjectType>
+	struct RTTIReflectablePtrField : public RTTIReflectablePtrFieldBase
+	{
+		/**
+		 * Initializes a field pointing to 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_ReflectablePtr, flags);
+		}
+
+		/**
+		 * Initializes a field containing an array of pointers to 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. Can be null. 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_ReflectablePtr, flags);
+		}
+
+		/** @copydoc RTTIField::getTypeSize */
+		UINT32 getTypeSize() override
+		{
+			return 0; // Complex types don't store size the conventional way
+		}
+
+		/** @copydoc RTTIReflectablePtrFieldBase::getValue */
+		std::shared_ptr<IReflectable> getValue(void* object) override
+		{
+			checkIsArray(false);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			std::function<std::shared_ptr<DataType>(ObjectType*)> f = any_cast<std::function<std::shared_ptr<DataType>(ObjectType*)>>(valueGetter);
+			std::shared_ptr<IReflectable> castDataType = f(castObjType);
+
+			return castDataType;
+		}
+
+		/** @copydoc RTTIReflectablePtrFieldBase::getArrayValue */
+		std::shared_ptr<IReflectable> getArrayValue(void* object, UINT32 index) override
+		{
+			checkIsArray(true);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			std::function<std::shared_ptr<DataType>(ObjectType*, UINT32)> f = any_cast<std::function<std::shared_ptr<DataType>(ObjectType*, UINT32)>>(valueGetter);
+
+			std::shared_ptr<IReflectable> castDataType = f(castObjType, index);
+			return castDataType;
+		}
+
+		/** @copydoc RTTIReflectablePtrFieldBase::setValue */
+		void setValue(void* object, std::shared_ptr<IReflectable> value) override
+		{
+			checkIsArray(false);
+
+			if(valueSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException,
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			std::shared_ptr<DataType> castDataObj = std::static_pointer_cast<DataType>(value);
+			std::function<void(ObjectType*, std::shared_ptr<DataType>)> f = any_cast<std::function<void(ObjectType*, std::shared_ptr<DataType>)>>(valueSetter);
+			f(castObjType, castDataObj);
+		}
+
+		/** @copydoc RTTIReflectablePtrFieldBase::setArrayValue */
+		void setArrayValue(void* object, UINT32 index, std::shared_ptr<IReflectable> value) override
+		{
+			checkIsArray(true);
+
+			if(valueSetter.empty())
+			{
+				BS_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			std::shared_ptr<DataType> castDataObj = std::static_pointer_cast<DataType>(value);
+			std::function<void(ObjectType*, UINT32, std::shared_ptr<DataType>)> f = any_cast<std::function<void(ObjectType*, UINT32, std::shared_ptr<DataType>)>>(valueSetter);
+			f(castObjType, index, castDataObj);
+		}
+
+		/** @copydoc RTTIField::setArraySize */
+		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 RTTIReflectablePtrFieldBase::newObject */
+		std::shared_ptr<IReflectable> newObject() override
+		{
+			return std::shared_ptr<IReflectable>(DataType::getRTTIStatic()->newRTTIObject());
+		}
+
+		/** @copydoc RTTIReflectablePtrFieldBase::getRTTIId */
+		UINT32 getRTTIId() override
+		{
+			return DataType::getRTTIStatic()->getRTTIId();
+		}
+
+		/** @copydoc RTTIReflectablePtrFieldBase::getRTTIName */
+		const String& getRTTIName() override
+		{
+			return DataType::getRTTIStatic()->getRTTIName();
+		}
+
+
+		/** @copydoc RTTIReflectablePtrFieldBase::getType */
+		RTTITypeBase* getType() override
+		{
+			return DataType::getRTTIStatic();
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 170 - 214
BansheeUtility/Include/BsRTTIType.h

@@ -14,6 +14,10 @@
 #include "BsIReflectable.h"
 #include "BsBinaryDiff.h"
 
+/** @addtogroup RTTI
+ *  @{
+ */
+
 namespace BansheeEngine
 {
 #define BS_PLAIN_MEMBER(name)								\
@@ -67,16 +71,18 @@ namespace BansheeEngine
 	addReflectablePtrArrayField(#name, id##, &MyType::get##name, &MyType::getSize##name, \
 	&MyType::set##name, &MyType::setSize##name);
 
+	/** @cond INTERNAL */
+
 	/**
-	 * @brief	Provides an interface for accessing fields of a certain class.
-	 * 			Data can be easily accessed by getter and setter methods.
+	 * Provides an interface for accessing fields of a certain class.
+	 * Data can be easily accessed by getter and setter methods.
 	 * 			
-	 *			Supported data types:
-	 *			 - Plain types - All types defined in BsRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte.  
-	 *			                 No pointers to plain types are supported. Data is passed around by value.
-	 *			 - Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its RTTI class. Can be pointer or value type.
-	 *			 - Arrays of both plain and reflectable types are supported
-	 *			 - Data blocks - A managed or unmanaged block of data. See BsManagedDataBlock.h
+	 * Supported data types:
+	 *	- Plain types - All types defined in BsRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte.  
+	 *	                No pointers to plain types are supported. Data is passed around by value.
+	 *	- Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its RTTI class. Can be pointer or value type.
+	 *	- Arrays of both plain and reflectable types are supported
+	 *	- Data blocks - A managed or unmanaged block of data. See ManagedDataBlock.
 	 */
 	class BS_UTILITY_EXPORT RTTITypeBase
 	{
@@ -84,79 +90,65 @@ namespace BansheeEngine
 		RTTITypeBase();
 		virtual ~RTTITypeBase();
 
-		/**
-		 * @brief	Returns RTTI type information for all classes that derive from the class
-		 *			that owns this RTTI type.
-		 */
+		/** Returns RTTI type information for all classes that derive from the class that owns this RTTI type. */
 		virtual Vector<RTTITypeBase*>& getDerivedClasses() = 0;
 
 		/**
-		 * @brief	Returns RTTI type information for the class that owns this RTTI type. 
-		 *			If the class has not base type, null is returned instead.
+		 * Returns RTTI type information for the class that owns this RTTI type. If the class has not base type, null is 
+		 * returned instead.
 		 */
 		virtual RTTITypeBase* getBaseClass() = 0;
 
-		/**
-		 * @brief	Returns true if current RTTI class is derived from "base".
-		 * 			(Or if it is the same type as base)
-		 */
+		/** Returns true if current RTTI class is derived from @p base. (Or if it is the same type as base) */
 		virtual bool isDerivedFrom(RTTITypeBase* base) = 0;
 
 		/**
-		 * @brief	Internal method. Called by the RTTI system when a class is first found in
-		 *			order to form child/parent class hierarchy.
+		 *  Called by the RTTI system when a class is first found in order to form child/parent class hierarchy.
+		 *
+		 * @note	Internal method.
 		 */
 		virtual void _registerDerivedClass(RTTITypeBase* derivedClass) = 0;
 
-		/**
-		 * @brief	Creates a new instance of the class owning this RTTI type.
-		 */
+		/** Creates a new instance of the class owning this RTTI type. */
 		virtual std::shared_ptr<IReflectable> newRTTIObject() = 0;
 
-		/**
-		 * @brief	Returns the name of the class owning this RTTI type.
-		 */
+		/** Returns the name of the class owning this RTTI type. */
 		virtual const String& getRTTIName() = 0;
 
-		/**
-		 * @brief	Returns an RTTI id that uniquely represents each class in the RTTI
-		 *			system.
-		 */
+		/** Returns an RTTI id that uniquely represents each class in the RTTI system. */
 		virtual UINT32 getRTTIId() = 0;
 
 		/**
-		 * @brief	Called by the serializers when serialization for this object has started.
-		 *			Use this to do any preprocessing on data you might need during serialization itself.
+		 * Called by the serializers when serialization for this object has started. Use this to do any preprocessing on 
+		 * data you might need during serialization itself.
 		 */
 		virtual void onSerializationStarted(IReflectable* obj) {}
 
 		/**
-		 * @brief	Called by the serializers when serialization for this object has ended.
-		 *			After serialization has ended you can be sure that the type has been fully serialized,
-		 *			and you may clean up any temporary data.
+		 * Called by the serializers when serialization for this object has ended. After serialization has ended you can 
+		 * be sure that the type has been fully serialized, and you may clean up any temporary data.
 		 */
 		virtual void onSerializationEnded(IReflectable* obj) {}
 
 		/**
-		 * @brief	Called by the serializers when deserialization for this object has started.
-		 *			Use this to do any preprocessing on data you might need during deserialization itself.
+		 * Called by the serializers when deserialization for this object has started. Use this to do any preprocessing 
+		 * on data you might need during deserialization itself.
 		 */
 		virtual void onDeserializationStarted(IReflectable* obj) {}
 
 		/**
-		 * @brief	Called by the serializers when deserialization for this object has ended.
-		 *			At this point you can be sure the instance has been fully deserialized and you
-		 *			may safely use it.
+		 * Called by the serializers when deserialization for this object has ended. At this point you can be sure the 
+		 * instance has been fully deserialized and you may safely use it.
 		 *
-		 *			One exception being are fields you marked with "WeakRef" flag, as they might be resolved
-		 *			only after deserialization has fully completed for all objects.
+		 * One exception being are fields you marked with "WeakRef" flag, as they might be resolved only after 
+		 * deserialization has fully completed for all objects.
 		 */
 		virtual void onDeserializationEnded(IReflectable* obj) {}
 
 		/**
-		 * @brief	Returns a handler that determines how are "diffs" generated and applied when it
-		 *			comes to objects of this RTTI type. A "diff" is a list of differences between two
-		 *			objects that may be saved, viewed or applied to another object to transform it.
+		 * Returns a handler that determines how are "diffs" generated and applied when it comes to objects of this RTTI 
+		 * type. A "diff" is a list of differences between two objects that may be saved, viewed or applied to another 
+		 * object to transform it.
 		 */
 		virtual IDiff& getDiffHandler() const
 		{
@@ -165,8 +157,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a plain field with the specified name on 
-		 *			the provided instance.
+		 * Allows you to assign a value to a plain field with the specified name on the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -193,8 +184,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a plain field array element with the 
-		 *			specified name and index on the provided instance.
+		 * Allows you to assign a value to a plain field array element with the specified name and index on the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -221,8 +211,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a reflectable field with the specified name on 
-		 *			the provided instance.
+		 * Allows you to assign a value to a reflectable field with the specified name on the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -240,8 +229,8 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a reflectable field array element with the 
-		 *			specified name and index on the provided instance.
+		 * Allows you to assign a value to a reflectable field array element with the specified name and index on the 
+		 * provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -259,8 +248,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a managed data block field with the specified name on 
-		 *			the provided instance.
+		 * Allows you to assign a value to a managed data block field with the specified name on the provided instance.
 		 *
 		 * @note	Caller must ensure instance type is valid for this field.
 		 */
@@ -275,8 +263,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a reflectable pointer field with the specified name on 
-		 *			the provided instance.
+		 * Allows you to assign a value to a reflectable pointer field with the specified name on the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -294,8 +281,8 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Allows you to assign a value to a reflectable pointer field array element with the 
-		 *			specified name and index on the provided instance.
+		 * Allows you to assign a value to a reflectable pointer field array element with the specified name and index on 
+		 * the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -313,7 +300,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Reads a value from a plain field with the specified name from the provided instance.
+		 * Reads a value from a plain field with the specified name from the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -340,7 +327,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Reads a value from a plain array field with the specified name and index from the provided instance.
+		 * Reads a value from a plain array field with the specified name and index from the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -367,7 +354,7 @@ namespace BansheeEngine
 		}	
 
 		/**
-		 * @brief	Reads a value from a reflectable object field with the specified name from the provided instance.
+		 * Reads a value from a reflectable object field with the specified name from the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -382,7 +369,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Reads a value from a reflectable object array field with the specified name and index from the provided instance.
+		 * Reads a value from a reflectable object array field with the specified name and index from the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -397,7 +384,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Reads a managed data block field with the specified name from the provided instance.
+		 * Reads a managed data block field with the specified name from the provided instance.
 		 *
 		 * @note	Caller must ensure instance type is valid for this field.
 		 */
@@ -412,7 +399,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Reads a value from a reflectable object pointer field with the specified name from the provided instance.
+		 * Reads a value from a reflectable object pointer field with the specified name from the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -427,7 +414,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Reads a value from a reflectable pointer array field with the specified name and index from the provided instance.
+		 * Reads a value from a reflectable pointer array field with the specified name and index from the provided instance.
 		 *
 		 * @note	Caller must ensure instance and value types are valid for this field.
 		 */
@@ -442,7 +429,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Returns the size of the array of the field with the specified name on the provided instance.
+		 * Returns the size of the array of the field with the specified name on the provided instance.
 		 *
 		 * @note	Caller must ensure instance type is valid and that the field as an array.
 		 */
@@ -454,10 +441,11 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Sets the size of the array of the field with the specified name on the provided instance.
+		 * Sets the size of the array of the field with the specified name on the provided instance.
 		 *
-		 * @note	Caller must ensure instance type is valid and that the field as an array. 
-		 *			This might clear any existing data from the array.
+		 * @note	
+		 * Caller must ensure instance type is valid and that the field as an array. This might clear any existing data 
+		 * from the array.
 		 */
 		template <class ObjectType>
 		void setArraySize(ObjectType* object, const String& name, UINT32 size)
@@ -466,27 +454,22 @@ namespace BansheeEngine
 			field->setArraySize(object, size);
 		}	
 
-		/**
-		 * @brief	Returns the total number of fields in this RTTI type.
-		 */
-		UINT32 getNumFields() { return (UINT32)mFields.size(); }
+		/** Returns the total number of fields in this RTTI type. */
+		UINT32 getNumFields() const { return (UINT32)mFields.size(); }
 
-		/**
-		 * @brief	Returns a field based on the field index. Use "getNumFields" to
-		 *			get total number of fields available.
-		 */
+		/** Returns a field based on the field index. Use getNumFields() to get total number of fields available. */
 		RTTIField* getField(UINT32 idx) { return mFields.at(idx); }
 
 		/**
-		 * @brief	Tries to find a field with the specified name. Throws an exception if it can't.
+		 * Tries to find a field with the specified name. Throws an exception if it can't.
 		 *
 		 * @param	name	The name of the field.
 		 */
 		RTTIField* findField(const String& name);
 
 		/**
-		 * @brief	Tries to find a field with the specified unique ID. Doesn't throw an exception
-		 * 			if it can't find the field (Unlike findField(name)). 
+		 * Tries to find a field with the specified unique ID. Doesn't throw an exception if it can't find the field 
+		 * (Unlike findField(const String&)). 
 		 *
 		 * @param	uniqueFieldId	Unique identifier for the field.
 		 *
@@ -496,18 +479,19 @@ namespace BansheeEngine
 
 	protected:
 		/**
-		 * @brief	Tries to add a new field to the fields array, and throws an exception
-		 * 			if a field with the same name or id already exists.
+		 * Tries to add a new field to the fields array, and throws an exception if a field with the same name or id 
+		 * already exists.
 		 *
-		 * @param [in]	field	Field, must be non-null.
+		 * @param[in]	field	Field, must be non-null.
 		 */
 		void addNewField(RTTIField* field);
 
 		/**
-		 * @brief	Checks if the templated DataType has any references back to us, that aren't weak.
+		 * Checks if the templated DataType has any references back to us, that aren't weak.
 		 * 			
-		 * @note	This method assumes this class holds a non-weak reference to DataType.
-		 * 			DataType must derive from IReflectable and implement getRTTIStatic method.
+		 * @note	
+		 * This method assumes this class holds a non-weak reference to DataType. DataType must derive from IReflectable 
+		 * and implement getRTTIStatic method.
 		 */
 		template<class DataType>
 		void checkForCircularReferences()
@@ -531,7 +515,7 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Throws an exception warning the user that a circular reference was found. 
+		 * Throws an exception warning the user that a circular reference was found. 
 		 *
 		 * @note Only a separate function so I don't need to include BsException header.
 		 */
@@ -541,9 +525,7 @@ namespace BansheeEngine
 		Vector<RTTIField*> mFields;
 	};
 
-	/**
-	 * @brief	Used for initializing a certain type as soon as the program is loaded.
-	 */
+	/** Used for initializing a certain type as soon as the program is loaded. */
 	template<typename Type, typename BaseType>
 	struct InitRTTIOnStart
 	{
@@ -556,9 +538,7 @@ namespace BansheeEngine
 		void makeSureIAmInstantiated() { }
 	};
 
-	/**
-	 * @brief	Specialization for root class of RTTI hierarchy - IReflectable
-	 */
+	/** Specialization for root class of RTTI hierarchy - IReflectable */
 	template<typename Type>
 	struct InitRTTIOnStart<Type, IReflectable>
 	{
@@ -572,8 +552,8 @@ namespace BansheeEngine
 	};
 
 	/**
-	 * @brief	Template that returns RTTI type of the specified type, unless the specified
-	 * 			type is IReflectable in which case it returns a null.
+	 * Template that returns RTTI type of the specified type, unless the specified type is IReflectable in which case it 
+	 * returns a null.
 	 */
 	template<typename Type>
 	struct GetRTTIType
@@ -581,24 +561,24 @@ namespace BansheeEngine
 		RTTITypeBase* operator()() { return Type::getRTTIStatic(); }
 	};
 
-	/**
-	 * @brief	Specialization for root class of RTTI hierarchy - IReflectable
-	 */
+	/** Specialization for root class of RTTI hierarchy - IReflectable. */
 	template<>
 	struct GetRTTIType<IReflectable>
 	{
 		RTTITypeBase* operator()() { return nullptr; }
 	};
 
+	/** @endcond */
+
 	/**
-	 * @brief	Allows you to provide a run-time type information for a specific class, along with 
-	 * 			support for serialization/deserialization.
+	 * Allows you to provide a run-time type information for a specific class, along with support for 
+	 * serialization/deserialization.
 	 * 			
-	 * 			Derive from this class and return the that class from IReflectable::getRTTI. 
-	 * 			This way you can separate serialization logic from the actual class you're serializing.
+	 * Derive from this class and return the that class from IReflectable::getRTTI. This way you can separate serialization 
+	 * logic from the actual class you're serializing.
 	 *
-	 *			This class will provide a way to register individual fields in the class, together with ways to
-	 *			read and write them, as well a providing information about class hierarchy, and run-time type checking.
+	 * This class will provide a way to register individual fields in the class, together with ways to read and write them, 
+	 * as well a providing information about class hierarchy, and run-time type checking.
 	 */
 	template <typename Type, typename BaseType, typename MyRTTIType>
 	class RTTIType : public RTTITypeBase
@@ -620,36 +600,28 @@ namespace BansheeEngine
 		}
 		virtual ~RTTIType() {}
 
-		/**
-		 * @brief	Returns a singleton of this RTTI type.
-		 */
+		/** Returns a singleton of this RTTI type. */
 		static MyRTTIType* instance()
 		{
 			static MyRTTIType inst;
 			return &inst;
 		}
 
-		/**
-		 * @copydoc	RTTITypeBase::getDerivedClasses
-		 */
-		virtual Vector<RTTITypeBase*>& getDerivedClasses()
+		/** @copydoc RTTITypeBase::getDerivedClasses */
+		Vector<RTTITypeBase*>& getDerivedClasses() override
 		{
 			static Vector<RTTITypeBase*> mRTTIDerivedClasses;
 			return mRTTIDerivedClasses;
 		}
 
-		/**
-		 * @copydoc	RTTITypeBase::getBaseClass
-		 */
-		virtual RTTITypeBase* getBaseClass()
+		/** @copydoc RTTITypeBase::getBaseClass */
+		RTTITypeBase* getBaseClass() override
 		{
 			return GetRTTIType<BaseType>()();
 		}
 
-		/**
-		 * @copydoc	RTTITypeBase::isDerivedFrom
-		 */
-		bool RTTITypeBase::isDerivedFrom(RTTITypeBase* base)
+		/** @copydoc RTTITypeBase::isDerivedFrom */
+		bool RTTITypeBase::isDerivedFrom(RTTITypeBase* base) override
 		{
 			assert(base != nullptr);
 
@@ -672,10 +644,8 @@ namespace BansheeEngine
 			return false;
 		}
 
-		/**
-		 * @copydoc	RTTITypeBase::_registerDerivedClass
-		 */
-		virtual void _registerDerivedClass(RTTITypeBase* derivedClass)
+		/** @copydoc	RTTITypeBase::_registerDerivedClass */
+		void _registerDerivedClass(RTTITypeBase* derivedClass) override
 		{
 			if(IReflectable::_isTypeIdDuplicate(derivedClass->getRTTIId()))
 			{
@@ -691,17 +661,16 @@ namespace BansheeEngine
 		/************************************************************************/
 
 		/**
-		 * @brief	Registers a new plain field. This field can then be accessed dynamically from the RTTI system and
-		 *			used for automatic serialization. See RTTIField for more information about field types.
+		 * Registers a new plain field. This field can then be accessed dynamically from the RTTI system and used for 
+		 * automatic serialization. See RTTIField for more information about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving the value of this field.
-		 * @param	setter  	Method used for setting the value of this field.
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving the value of this field.
+		 * @param[in]	setter  	Method used for setting the value of this field.
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType, class DataType>
 		void addPlainField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(), 
@@ -713,17 +682,16 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Registers a new reflectable object field. This field can then be accessed dynamically from the RTTI system and
-		 *			used for automatic serialization. See RTTIField for more information about field types.
+		 * Registers a new reflectable object field. This field can then be accessed dynamically from the RTTI system and
+		 * used for automatic serialization. See RTTIField for more information about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving the value of this field.
-		 * @param	setter  	Method used for setting the value of this field.
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving the value of this field.
+		 * @param[in]	setter  	Method used for setting the value of this field.
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType, class DataType>
 		void addReflectableField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(), 
@@ -735,17 +703,16 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Registers a new reflectable object pointer field. This field can then be accessed dynamically from the RTTI system and
-		 *			used for automatic serialization. See RTTIField for more information about field types.
+		 * Registers a new reflectable object pointer field. This field can then be accessed dynamically from the RTTI 
+		 * system and used for automatic serialization. See RTTIField for more information about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving the value of this field.
-		 * @param	setter  	Method used for setting the value of this field.
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving the value of this field.
+		 * @param[in]	setter  	Method used for setting the value of this field.
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType, class DataType>
 		void addReflectablePtrField(const String& name, UINT32 uniqueId, std::shared_ptr<DataType> (ObjectType::*getter)(), 
@@ -757,19 +724,18 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Registers a new field containg an array of plain values. This field can then be accessed dynamically from the RTTI system and
-		 *			used for automatic serialization. See RTTIField for more information about field types.
+		 * Registers a new field containg an array of plain values. This field can then be accessed dynamically from the 
+		 * RTTI system and used for automatic serialization. See RTTIField for more information about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving a single element of the array.
-		 * @param	getSize 	Getter method that returns the size of the array.
-		 * @param	setter  	Method used for setting the a single element of the field.
-		 * @param	setSize 	Setter method that allows you to resize the array. 
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving a single element of the array.
+		 * @param[in]	getSize 	Getter method that returns the size of the array.
+		 * @param[in]	setter  	Method used for setting the a single element of the field.
+		 * @param[in]	setSize 	Setter method that allows you to resize the array. 
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType, class DataType>
 		void addPlainArrayField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), 
@@ -783,20 +749,18 @@ namespace BansheeEngine
 		}	
 
 		/**
-		 * @brief	Registers a new field containg an array of reflectable object values. This field can then be accessed 
-		 *			dynamically from the RTTI system and used for automatic serialization. See RTTIField for more information 
-		 *			about field types.
+		 * Registers a new field containg an array of reflectable object values. This field can then be accessed dynamically
+		 * from the RTTI system and used for automatic serialization. See RTTIField for more information about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving a single element of the array.
-		 * @param	getSize 	Getter method that returns the size of the array.
-		 * @param	setter  	Method used for setting the a single element of the field.
-		 * @param	setSize 	Setter method that allows you to resize the array. 
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving a single element of the array.
+		 * @param[in]	getSize 	Getter method that returns the size of the array.
+		 * @param[in]	setter  	Method used for setting the a single element of the field.
+		 * @param[in]	setSize 	Setter method that allows you to resize the array. 
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType, class DataType>
 		void addReflectableArrayField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), 
@@ -810,20 +774,19 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Registers a new field containg an array of reflectable obejct pointers. This field can then be accessed 
-		 *			dynamically from the RTTI system and used for automatic serialization. See RTTIField for more information 
-		 *			about field types.
+		 * Registers a new field containg an array of reflectable obejct pointers. This field can then be accessed 
+		 * dynamically from the RTTI system and used for automatic serialization. See RTTIField for more information 
+		 * about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving a single element of the array.
-		 * @param	getSize 	Getter method that returns the size of the array.
-		 * @param	setter  	Method used for setting the a single element of the field.
-		 * @param	setSize 	Setter method that allows you to resize the array. 
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving a single element of the array.
+		 * @param[in]	getSize 	Getter method that returns the size of the array.
+		 * @param[in]	setter  	Method used for setting the a single element of the field.
+		 * @param[in]	setSize 	Setter method that allows you to resize the array. 
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType, class DataType>
 		void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, std::shared_ptr<DataType> (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), 
@@ -837,17 +800,16 @@ namespace BansheeEngine
 		}
 
 		/**
-		 * @brief	Registers a new managed data block field. This field can then be accessed dynamically from the RTTI system and
-		 *			used for automatic serialization. See RTTIField for more information about field types.
+		 * Registers a new managed data block field. This field can then be accessed dynamically from the RTTI system and
+		 * used for automatic serialization. See RTTIField for more information about field types.
 		 *
-		 * @param	name		Name of the field.
-		 * @param	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	getter  	Method used for retrieving the value of this field.
-		 * @param	setter  	Method used for setting the value of this field.
-		 * @param	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
+		 * @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  	Method used for retrieving the value of this field.
+		 * @param[in]	setter  	Method used for setting the value of this field.
+		 * @param[in]	flags		Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
 		 */
 		template<class ObjectType>
 		void addDataBlockField(const String& name, UINT32 uniqueId, ManagedDataBlock (ObjectType::*getter)(), 
@@ -1078,9 +1040,7 @@ namespace BansheeEngine
 	template <typename Type, typename BaseType, typename MyRTTIType>
 	InitRTTIOnStart<Type, BaseType> RTTIType<Type, BaseType, MyRTTIType>::initOnStart;
 
-	/**
-	 * @brief	Returns true if the provided object can be safely cast into type T.
-	 */
+	/** 	Returns true if the provided object can be safely cast into type T. */
 	template<class T>
 	bool rtti_is_of_type(IReflectable* object)
 	{
@@ -1090,9 +1050,7 @@ namespace BansheeEngine
 		return object->getTypeId() == T::getRTTIStatic()->getRTTIId();
 	}
 
-	/**
-	 * @brief	Returns true if the provided object can be safely cast into type T.
-	 */
+	/** Returns true if the provided object can be safely cast into type T. */
 	template<class T>
 	bool rtti_is_of_type(std::shared_ptr<IReflectable> object)
 	{
@@ -1102,14 +1060,10 @@ namespace BansheeEngine
 		return object->getTypeId() == T::getRTTIStatic()->getRTTIId();
 	}
 
-	/**
-	 * @brief	Creates a new object just from its type ID.
-	 */
+	/** Creates a new object just from its type ID. */
 	std::shared_ptr<IReflectable> rtti_create(UINT32 rttiId);
 
-	/**
-	 * @brief	Checks is the current object a subclass of some type.
-	 */
+	/** Checks is the current object a subclass of some type. */
 	template<class T>
 	bool rtti_is_subclass(IReflectable* object)
 	{
@@ -1118,4 +1072,6 @@ namespace BansheeEngine
 
 		return object->isDerivedFrom(T::getRTTIStatic());
 	}
+
+	/** @} */
 }

+ 169 - 186
BansheeUtility/Include/BsSerializedObject.h

@@ -1,187 +1,170 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsIReflectable.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Base class for intermediate representations of
-	 *			objects that are being decoded with BinarySerializer.
-	 */
-	struct BS_UTILITY_EXPORT SerializedInstance : IReflectable
-	{
-		virtual ~SerializedInstance() { }
-
-		/**
-		 * @brief	Performs a deep clone of this object any any potential child objects.
-		 * 			
-		 * @param	cloneData	If true the data contained by the objects will be cloned as well, instead of
-		 * 						just meta-data. If false then both the original and the cloned instances
-		 * 						will point to the same instances of data. The original will retain data ownership 
-		 * 						and it will go out of scope when the original does.
-		 */
-		virtual SPtr<SerializedInstance> clone(bool cloneData = true) = 0;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedInstanceRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/**
-	 * @brief	An intermediate serialized data for a single field in an object.
-	 */
-	struct BS_UTILITY_EXPORT SerializedEntry : IReflectable
-	{
-		SerializedEntry()
-			:fieldId(0), serialized(nullptr)
-		{ }
-
-		UINT32 fieldId;
-		SPtr<SerializedInstance> serialized;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedEntryRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/**
-	 * @brief	A serialized value representing a single entry in an array.
-	 */
-	struct BS_UTILITY_EXPORT SerializedArrayEntry : IReflectable
-	{
-		SerializedArrayEntry()
-			:index(0), serialized(nullptr)
-		{ }
-
-		UINT32 index;
-		SPtr<SerializedInstance> serialized;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedArrayEntryRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/**
-	 * @brief	A serialized portion of an object belonging to a specific class in a class hierarchy.
-	 * 			Consists of multiple entries, one for each field.
-	 */
-	struct BS_UTILITY_EXPORT SerializedSubObject : IReflectable
-	{
-		SerializedSubObject()
-			:typeId(0)
-		{ }
-
-		UINT32 typeId;
-		UnorderedMap<UINT32, SerializedEntry> entries;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedSubObjectRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/**
-	 * @brief	A serialized object consisting of multiple sub-objects,
-	 *			one for each inherited class.
-	 */
-	struct BS_UTILITY_EXPORT SerializedObject : SerializedInstance
-	{
-		/**
-		 * @brief	Returns the RTTI type ID for the most-derived class of this object.
-		 */
-		UINT32 getRootTypeId() const { return subObjects[0].typeId; }
-
-		/**
-		 * @copydoc	SerializedInstance::clone
-		 */
-		SPtr<SerializedInstance> clone(bool cloneData = true) override;
-
-		Vector<SerializedSubObject> subObjects;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedObjectRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/**
-	 * @brief	Contains data for a serialized value of a specific
-	 *			field or array entry.
-	 */
-	struct BS_UTILITY_EXPORT SerializedField : SerializedInstance
-	{
-		SerializedField()
-			:value(nullptr), size(0), ownsMemory(false)
-		{
-
-		}
-
-		~SerializedField()
-		{
-			if (ownsMemory && value != nullptr)
-				bs_free(value);
-		}
-
-		/**
-		 * @copydoc	SerializedInstance::clone
-		 */
-		SPtr<SerializedInstance> clone(bool cloneData = true) override;
-
-		UINT8* value;
-		UINT32 size;
-		bool ownsMemory;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedFieldRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
-
-	/**
-	 * @brief	A serialized array containing a list of all its entries.
-	 */
-	struct BS_UTILITY_EXPORT SerializedArray : SerializedInstance
-	{
-		SerializedArray()
-			:numElements(0)
-		{ }
-
-		/**
-		 * @copydoc	SerializedInstance::clone
-		 */
-		SPtr<SerializedInstance> clone(bool cloneData = true) override;
-
-		UnorderedMap<UINT32, SerializedArrayEntry> entries;
-		UINT32 numElements;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class SerializedArrayRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsIReflectable.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Serialization
+	 *  @{
+	 */
+
+	/** Base class for intermediate representations of objects that are being decoded with BinarySerializer. */
+	struct BS_UTILITY_EXPORT SerializedInstance : IReflectable
+	{
+		virtual ~SerializedInstance() { }
+
+		/**
+		 * Performs a deep clone of this object any any potential child objects.
+		 * 			
+		 * @param[in]	cloneData	If true the data contained by the objects will be cloned as well, instead of just 
+		 *							meta-data. If false then both the original and the cloned instances will point to the 
+		 *							same instances of data. The original will retain data ownership and it will go out of 
+		 *							scope when the original does.
+		 */
+		virtual SPtr<SerializedInstance> clone(bool cloneData = true) = 0;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedInstanceRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** An intermediate serialized data for a single field in an object. */
+	struct BS_UTILITY_EXPORT SerializedEntry : IReflectable
+	{
+		SerializedEntry()
+			:fieldId(0), serialized(nullptr)
+		{ }
+
+		UINT32 fieldId;
+		SPtr<SerializedInstance> serialized;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedEntryRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** A serialized value representing a single entry in an array. */
+	struct BS_UTILITY_EXPORT SerializedArrayEntry : IReflectable
+	{
+		SerializedArrayEntry()
+			:index(0), serialized(nullptr)
+		{ }
+
+		UINT32 index;
+		SPtr<SerializedInstance> serialized;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedArrayEntryRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/**
+	 * A serialized portion of an object belonging to a specific class in a class hierarchy. Consists of multiple entries,
+	 * one for each field.
+	 */
+	struct BS_UTILITY_EXPORT SerializedSubObject : IReflectable
+	{
+		SerializedSubObject()
+			:typeId(0)
+		{ }
+
+		UINT32 typeId;
+		UnorderedMap<UINT32, SerializedEntry> entries;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedSubObjectRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** A serialized object consisting of multiple sub-objects, one for each inherited class. */
+	struct BS_UTILITY_EXPORT SerializedObject : SerializedInstance
+	{
+		/** Returns the RTTI type ID for the most-derived class of this object. */
+		UINT32 getRootTypeId() const { return subObjects[0].typeId; }
+
+		/** @copydoc SerializedInstance::clone */
+		SPtr<SerializedInstance> clone(bool cloneData = true) override;
+
+		Vector<SerializedSubObject> subObjects;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedObjectRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** Contains data for a serialized value of a specific field or array entry. */
+	struct BS_UTILITY_EXPORT SerializedField : SerializedInstance
+	{
+		SerializedField()
+			:value(nullptr), size(0), ownsMemory(false)
+		{
+
+		}
+
+		~SerializedField()
+		{
+			if (ownsMemory && value != nullptr)
+				bs_free(value);
+		}
+
+		/** @copydoc SerializedInstance::clone */
+		SPtr<SerializedInstance> clone(bool cloneData = true) override;
+
+		UINT8* value;
+		UINT32 size;
+		bool ownsMemory;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedFieldRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** A serialized array containing a list of all its entries. */
+	struct BS_UTILITY_EXPORT SerializedArray : SerializedInstance
+	{
+		SerializedArray()
+			:numElements(0)
+		{ }
+
+		/** @copydoc SerializedInstance::clone */
+		SPtr<SerializedInstance> clone(bool cloneData = true) override;
+
+		UnorderedMap<UINT32, SerializedArrayEntry> entries;
+		UINT32 numElements;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SerializedArrayRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/** @} */
 }

+ 372 - 368
BansheeUtility/Include/BsSerializedObjectRTTI.h

@@ -1,369 +1,373 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsRTTIType.h"
-#include "BsSerializedObject.h"
-
-namespace BansheeEngine
-{
-	class BS_UTILITY_EXPORT SerializedInstanceRTTI : public RTTIType <SerializedInstance, IReflectable, SerializedInstanceRTTI>
-	{
-	public:
-		SerializedInstanceRTTI()
-		{ }
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedInstance";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedInstance;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return nullptr;
-		}
-	};
-
-	class BS_UTILITY_EXPORT SerializedFieldRTTI : public RTTIType <SerializedField, SerializedInstance, SerializedFieldRTTI>
-	{
-	private:
-		ManagedDataBlock getData(SerializedField* obj)
-		{
-			ManagedDataBlock dataBlock((UINT8*)obj->value, obj->size);
-			return dataBlock;
-		}
-
-		void setData(SerializedField* obj, ManagedDataBlock val)
-		{
-			// Nothing to do here, the pointer we provided already belongs to SerializedField
-			// so the data is already written
-		}
-
-		static UINT8* allocateData(SerializedField* obj, UINT32 numBytes)
-		{
-			obj->value = (UINT8*)bs_alloc(numBytes);
-			obj->size = numBytes;
-			obj->ownsMemory = true;
-
-			return obj->value;
-		}
-	public:
-		SerializedFieldRTTI()
-		{
-			addDataBlockField("data", 0, &SerializedFieldRTTI::getData, &SerializedFieldRTTI::setData, 0, &SerializedFieldRTTI::allocateData);
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedField";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedField;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<SerializedField>();
-		}
-	};
-
-	class BS_UTILITY_EXPORT SerializedObjectRTTI : public RTTIType <SerializedObject, SerializedInstance, SerializedObjectRTTI>
-	{
-	private:
-		SerializedSubObject& getEntry(SerializedObject* obj, UINT32 arrayIdx)
-		{
-			return obj->subObjects[arrayIdx];
-		}
-
-		void setEntry(SerializedObject* obj, UINT32 arrayIdx, SerializedSubObject& val)
-		{
-			obj->subObjects[arrayIdx] = val;
-		}
-
-		UINT32 getNumEntries(SerializedObject* obj)
-		{
-			return (UINT32)obj->subObjects.size();
-		}
-
-		void setNumEntries(SerializedObject* obj, UINT32 numEntries)
-		{
-			obj->subObjects = Vector<SerializedSubObject>(numEntries);
-		}
-	public:
-		SerializedObjectRTTI()
-		{
-			addReflectableArrayField("entries", 1, &SerializedObjectRTTI::getEntry, &SerializedObjectRTTI::getNumEntries,
-				&SerializedObjectRTTI::setEntry, &SerializedObjectRTTI::setNumEntries);
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedObject";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedObject;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<SerializedObject>();
-		}
-	};
-
-	class BS_UTILITY_EXPORT SerializedArrayRTTI : public RTTIType <SerializedArray, SerializedInstance, SerializedArrayRTTI>
-	{
-	private:
-		UINT32& getNumElements(SerializedArray* obj)
-		{
-			return obj->numElements;
-		}
-
-		void setNumElements(SerializedArray* obj, UINT32& val)
-		{
-			obj->numElements = val;
-		}
-
-		SerializedArrayEntry& getEntry(SerializedArray* obj, UINT32 arrayIdx)
-		{
-			Vector<SerializedArrayEntry>& sequentialEntries = any_cast_ref<Vector<SerializedArrayEntry>>(obj->mRTTIData);
-			return sequentialEntries[arrayIdx];
-		}
-
-		void setEntry(SerializedArray* obj, UINT32 arrayIdx, SerializedArrayEntry& val)
-		{
-			obj->entries[val.index] = val;
-		}
-
-		UINT32 getNumEntries(SerializedArray* obj)
-		{
-			Vector<SerializedArrayEntry>& sequentialEntries = any_cast_ref<Vector<SerializedArrayEntry>>(obj->mRTTIData);
-			return (UINT32)sequentialEntries.size();
-		}
-
-		void setNumEntries(SerializedArray* obj, UINT32 numEntries)
-		{
-			obj->entries = UnorderedMap<UINT32, SerializedArrayEntry>();
-		}
-	public:
-		SerializedArrayRTTI()
-		{
-			addPlainField("numElements", 0, &SerializedArrayRTTI::getNumElements, &SerializedArrayRTTI::setNumElements);
-			addReflectableArrayField("entries", 1, &SerializedArrayRTTI::getEntry, &SerializedArrayRTTI::getNumEntries,
-				&SerializedArrayRTTI::setEntry, &SerializedArrayRTTI::setNumEntries);
-		}
-
-		virtual void onSerializationStarted(IReflectable* obj)
-		{
-			SerializedArray* serializedArray = static_cast<SerializedArray*>(obj);
-
-			Vector<SerializedArrayEntry> sequentialData;
-			for (auto& entry : serializedArray->entries)
-				sequentialData.push_back(entry.second);
-
-			serializedArray->mRTTIData = sequentialData;
-		}
-
-		virtual void onSerializationEnded(IReflectable* obj)
-		{
-			SerializedArray* serializedArray = static_cast<SerializedArray*>(obj);
-			serializedArray->mRTTIData = nullptr;
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedArray";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedArray;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<SerializedArray>();
-		}
-	};
-
-	class BS_UTILITY_EXPORT SerializedSubObjectRTTI : public RTTIType <SerializedSubObject, IReflectable, SerializedSubObjectRTTI>
-	{
-	private:
-		UINT32& getTypeId(SerializedSubObject* obj)
-		{
-			return obj->typeId;
-		}
-
-		void setTypeId(SerializedSubObject* obj, UINT32& val)
-		{
-			obj->typeId = val;
-		}
-
-		SerializedEntry& getEntry(SerializedSubObject* obj, UINT32 arrayIdx)
-		{
-			Vector<SerializedEntry>& sequentialEntries = any_cast_ref<Vector<SerializedEntry>>(obj->mRTTIData);
-			return sequentialEntries[arrayIdx];
-		}
-
-		void setEntry(SerializedSubObject* obj, UINT32 arrayIdx, SerializedEntry& val)
-		{
-			obj->entries[val.fieldId] = val;
-		}
-
-		UINT32 getNumEntries(SerializedSubObject* obj)
-		{
-			Vector<SerializedEntry>& sequentialEntries = any_cast_ref<Vector<SerializedEntry>>(obj->mRTTIData);
-			return (UINT32)sequentialEntries.size();
-		}
-
-		void setNumEntries(SerializedSubObject* obj, UINT32 numEntries)
-		{
-			obj->entries = UnorderedMap<UINT32, SerializedEntry>();
-		}
-	public:
-		SerializedSubObjectRTTI()
-		{
-			addPlainField("typeId", 0, &SerializedSubObjectRTTI::getTypeId, &SerializedSubObjectRTTI::setTypeId);
-			addReflectableArrayField("entries", 1, &SerializedSubObjectRTTI::getEntry, &SerializedSubObjectRTTI::getNumEntries,
-				&SerializedSubObjectRTTI::setEntry, &SerializedSubObjectRTTI::setNumEntries);
-		}
-
-		virtual void onSerializationStarted(IReflectable* obj) override
-		{
-			SerializedSubObject* serializableObject = static_cast<SerializedSubObject*>(obj);
-
-			Vector<SerializedEntry> sequentialData;
-			for (auto& entry : serializableObject->entries)
-				sequentialData.push_back(entry.second);
-
-			serializableObject->mRTTIData = sequentialData;
-		}
-
-		virtual void onSerializationEnded(IReflectable* obj) override
-		{
-			SerializedSubObject* serializableObject = static_cast<SerializedSubObject*>(obj);
-			serializableObject->mRTTIData = nullptr;
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedSubObject";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedSubObject;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<SerializedSubObject>();
-		}
-	};
-
-	class BS_UTILITY_EXPORT SerializedEntryRTTI : public RTTIType <SerializedEntry, IReflectable, SerializedEntryRTTI>
-	{
-	private:
-		UINT32& getFieldId(SerializedEntry* obj)
-		{
-			return obj->fieldId;
-		}
-
-		void setFieldId(SerializedEntry* obj, UINT32& val)
-		{
-			obj->fieldId = val;
-		}
-
-		SPtr<SerializedInstance> getSerialized(SerializedEntry* obj)
-		{
-			return obj->serialized;
-		}
-
-		void setSerialized(SerializedEntry* obj, SPtr<SerializedInstance> val)
-		{
-			obj->serialized = val;
-		}
-
-	public:
-		SerializedEntryRTTI()
-		{
-			addPlainField("fieldId", 0, &SerializedEntryRTTI::getFieldId, &SerializedEntryRTTI::setFieldId);
-			addReflectablePtrField("serialized", 1, &SerializedEntryRTTI::getSerialized, &SerializedEntryRTTI::setSerialized);
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedEntry";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedEntry;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<SerializedEntry>();
-		}
-	};
-
-	class BS_UTILITY_EXPORT SerializedArrayEntryRTTI : public RTTIType <SerializedArrayEntry, IReflectable, SerializedArrayEntryRTTI>
-	{
-	private:
-		UINT32& getArrayIdx(SerializedArrayEntry* obj)
-		{
-			return obj->index;
-		}
-
-		void setArrayIdx(SerializedArrayEntry* obj, UINT32& val)
-		{
-			obj->index = val;
-		}
-
-		SPtr<SerializedInstance> getSerialized(SerializedArrayEntry* obj)
-		{
-			return obj->serialized;
-		}
-
-		void setSerialized(SerializedArrayEntry* obj, SPtr<SerializedInstance> val)
-		{
-			obj->serialized = val;
-		}
-
-	public:
-		SerializedArrayEntryRTTI()
-		{
-			addPlainField("index", 0, &SerializedArrayEntryRTTI::getArrayIdx, &SerializedArrayEntryRTTI::setArrayIdx);
-			addReflectablePtrField("serialized", 1, &SerializedArrayEntryRTTI::getSerialized, &SerializedArrayEntryRTTI::setSerialized);
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "SerializedArrayEntry";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_SerializedArrayEntry;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<SerializedArrayEntry>();
-		}
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsRTTIType.h"
+#include "BsSerializedObject.h"
+
+namespace BansheeEngine
+{
+	/** @cond RTTI */
+
+	class BS_UTILITY_EXPORT SerializedInstanceRTTI : public RTTIType <SerializedInstance, IReflectable, SerializedInstanceRTTI>
+	{
+	public:
+		SerializedInstanceRTTI()
+		{ }
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedInstance";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedInstance;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return nullptr;
+		}
+	};
+
+	class BS_UTILITY_EXPORT SerializedFieldRTTI : public RTTIType <SerializedField, SerializedInstance, SerializedFieldRTTI>
+	{
+	private:
+		ManagedDataBlock getData(SerializedField* obj)
+		{
+			ManagedDataBlock dataBlock((UINT8*)obj->value, obj->size);
+			return dataBlock;
+		}
+
+		void setData(SerializedField* obj, ManagedDataBlock val)
+		{
+			// Nothing to do here, the pointer we provided already belongs to SerializedField
+			// so the data is already written
+		}
+
+		static UINT8* allocateData(SerializedField* obj, UINT32 numBytes)
+		{
+			obj->value = (UINT8*)bs_alloc(numBytes);
+			obj->size = numBytes;
+			obj->ownsMemory = true;
+
+			return obj->value;
+		}
+	public:
+		SerializedFieldRTTI()
+		{
+			addDataBlockField("data", 0, &SerializedFieldRTTI::getData, &SerializedFieldRTTI::setData, 0, &SerializedFieldRTTI::allocateData);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedField";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedField;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<SerializedField>();
+		}
+	};
+
+	class BS_UTILITY_EXPORT SerializedObjectRTTI : public RTTIType <SerializedObject, SerializedInstance, SerializedObjectRTTI>
+	{
+	private:
+		SerializedSubObject& getEntry(SerializedObject* obj, UINT32 arrayIdx)
+		{
+			return obj->subObjects[arrayIdx];
+		}
+
+		void setEntry(SerializedObject* obj, UINT32 arrayIdx, SerializedSubObject& val)
+		{
+			obj->subObjects[arrayIdx] = val;
+		}
+
+		UINT32 getNumEntries(SerializedObject* obj)
+		{
+			return (UINT32)obj->subObjects.size();
+		}
+
+		void setNumEntries(SerializedObject* obj, UINT32 numEntries)
+		{
+			obj->subObjects = Vector<SerializedSubObject>(numEntries);
+		}
+	public:
+		SerializedObjectRTTI()
+		{
+			addReflectableArrayField("entries", 1, &SerializedObjectRTTI::getEntry, &SerializedObjectRTTI::getNumEntries,
+				&SerializedObjectRTTI::setEntry, &SerializedObjectRTTI::setNumEntries);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedObject";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedObject;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<SerializedObject>();
+		}
+	};
+
+	class BS_UTILITY_EXPORT SerializedArrayRTTI : public RTTIType <SerializedArray, SerializedInstance, SerializedArrayRTTI>
+	{
+	private:
+		UINT32& getNumElements(SerializedArray* obj)
+		{
+			return obj->numElements;
+		}
+
+		void setNumElements(SerializedArray* obj, UINT32& val)
+		{
+			obj->numElements = val;
+		}
+
+		SerializedArrayEntry& getEntry(SerializedArray* obj, UINT32 arrayIdx)
+		{
+			Vector<SerializedArrayEntry>& sequentialEntries = any_cast_ref<Vector<SerializedArrayEntry>>(obj->mRTTIData);
+			return sequentialEntries[arrayIdx];
+		}
+
+		void setEntry(SerializedArray* obj, UINT32 arrayIdx, SerializedArrayEntry& val)
+		{
+			obj->entries[val.index] = val;
+		}
+
+		UINT32 getNumEntries(SerializedArray* obj)
+		{
+			Vector<SerializedArrayEntry>& sequentialEntries = any_cast_ref<Vector<SerializedArrayEntry>>(obj->mRTTIData);
+			return (UINT32)sequentialEntries.size();
+		}
+
+		void setNumEntries(SerializedArray* obj, UINT32 numEntries)
+		{
+			obj->entries = UnorderedMap<UINT32, SerializedArrayEntry>();
+		}
+	public:
+		SerializedArrayRTTI()
+		{
+			addPlainField("numElements", 0, &SerializedArrayRTTI::getNumElements, &SerializedArrayRTTI::setNumElements);
+			addReflectableArrayField("entries", 1, &SerializedArrayRTTI::getEntry, &SerializedArrayRTTI::getNumEntries,
+				&SerializedArrayRTTI::setEntry, &SerializedArrayRTTI::setNumEntries);
+		}
+
+		virtual void onSerializationStarted(IReflectable* obj)
+		{
+			SerializedArray* serializedArray = static_cast<SerializedArray*>(obj);
+
+			Vector<SerializedArrayEntry> sequentialData;
+			for (auto& entry : serializedArray->entries)
+				sequentialData.push_back(entry.second);
+
+			serializedArray->mRTTIData = sequentialData;
+		}
+
+		virtual void onSerializationEnded(IReflectable* obj)
+		{
+			SerializedArray* serializedArray = static_cast<SerializedArray*>(obj);
+			serializedArray->mRTTIData = nullptr;
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedArray";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedArray;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<SerializedArray>();
+		}
+	};
+
+	class BS_UTILITY_EXPORT SerializedSubObjectRTTI : public RTTIType <SerializedSubObject, IReflectable, SerializedSubObjectRTTI>
+	{
+	private:
+		UINT32& getTypeId(SerializedSubObject* obj)
+		{
+			return obj->typeId;
+		}
+
+		void setTypeId(SerializedSubObject* obj, UINT32& val)
+		{
+			obj->typeId = val;
+		}
+
+		SerializedEntry& getEntry(SerializedSubObject* obj, UINT32 arrayIdx)
+		{
+			Vector<SerializedEntry>& sequentialEntries = any_cast_ref<Vector<SerializedEntry>>(obj->mRTTIData);
+			return sequentialEntries[arrayIdx];
+		}
+
+		void setEntry(SerializedSubObject* obj, UINT32 arrayIdx, SerializedEntry& val)
+		{
+			obj->entries[val.fieldId] = val;
+		}
+
+		UINT32 getNumEntries(SerializedSubObject* obj)
+		{
+			Vector<SerializedEntry>& sequentialEntries = any_cast_ref<Vector<SerializedEntry>>(obj->mRTTIData);
+			return (UINT32)sequentialEntries.size();
+		}
+
+		void setNumEntries(SerializedSubObject* obj, UINT32 numEntries)
+		{
+			obj->entries = UnorderedMap<UINT32, SerializedEntry>();
+		}
+	public:
+		SerializedSubObjectRTTI()
+		{
+			addPlainField("typeId", 0, &SerializedSubObjectRTTI::getTypeId, &SerializedSubObjectRTTI::setTypeId);
+			addReflectableArrayField("entries", 1, &SerializedSubObjectRTTI::getEntry, &SerializedSubObjectRTTI::getNumEntries,
+				&SerializedSubObjectRTTI::setEntry, &SerializedSubObjectRTTI::setNumEntries);
+		}
+
+		virtual void onSerializationStarted(IReflectable* obj) override
+		{
+			SerializedSubObject* serializableObject = static_cast<SerializedSubObject*>(obj);
+
+			Vector<SerializedEntry> sequentialData;
+			for (auto& entry : serializableObject->entries)
+				sequentialData.push_back(entry.second);
+
+			serializableObject->mRTTIData = sequentialData;
+		}
+
+		virtual void onSerializationEnded(IReflectable* obj) override
+		{
+			SerializedSubObject* serializableObject = static_cast<SerializedSubObject*>(obj);
+			serializableObject->mRTTIData = nullptr;
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedSubObject";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedSubObject;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<SerializedSubObject>();
+		}
+	};
+
+	class BS_UTILITY_EXPORT SerializedEntryRTTI : public RTTIType <SerializedEntry, IReflectable, SerializedEntryRTTI>
+	{
+	private:
+		UINT32& getFieldId(SerializedEntry* obj)
+		{
+			return obj->fieldId;
+		}
+
+		void setFieldId(SerializedEntry* obj, UINT32& val)
+		{
+			obj->fieldId = val;
+		}
+
+		SPtr<SerializedInstance> getSerialized(SerializedEntry* obj)
+		{
+			return obj->serialized;
+		}
+
+		void setSerialized(SerializedEntry* obj, SPtr<SerializedInstance> val)
+		{
+			obj->serialized = val;
+		}
+
+	public:
+		SerializedEntryRTTI()
+		{
+			addPlainField("fieldId", 0, &SerializedEntryRTTI::getFieldId, &SerializedEntryRTTI::setFieldId);
+			addReflectablePtrField("serialized", 1, &SerializedEntryRTTI::getSerialized, &SerializedEntryRTTI::setSerialized);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedEntry";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedEntry;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<SerializedEntry>();
+		}
+	};
+
+	class BS_UTILITY_EXPORT SerializedArrayEntryRTTI : public RTTIType <SerializedArrayEntry, IReflectable, SerializedArrayEntryRTTI>
+	{
+	private:
+		UINT32& getArrayIdx(SerializedArrayEntry* obj)
+		{
+			return obj->index;
+		}
+
+		void setArrayIdx(SerializedArrayEntry* obj, UINT32& val)
+		{
+			obj->index = val;
+		}
+
+		SPtr<SerializedInstance> getSerialized(SerializedArrayEntry* obj)
+		{
+			return obj->serialized;
+		}
+
+		void setSerialized(SerializedArrayEntry* obj, SPtr<SerializedInstance> val)
+		{
+			obj->serialized = val;
+		}
+
+	public:
+		SerializedArrayEntryRTTI()
+		{
+			addPlainField("index", 0, &SerializedArrayEntryRTTI::getArrayIdx, &SerializedArrayEntryRTTI::setArrayIdx);
+			addReflectablePtrField("serialized", 1, &SerializedArrayEntryRTTI::getSerialized, &SerializedArrayEntryRTTI::setSerialized);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "SerializedArrayEntry";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_SerializedArrayEntry;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<SerializedArrayEntry>();
+		}
+	};
+
+	/** @endcond */
 }

+ 55 - 54
BansheeUtility/Include/BsServiceLocator.h

@@ -1,55 +1,56 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	/**
-	* @brief	A locator system that allows you to quickly find a service of
-	*			a specific type.
-	*
-	* @note		This is similar to a singleton pattern but unlike singleton the active instance 
-	*			is not required to be available and can be replaced with another system during 
-	*			runtime, or completely removed.
-	*/
-	template <class T>
-	class ServiceLocator
-	{
-	public:
-		/**
-		 * @brief	Returns an instance of the service we are looking for,
-		 *			if one is available.
-		 *
-		 * @note	Can return null.
-		 */
-		static T* instance() { return mService; }
-
-		/**
-		 * @brief	Starts providing a new service when "instance()" is called.
-		 *			Replaces the previous service. 
-		 */
-		static void _provide(T* service)
-		{
-			mService = service;
-		}
-
-		/**
-		 * @brief	Stops providing a service when "instance()" is called. Ignored if the current service
-		 * 			doesn't match the provided service.
-		 */
-		static void _remove(T* service)
-		{
-			if (mService != service)
-				return;
-
-			mService = nullptr;
-		}
-
-	private:
-		static T* mService;
-	};
-
-	template <class T>
-	T* ServiceLocator<T>::mService = nullptr;
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/**
+	 * A locator system that allows you to quickly find a service of a specific type.
+	 *
+	 * @note	
+	 * This is similar to a singleton pattern but unlike singleton the active instance is not required to be available and 
+	 * can be replaced with another system during runtime, or completely removed.
+	 */
+	template <class T>
+	class ServiceLocator
+	{
+	public:
+		/**
+		 * Returns an instance of the service we are looking for, if one is available.
+		 *
+		 * @note	Can return null.
+		 */
+		static T* instance() { return mService; }
+
+		/** Starts providing a new service when "instance()" is called. Replaces the previous service. */
+		static void _provide(T* service)
+		{
+			mService = service;
+		}
+
+		/**
+		 * Stops providing a service when "instance()" is called. Ignored if the current service doesn't match the 
+		 * provided service.
+		 */
+		static void _remove(T* service)
+		{
+			if (mService != service)
+				return;
+
+			mService = nullptr;
+		}
+
+	private:
+		static T* mService;
+	};
+
+	template <class T>
+	T* ServiceLocator<T>::mService = nullptr;
+
+	/** @} */
 }

+ 211 - 214
BansheeUtility/Include/BsStaticAlloc.h

@@ -1,215 +1,212 @@
-#pragma once
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Static allocator that attempts to perform zero heap allocations by always keeping an active
-	 *			stack-allocated buffer. If the size of allocated data goes over the set limit dynamic allocations
-	 *			will occur however.
-	 *
-	 * @note	This kind of allocator is only able to free all of its memory at once. Freeing individual elements
-	 *			will not free the memory until a call to ::clear.
-	 * 			
-	 * @tparam	BlockSize				Size of the initially allocated static block, and minimum size of any dynamically allocated memory.
-	 * @tparam	MaxDynamicMemory		Maximum amount of unused memory allowed in the buffer after a call to ::clear. Keeping active dynamic 
-	 *									buffers can help prevent further memory allocations at the cost of memory. This is not relevant
-	 *									if you stay within the bounds of the statically allocated memory.
-	 */
-	template<int BlockSize = 512, int MaxDynamicMemory = 512>
-	class StaticAlloc
-	{
-	private:
-		/**
-		 * @brief	A single block of memory within a static allocator.
-		 */
-		class MemBlock
-		{
-		public:
-			MemBlock(UINT8* data, UINT32 size) 
-				:mData(data), mFreePtr(0), mSize(size),
-				mPrevBlock(nullptr), mNextBlock(nullptr)
-			{ }
-
-			/**
-			 * @brief	Allocates a piece of memory within the block. Caller must ensure
-			 *			the block has enough empty space.
-			 */
-			UINT8* alloc(UINT32 amount)
-			{
-				UINT8* freePtr = &mData[mFreePtr];
-				mFreePtr += amount;
-
-				return freePtr;
-			}
-
-			/**
-			 * @brief	Releases all allocations within a block but doesn't actually free the memory.
-			 */
-			void clear()
-			{
-				mFreePtr = 0;
-			}
-
-			UINT8* mData;
-			UINT32 mFreePtr;
-			UINT32 mSize;
-			MemBlock* mPrevBlock;
-			MemBlock* mNextBlock;
-		};
-
-	public:
-		StaticAlloc()
-			:mStaticBlock(mStaticData, BlockSize), mFreeBlock(&mStaticBlock),
-			mTotalAllocBytes(0)
-		{
-
-		}
-
-		~StaticAlloc()
-		{
-			assert(mFreeBlock == &mStaticBlock && mStaticBlock.mFreePtr == 0);
-
-			freeBlocks(mFreeBlock);
-		}
-
-		/**
-		 * @brief	Allocates a new piece of memory of the specified size.
-		 *
-		 * @param	amount	Amount of memory to allocate, in bytes.
-		 */
-		UINT8* alloc(UINT32 amount)
-		{
-#if BS_DEBUG_MODE
-			amount += sizeof(UINT32);
-#endif
-
-			UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
-			if (amount > freeMem)
-				allocBlock(amount);
-
-			UINT8* data = mFreeBlock->alloc(amount);
-
-#if BS_DEBUG_MODE
-			mTotalAllocBytes += amount;
-
-			UINT32* storedSize = reinterpret_cast<UINT32*>(data);
-			*storedSize = amount;
-
-			return data + sizeof(UINT32);
-#else
-			return data;
-#endif
-		}
-
-		/**
-		 * @brief	Deallocates a previously allocated piece of memory.
-		 */
-		void free(void* data)
-		{
-			// Dealloc is only used for debug and can be removed if needed. All the actual deallocation
-			// happens in ::clear
-
-#if BS_DEBUG_MODE
-			UINT8* dataPtr = (UINT8*)data;
-			dataPtr -= sizeof(UINT32);
-
-			UINT32* storedSize = (UINT32*)(dataPtr);
-			mTotalAllocBytes -= *storedSize;
-#endif
-		}
-
-		void clear()
-		{
-			assert(mTotalAllocBytes == 0);
-
-			MemBlock* dynamicBlock = mStaticBlock.mNextBlock;
-			INT32 totalDynamicMemAmount = 0;
-			UINT32 numDynamicBlocks = 0;
-
-			while (dynamicBlock != nullptr)
-			{
-				totalDynamicMemAmount += dynamicBlock->mFreePtr;
-				dynamicBlock->clear();
-			
-				dynamicBlock = dynamicBlock->mNextBlock;
-				numDynamicBlocks++;
-			}
-
-			mFreeBlock = &mStaticBlock;
-			mStaticBlock.clear();
-
-			if (numDynamicBlocks > 1)
-			{
-				freeBlocks(&mStaticBlock);
-				allocBlock(std::min(totalDynamicMemAmount, MaxDynamicMemory));
-				mFreeBlock = &mStaticBlock;
-			}
-			else if (numDynamicBlocks == 1 && MaxDynamicMemory == 0)
-			{
-				freeBlocks(&mStaticBlock);
-			}
-		}
-
-	private:
-		UINT8 mStaticData[BlockSize];
-		MemBlock mStaticBlock;
-
-		MemBlock* mFreeBlock;
-		UINT32 mTotalAllocBytes;
-
-		/**
-		 * @brief	Allocates a dynamic block of memory of the wanted size. The exact allocation size
-		 *			might be slightly higher in order to store block meta data.
-		 */
-		MemBlock* allocBlock(UINT32 wantedSize)
-		{
-			UINT32 blockSize = BlockSize;
-			if (wantedSize > blockSize)
-				blockSize = wantedSize;
-
-			MemBlock* dynamicBlock = mFreeBlock->mNextBlock;
-			MemBlock* newBlock = nullptr;
-			while (dynamicBlock != nullptr)
-			{
-				if (dynamicBlock->mSize >= blockSize)
-				{
-					newBlock = dynamicBlock;
-					break;
-				}
-
-				dynamicBlock = dynamicBlock->mNextBlock;
-			}
-
-			if (newBlock == nullptr)
-			{
-				UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc(blockSize + sizeof(MemBlock)));
-				newBlock = new (data)MemBlock(data + sizeof(MemBlock), blockSize);
-				newBlock->mPrevBlock = mFreeBlock;
-				mFreeBlock->mNextBlock = newBlock;
-			}
-
-			mFreeBlock = newBlock;
-			return newBlock;
-		}
-
-		/**
-		 * @brief	Releases memory for any dynamic blocks following the
-		 *			provided block (if there are any).
-		 */
-		void freeBlocks(MemBlock* start)
-		{
-			MemBlock* dynamicBlock = start->mNextBlock;
-			while (dynamicBlock != nullptr)
-			{
-				MemBlock* nextBlock = dynamicBlock->mNextBlock;
-
-				dynamicBlock->~MemBlock();
-				bs_free(dynamicBlock);
-
-				dynamicBlock = nextBlock;
-			}
-
-			start->mNextBlock = nullptr;
-		}
-	};
+#pragma once
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+
+	/** @addtogroup Memory
+	 *  @{
+	 */
+
+	/**
+	 * Static allocator that attempts to perform zero heap allocations by always keeping an active stack-allocated buffer. 
+	 * If the size of allocated data goes over the set limit dynamic allocations will occur however.
+	 *
+	 * @note	This kind of allocator is only able to free all of its memory at once. Freeing individual elements
+	 *			will not free the memory until a call to clear().
+	 * 			
+	 * @tparam	BlockSize			Size of the initially allocated static block, and minimum size of any dynamically allocated memory.
+	 * @tparam	MaxDynamicMemory	Maximum amount of unused memory allowed in the buffer after a call to clear(). Keeping active dynamic 
+	 *								buffers can help prevent further memory allocations at the cost of memory. This is not relevant
+	 *								if you stay within the bounds of the statically allocated memory.
+	 */
+	template<int BlockSize = 512, int MaxDynamicMemory = 512>
+	class StaticAlloc
+	{
+	private:
+		/** A single block of memory within a static allocator. */
+		class MemBlock
+		{
+		public:
+			MemBlock(UINT8* data, UINT32 size) 
+				:mData(data), mFreePtr(0), mSize(size),
+				mPrevBlock(nullptr), mNextBlock(nullptr)
+			{ }
+
+			/** Allocates a piece of memory within the block. Caller must ensure the block has enough empty space. */
+			UINT8* alloc(UINT32 amount)
+			{
+				UINT8* freePtr = &mData[mFreePtr];
+				mFreePtr += amount;
+
+				return freePtr;
+			}
+
+			/** Releases all allocations within a block but doesn't actually free the memory. */
+			void clear()
+			{
+				mFreePtr = 0;
+			}
+
+			UINT8* mData;
+			UINT32 mFreePtr;
+			UINT32 mSize;
+			MemBlock* mPrevBlock;
+			MemBlock* mNextBlock;
+		};
+
+	public:
+		StaticAlloc()
+			:mStaticBlock(mStaticData, BlockSize), mFreeBlock(&mStaticBlock),
+			mTotalAllocBytes(0)
+		{
+
+		}
+
+		~StaticAlloc()
+		{
+			assert(mFreeBlock == &mStaticBlock && mStaticBlock.mFreePtr == 0);
+
+			freeBlocks(mFreeBlock);
+		}
+
+		/**
+		 * Allocates a new piece of memory of the specified size.
+		 *
+		 * @param[in]	amount	Amount of memory to allocate, in bytes.
+		 */
+		UINT8* alloc(UINT32 amount)
+		{
+#if BS_DEBUG_MODE
+			amount += sizeof(UINT32);
+#endif
+
+			UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
+			if (amount > freeMem)
+				allocBlock(amount);
+
+			UINT8* data = mFreeBlock->alloc(amount);
+
+#if BS_DEBUG_MODE
+			mTotalAllocBytes += amount;
+
+			UINT32* storedSize = reinterpret_cast<UINT32*>(data);
+			*storedSize = amount;
+
+			return data + sizeof(UINT32);
+#else
+			return data;
+#endif
+		}
+
+		/** Deallocates a previously allocated piece of memory. */
+		void free(void* data)
+		{
+			// Dealloc is only used for debug and can be removed if needed. All the actual deallocation
+			// happens in clear()
+
+#if BS_DEBUG_MODE
+			UINT8* dataPtr = (UINT8*)data;
+			dataPtr -= sizeof(UINT32);
+
+			UINT32* storedSize = (UINT32*)(dataPtr);
+			mTotalAllocBytes -= *storedSize;
+#endif
+		}
+
+		/** Frees the internal memory buffers. All external allocations must be freed before calling this. */
+		void clear()
+		{
+			assert(mTotalAllocBytes == 0);
+
+			MemBlock* dynamicBlock = mStaticBlock.mNextBlock;
+			INT32 totalDynamicMemAmount = 0;
+			UINT32 numDynamicBlocks = 0;
+
+			while (dynamicBlock != nullptr)
+			{
+				totalDynamicMemAmount += dynamicBlock->mFreePtr;
+				dynamicBlock->clear();
+			
+				dynamicBlock = dynamicBlock->mNextBlock;
+				numDynamicBlocks++;
+			}
+
+			mFreeBlock = &mStaticBlock;
+			mStaticBlock.clear();
+
+			if (numDynamicBlocks > 1)
+			{
+				freeBlocks(&mStaticBlock);
+				allocBlock(std::min(totalDynamicMemAmount, MaxDynamicMemory));
+				mFreeBlock = &mStaticBlock;
+			}
+			else if (numDynamicBlocks == 1 && MaxDynamicMemory == 0)
+			{
+				freeBlocks(&mStaticBlock);
+			}
+		}
+
+	private:
+		UINT8 mStaticData[BlockSize];
+		MemBlock mStaticBlock;
+
+		MemBlock* mFreeBlock;
+		UINT32 mTotalAllocBytes;
+
+		/**
+		 * Allocates a dynamic block of memory of the wanted size. The exact allocation size might be slightly higher in 
+		 * order to store block meta data.
+		 */
+		MemBlock* allocBlock(UINT32 wantedSize)
+		{
+			UINT32 blockSize = BlockSize;
+			if (wantedSize > blockSize)
+				blockSize = wantedSize;
+
+			MemBlock* dynamicBlock = mFreeBlock->mNextBlock;
+			MemBlock* newBlock = nullptr;
+			while (dynamicBlock != nullptr)
+			{
+				if (dynamicBlock->mSize >= blockSize)
+				{
+					newBlock = dynamicBlock;
+					break;
+				}
+
+				dynamicBlock = dynamicBlock->mNextBlock;
+			}
+
+			if (newBlock == nullptr)
+			{
+				UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc(blockSize + sizeof(MemBlock)));
+				newBlock = new (data)MemBlock(data + sizeof(MemBlock), blockSize);
+				newBlock->mPrevBlock = mFreeBlock;
+				mFreeBlock->mNextBlock = newBlock;
+			}
+
+			mFreeBlock = newBlock;
+			return newBlock;
+		}
+
+		/** Releases memory for any dynamic blocks following the provided block (if there are any). */
+		void freeBlocks(MemBlock* start)
+		{
+			MemBlock* dynamicBlock = start->mNextBlock;
+			while (dynamicBlock != nullptr)
+			{
+				MemBlock* nextBlock = dynamicBlock->mNextBlock;
+
+				dynamicBlock->~MemBlock();
+				bs_free(dynamicBlock);
+
+				dynamicBlock = nextBlock;
+			}
+
+			start->mNextBlock = nullptr;
+		}
+	};
+
+	/** @} */
+	/** @endcond */
 }

+ 108 - 111
BansheeUtility/Include/BsTexAtlasGenerator.h

@@ -1,112 +1,109 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsVector2.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Represents a single element used as in input to
-	 * 			TexAtlasGenerator. Usually represents a single texture.
-	 * 			
-	 * @note	"input" is required to be filled in before passing it to
-	 * 			TexAtlasGenerator.
-	 * 			"output" will be filled in by TexAtlasGenerator after a call to
-	 * 			TexAtlasGenerator::createAtlasLayout
-	 */
-	struct TexAtlasElementDesc
-	{
-		struct
-		{
-			UINT32 width, height;
-		} input;
-		
-		struct
-		{
-			UINT32 x, y;
-			INT32 page;
-		} output;
-	};
-
-	/**
-	 * @brief	A single page of the texture atlas.
-	 */
-	struct TexAtlasPageDesc
-	{
-		UINT32 width, height;
-	};
-
-	class TexAtlasNode;
-
-	/**
-	 * @brief	Organizes a set of textures into a single larger texture (an atlas) by minimizing empty space.
-	 */
-	class BS_UTILITY_EXPORT TexAtlasGenerator
-	{
-	public:
-		/**
-		 * @brief	Constructs a new texture atlas generator with the provided parameters.
-		 *
-		 * @param	square			(optional) Should the returned texture always be square. (width == height)
-		 * 							This option is only used if "fixedSize" parameter is set to false.
-		 * @param	maxTexWidth 	(optional) Maximum width of the texture. 
-		 * @param	maxTexHeight	(optional) Maximum height of the texture. 
-		 * @param	fixedSize   	(optional) If this field is false, algorithm will try to reduce the size of the texture
-		 * 							if possible. If it is true, the algorithm will always produce textures of the specified
-		 * 							"maxTexWidth", "maxTexHeight" size.
-		 */
-		TexAtlasGenerator(bool square = false, UINT32 maxTexWidth = 2048, UINT32 maxTexHeight = 2048, bool fixedSize = false);
-
-		/**
-		 * @brief	Creates an optimal texture layout by packing texture elements in order to end up with
-		 * 			as little empty space as possible.
-		 *
-		 * @param	elements	Elements to process. They need to have their "input" structures filled in,
-		 * 						and this method will fill "output" when it returns.
-		 * 						
-		 * @note	Algorithm will split elements over multiple textures if they don't fit
-		 * 						in a single texture (Determined by maximum texture size)
-		 *
-		 * @return	One or more descriptors that determine the size of the final atlas textures. Texture elements
-		 * 			will reference these pages with their "output.page" parameter.
-		 */
-		Vector<TexAtlasPageDesc> createAtlasLayout(Vector<TexAtlasElementDesc>& elements) const;
-
-	private:
-		bool mSquare;
-		bool mFixedSize;
-		UINT32 mMaxTexWidth;
-		UINT32 mMaxTexHeight;
-
-		/**
-		 * @brief	Organize all of the provide elements and place them into minimum number of pages with the specified width and height.
-		 * 			
-		 * 			Caller must ensure "elements" array has the page indexes reset to -1 before calling, otherwise it will be assumed
-		 * 			those elements already have assigned pages.
-		 * 			
-		 *			Using "startPage" parameter you may add an offset to the generated page indexes.
-		 *
-		 * @return	Number of pages generated.
-		 */
-		int generatePagesForSize(Vector<TexAtlasElementDesc>& elements, UINT32 width, UINT32 height, UINT32 startPage = 0) const;
-
-		/**
-		 * @brief	Finds the largest element without a page that fits within the provided node.
-		 *
-		 * @return	Array index of the found page, or -1 if all textures have a page.
-		 */
-		int addLargestTextureWithoutPageThatFits(Vector<TexAtlasElementDesc>& elements, TexAtlasNode& node) const;
-
-		/**
-		 * @brief	Scan all of the provided elements and find the largest one that still doesn't have a page assigned.
-		 * 			
-		 * @return	Array index of the found page, or -1 if all textures have a page.
-		 */
-		int findLargestTextureWithoutPage(const Vector<TexAtlasElementDesc>& elements) const;
-
-		/**
-		 * @brief	Sorts all the texture elements so that larget elements come first.
-		 */
-		void sortBySize(Vector<TexAtlasElementDesc>& elements) const;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsVector2.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Image
+	 *  @{
+	 */
+
+	/**
+	 * Represents a single element used as in input to TexAtlasGenerator. Usually represents a single texture.
+	 * 			
+	 * @note	input is required to be filled in before passing it to TexAtlasGenerator.
+	 * @note	output will be filled in by TexAtlasGenerator after a call to TexAtlasGenerator::createAtlasLayout().
+	 */
+	struct TexAtlasElementDesc
+	{
+		struct
+		{
+			UINT32 width, height;
+		} input;
+		
+		struct
+		{
+			UINT32 x, y;
+			INT32 page;
+		} output;
+	};
+
+	/** A single page of the texture atlas. */
+	struct TexAtlasPageDesc
+	{
+		UINT32 width, height;
+	};
+
+	class TexAtlasNode;
+
+	/** Organizes a set of textures into a single larger texture (an atlas) by minimizing empty space. */
+	class BS_UTILITY_EXPORT TexAtlasGenerator
+	{
+	public:
+		/**
+		 * Constructs a new texture atlas generator with the provided parameters.
+		 *
+		 * @param[in]	square			(optional) Should the returned texture always be square. (width == height)
+		 * 								This option is only used if @p fixedSize parameter is set to false.
+		 * @param[in]	maxTexWidth 	(optional) Maximum width of the texture. 
+		 * @param[in]	maxTexHeight	(optional) Maximum height of the texture. 
+		 * @param[in]	fixedSize   	(optional) If this field is false, algorithm will try to reduce the size of the texture
+		 * 								if possible. If it is true, the algorithm will always produce textures of the specified
+		 * 								@p maxTexWidth, @p maxTexHeight size.
+		 */
+		TexAtlasGenerator(bool square = false, UINT32 maxTexWidth = 2048, UINT32 maxTexHeight = 2048, bool fixedSize = false);
+
+		/**
+		 * Creates an optimal texture layout by packing texture elements in order to end up with as little empty space 
+		 * as possible.
+		 *
+		 * @param[in]	elements	Elements to process. They need to have their input structures filled in,
+		 * 							and this method will fill output when it returns.
+		 * @return					One or more descriptors that determine the size of the final atlas textures. 
+		 *							Texture elements will reference these pages with their output.page parameter.
+		 *
+		 * @note	
+		 * Algorithm will split elements over multiple textures if they don't fit in a single texture (Determined by 
+		 * maximum texture size).
+		 */
+		Vector<TexAtlasPageDesc> createAtlasLayout(Vector<TexAtlasElementDesc>& elements) const;
+
+	private:
+		bool mSquare;
+		bool mFixedSize;
+		UINT32 mMaxTexWidth;
+		UINT32 mMaxTexHeight;
+
+		/**
+		 * Organize all of the provide elements and place them into minimum number of pages with the specified width and height.
+		 * 			
+		 * Caller must ensure @p elements array has the page indexes reset to -1 before calling, otherwise it will be assumed
+		 * those elements already have assigned pages.
+		 * 			
+		 * Using @p startPage parameter you may add an offset to the generated page indexes.
+		 *
+		 * @return	Number of pages generated.
+		 */
+		int generatePagesForSize(Vector<TexAtlasElementDesc>& elements, UINT32 width, UINT32 height, UINT32 startPage = 0) const;
+
+		/**
+		 * Finds the largest element without a page that fits within the provided node.
+		 *
+		 * @return	Array index of the found page, or -1 if all textures have a page.
+		 */
+		int addLargestTextureWithoutPageThatFits(Vector<TexAtlasElementDesc>& elements, TexAtlasNode& node) const;
+
+		/**
+		 * Scan all of the provided elements and find the largest one that still doesn't have a page assigned.
+		 * 			
+		 * @return	Array index of the found page, or -1 if all textures have a page.
+		 */
+		int findLargestTextureWithoutPage(const Vector<TexAtlasElementDesc>& elements) const;
+
+		/** Sorts all the texture elements so that larget elements come first. */
+		void sortBySize(Vector<TexAtlasElementDesc>& elements) const;
+	};
+
+	/** @endcond */
 }

+ 92 - 94
BansheeUtility/Include/BsTime.h

@@ -1,95 +1,93 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsModule.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Manages all time related functionality.
-	 * 			
-	 * @note	Sim thread only unless where specified otherwise.
-	 */
-	class BS_UTILITY_EXPORT Time : public Module<Time>
-	{
-	public:
-		Time();
-		~Time();
-
-		/**
-		 * @brief	Gets the time elapsed since application start.
-		 * 			Only gets updated once per frame.
-		 *
-		 * @return	The time since application start, in seconds.
-		 */
-		float getTime() const { return mTimeSinceStart; }
-
-		/**
-		 * @brief	Gets the time elapsed since application start.
-		 * 			Only gets updated once per frame.
-		 *
-		 * @return	The time since application start, in miliseconds.
-		 */
-		UINT64 getTimeMs() const { return mTimeSinceStartMs; }
-
-		/**
-		 * @brief	Gets the time since last frame was executed.
-		 * 			Only gets updated once per frame.
-		 *
-		 * @return	Time since last frame was executed, in seconds.
-		 */
-		float getFrameDelta() const { return mFrameDelta; }
-
-		/**
-		 * @brief	Returns the sequential index of the current frame. First frame is 0.
-		 *
-		 * @return	The current frame.
-		 *
-		 * @note	Thread safe, but only counts sim thread frames.
-		 */
-		UINT64 getFrameIdx() const { return mCurrentFrame.load(); }
-
-		/**
-		 * @brief	Returns the precise time since application start, in microseconds.
-		 * 			Unlike other time methods this is not only updated every frame,
-		 * 			but will return exact time at the moment it is called.
-		 * 			
-		 * @note	You will generally only want to use this for performance measurements and similar.
-		 * 			Use non-precise methods in majority of code as it is useful to keep the time value equal
-		 * 			in all methods during a single frame.
-		 *
-		 * @return	Time in microseconds.
-		 */
-		UINT64 getTimePrecise() const;
-
-		/**
-		 * @brief	Gets the time at which the application was started, counting
-		 * 			from system start.
-		 *
-		 * @return	The time since system to application start, in milliseconds.
-		 */
-		UINT64 getStartTimeMs() const { return mAppStartTime; }
-
-		/**
-		 * @brief	Called every frame. Should only be called by Application.
-		 */
-		void update();
-
-		/**
-		 * @brief	Multiply with time in microseconds to get a time in seconds.
-		 */
-		static const double MICROSEC_TO_SEC;
-	private:
-		float mFrameDelta; /**< Frame delta in seconds */
-		float mTimeSinceStart; /**< Time since start in seconds */
-		UINT64 mTimeSinceStartMs;
-
-		UINT64 mAppStartTime; /**< Time the application started, in microseconds */
-		unsigned long mLastFrameTime; /**< Time since last runOneFrame call, In microseconds */
-		std::atomic<unsigned long> mCurrentFrame;
-
-		Timer* mTimer;
-	};
-
-	BS_UTILITY_EXPORT Time& gTime();
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/**
+	 * Manages all time related functionality.
+	 * 			
+	 * @note	Sim thread only unless where specified otherwise.
+	 */
+	class BS_UTILITY_EXPORT Time : public Module<Time>
+	{
+	public:
+		Time();
+		~Time();
+
+		/**
+		 * Gets the time elapsed since application start. Only gets updated once per frame.
+		 *
+		 * @return	The time since application start, in seconds.
+		 */
+		float getTime() const { return mTimeSinceStart; }
+
+		/**
+		 * Gets the time elapsed since application start. Only gets updated once per frame.
+		 *
+		 * @return	The time since application start, in miliseconds.
+		 */
+		UINT64 getTimeMs() const { return mTimeSinceStartMs; }
+
+		/**
+		 * Gets the time since last frame was executed. Only gets updated once per frame.
+		 *
+		 * @return	Time since last frame was executed, in seconds.
+		 */
+		float getFrameDelta() const { return mFrameDelta; }
+
+		/**
+		 * Returns the sequential index of the current frame. First frame is 0.
+		 *
+		 * @return	The current frame.
+		 *
+		 * @note	Thread safe, but only counts sim thread frames.
+		 */
+		UINT64 getFrameIdx() const { return mCurrentFrame.load(); }
+
+		/**
+		 * Returns the precise time since application start, in microseconds. Unlike other time methods this is not only 
+		 * updated every frame, but will return exact time at the moment it is called.
+		 * 		
+		 * @return	Time in microseconds.
+		 *
+		 * @note	
+		 * You will generally only want to use this for performance measurements and similar. Use non-precise methods in 
+		 * majority of code as it is useful to keep the time value equal in all methods during a single frame.
+		 */
+		UINT64 getTimePrecise() const;
+
+		/**
+		 * Gets the time at which the application was started, counting from system start.
+		 *
+		 * @return	The time since system to application start, in milliseconds.
+		 */
+		UINT64 getStartTimeMs() const { return mAppStartTime; }
+
+		/** Called every frame. Should only be called by Application. */
+		void update();
+
+		/** Multiply with time in microseconds to get a time in seconds. */
+		static const double MICROSEC_TO_SEC;
+	private:
+		float mFrameDelta; /**< Frame delta in seconds */
+		float mTimeSinceStart; /**< Time since start in seconds */
+		UINT64 mTimeSinceStartMs;
+
+		UINT64 mAppStartTime; /**< Time the application started, in microseconds */
+		unsigned long mLastFrameTime; /**< Time since last runOneFrame call, In microseconds */
+		std::atomic<unsigned long> mCurrentFrame;
+
+		Timer* mTimer;
+	};
+
+	/** Easier way to access the Time module. */
+	BS_UTILITY_EXPORT Time& gTime();
+
+	/** @} */
 }

+ 51 - 61
BansheeUtility/Include/BsTimer.h

@@ -1,61 +1,51 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Timer class used for querying high precision timers.
-	 *
-	 * @note	Not thread safe.
-	 */
-	class BS_UTILITY_EXPORT Timer
-    {
-    public:
-		/**
-		 * @brief	Construct the timer and start timing.
-		 */
-		Timer();
-		~Timer();
-
-		/**
-		 * @brief	Reset the timer to zero.
-		 */
-		void reset();
-
-		/**
-		 * @brief	Returns time in milliseconds since timer was initialized or
-		 * 			last reset.
-		 */
-		unsigned long getMilliseconds();
-
-		/**
-		 * @brief	Returns time in microseconds since timer was initialized or
-		 * 			last reset.
-		 */
-		unsigned long getMicroseconds();
-
-		/**
-		 * @brief	Returns time in milliseconds since timer was initialized or
-		 * 			last reset. Only CPU timer measured.
-		 */
-		unsigned long getMillisecondsCPU();
-
-		/**
-		 * @brief	Returns time in microseconds since timer was initialized or
-		 * 			last reset. Only CPU timer measured.
-		 */
-		unsigned long getMicrosecondsCPU();
-
-		/**
-		 * @brief	Returns the time at which the timer was initialized, in milliseconds.
-		 *
-		 * @return	Time in milliseconds.
-		 */
-		unsigned long getStartMs() const;
-
-	private:
-		struct Data;
-		Data* m;
-    };
-}
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/**
+	 * Timer class used for querying high precision timers.
+	 *
+	 * @note	Not thread safe.
+	 */
+	class BS_UTILITY_EXPORT Timer
+    {
+    public:
+		/** Construct the timer and start timing. */
+		Timer();
+		~Timer();
+
+		/** Reset the timer to zero. */
+		void reset();
+
+		/** Returns time in milliseconds since timer was initialized or last reset. */
+		unsigned long getMilliseconds();
+
+		/** Returns time in microseconds since timer was initialized or last reset. */
+		unsigned long getMicroseconds();
+
+		/** Returns time in milliseconds since timer was initialized or last reset. Only CPU timer measured. */
+		unsigned long getMillisecondsCPU();
+
+		/** Returns time in microseconds since timer was initialized or last reset. Only CPU timer measured. */
+		unsigned long getMicrosecondsCPU();
+
+		/**
+		 * Returns the time at which the timer was initialized, in milliseconds.
+		 *
+		 * @return	Time in milliseconds.
+		 */
+		unsigned long getStartMs() const;
+
+	private:
+		struct Data;
+		Data* m;
+    };
+
+	/** @} */
+}

+ 23 - 24
BansheeUtility/Include/BsUtil.h

@@ -1,25 +1,24 @@
-#pragma once
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Generates a new hash for the provided type using the default standard
-	 * 			hasher and combines it with a previous hash.
-	 */
-	template <class T>
-	inline void hash_combine(std::size_t& seed, const T& v)
-	{
-		std::hash<T> hasher;
-		seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
-	}
-
-	/**
-	 * @brief	Generates an MD5 hash string for the provided source string.
-	 */
-	String BS_UTILITY_EXPORT md5(const WString& source);
-
-	/**
-	 * @brief	Generates an MD5 hash string for the provided source string.
-	 */
-	String BS_UTILITY_EXPORT md5(const String& source);
+#pragma once
+
+namespace BansheeEngine
+{
+	/** @addtogroup General
+	 *  @{
+	 */
+
+	/** Generates a new hash for the provided type using the default standard hasher and combines it with a previous hash. */
+	template <class T>
+	inline void hash_combine(std::size_t& seed, const T& v)
+	{
+		std::hash<T> hasher;
+		seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+	}
+
+	/** Generates an MD5 hash string for the provided source string. */
+	String BS_UTILITY_EXPORT md5(const WString& source);
+
+	/**	Generates an MD5 hash string for the provided source string. */
+	String BS_UTILITY_EXPORT md5(const String& source);
+
+	/** @} */
 }