Просмотр исходного кода

WIP better material parameter caching

BearishSun 10 лет назад
Родитель
Сommit
0134c9aaaf

+ 2 - 0
BansheeCore/BansheeCore.vcxproj

@@ -299,6 +299,7 @@
     <ClInclude Include="Include\BsCoreObjectCore.h" />
     <ClInclude Include="Include\BsHString.h" />
     <ClInclude Include="Include\BsIconUtility.h" />
+    <ClInclude Include="Include\BsMaterialParams.h" />
     <ClInclude Include="Include\BsMeshImportOptions.h" />
     <ClInclude Include="Include\BsMeshImportOptionsRTTI.h" />
     <ClInclude Include="Include\BsMeshUtility.h" />
@@ -567,6 +568,7 @@
     <ClCompile Include="Source\BsViewport.cpp" />
     <ClCompile Include="Source\BsSceneObject.cpp" />
     <ClCompile Include="Source\BsComponent.cpp" />
+    <ClCompile Include="Source\BsMaterialParams.cpp" />
     <ClCompile Include="Source\Win32\BsWin32Platform.cpp" />
     <ClCompile Include="Source\Win32\BsWin32FolderMonitor.cpp" />
     <ClCompile Include="Source\Win32\BsWin32Window.cpp" />

+ 6 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -587,6 +587,9 @@
     <ClInclude Include="Include\BsPixelVolume.h">
       <Filter>Header Files\Utility</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsMaterialParams.h">
+      <Filter>Header Files\Material</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -919,5 +922,8 @@
     <ClCompile Include="Source\BsPixelUtil.cpp">
       <Filter>Source Files\Utility</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsMaterialParams.cpp">
+      <Filter>Source Files\Material</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 464 - 464
BansheeCore/Include/BsCommonTypes.h

@@ -1,465 +1,465 @@
-#pragma once
-
-namespace BansheeEngine 
-{
-	/**
-	 * @brief	Factors used when blending new pixels with existing pixels.
-	 */
-    enum BlendFactor
-    {
-		BF_ONE, /**< Use a value of one for all pixel components. */
-		BF_ZERO, /**< Use a value of zero for all pixel components. */
-		BF_DEST_COLOR, /**< Use the existing pixel value. */
-		BF_SOURCE_COLOR, /**< Use the newly generated pixel value. */
-		BF_INV_DEST_COLOR, /**< Use the inverse of the existing value. */
-		BF_INV_SOURCE_COLOR, /**< Use the inverse of the newly generated pixel value. */
-		BF_DEST_ALPHA, /**< Use the existing alpha value. */
-		BF_SOURCE_ALPHA, /**< Use the newly generated alpha value. */
-		BF_INV_DEST_ALPHA, /**< Use the inverse of the existing alpha value. */
-		BF_INV_SOURCE_ALPHA /**< Use the inverse of the newly generated alpha value. */
-    };
-
-	/**
-	 * @brief	Operations that determines how are blending factors combined.
-	 */
-	enum BlendOperation
-	{
-		BO_ADD, /**< Blend factors are added together. */
-		BO_SUBTRACT, /**< Blend factors are subtracted in "srcFactor - dstFactor" order. */
-		BO_REVERSE_SUBTRACT, /**< Blend factors are subtracted in "dstFactor - srcFactor" order. */
-		BO_MIN, /**< Minimum of the two factors is chosen. */
-		BO_MAX /**< Maximum of the two factors is chosen. */
-	};
-
-	/**
-	 * @brief	Comparison functions used for the depth/stencil buffer.
-	 */
-    enum CompareFunction
-    {
-		CMPF_ALWAYS_FAIL, /**< Operation will always fail. */
-		CMPF_ALWAYS_PASS, /**< Operation will always pass. */
-		CMPF_LESS, /**< Operation will pass if the new value is less than existing value. */
-        CMPF_LESS_EQUAL, /**< Operation will pass if the new value is less or equal than existing value. */
-        CMPF_EQUAL, /**< Operation will pass if the new value is equal to the existing value. */
-        CMPF_NOT_EQUAL, /**< Operation will pass if the new value is not equal to the existing value. */
-        CMPF_GREATER_EQUAL, /**< Operation will pass if the new value greater or equal than the existing value. */
-        CMPF_GREATER /**< Operation will pass if the new value greater than the existing value. */
-    };
-
-	/**
-	 * @brief	Types of texture addressing modes that determine what happens when texture
-	 *			coordinates are outside of the valid range.
-	 */
-    enum TextureAddressingMode
-    {
-		TAM_WRAP, /**< Coordinates wrap back to the valid range. */
-		TAM_MIRROR, /**< Coordinates flip every time the size of the valid range is passed. */
-		TAM_CLAMP, /**< Coordinates are clamped within the valid range. */
-		TAM_BORDER /**< Coordinates outside of the valid range will return a separately set border color. */
-    };
-
-	/**
-	 * @brief	Types of available filtering situations.
-	 */
-    enum FilterType
-    {
-		FT_MIN, /**< The filter used when shrinking a texture. */
-        FT_MAG, /**< The filter used when magnifying a texture. */
-        FT_MIP /**< The filter used when filtering between mipmaps. */
-    };
-
-	/**
-	 * @brief	Filtering options for textures.
-	 */
-    enum FilterOptions
-    {
-		FO_NONE = 0, /**< Use no filtering. Only relevant for mipmap filtering. */
-		FO_POINT = 1, /**< Filter using the nearest found pixel. Most basic filtering. */
-		FO_LINEAR = 2, /**< Average a 2x2 pixel area, signifies bilinear filtering for texture, trilinear for mipmaps. */
-		FO_ANISOTROPIC = 3, /**< More advanced filtering that improves quality when viewing textures at a steep angle */
-		FO_USE_COMPARISON = 4 /**< Specifies that the sampled values will be compared against existing sampled data. Should be OR-ed with other filtering options. */
-    };
-
-	/**
-	 * @brief	Types of frame buffers.
-	 */
-	enum FrameBufferType
-	{
-		FBT_COLOR = 0x1,
-		FBT_DEPTH = 0x2,
-		FBT_STENCIL = 0x4
-	};
-
-	/**
-	 * @brief	Types of culling that determine how (and if) hardware discards faces with certain
-	 *			winding order. Winding order can be used for determining front or back facing polygons by
-	 *			checking the order of its vertices from the render perspective.
-	 */
-    enum CullingMode
-    {
-		CULL_NONE = 0, /**< Hardware performs no culling and renders both sides. */
-		CULL_CLOCKWISE = 1, /**< Hardware culls faces that have a clockwise vertex ordering. */
-        CULL_COUNTERCLOCKWISE = 2 /**< Hardware culls faces that have a counter-clockwise vertex ordering. */
-    };
-
-	/**
-	 * @brief	Polygon mode to use when rasterizing.
-	 */
-    enum PolygonMode
-    {
-		PM_WIREFRAME = 1, /**< Render as wireframe showing only polygon outlines. */
-        PM_SOLID = 2 /**< Render as solid showing whole polygons. */
-    };
-
-	/**
-	 * @brief	Types of action that can happen on the stencil buffer.
-	 */
-	enum StencilOperation
-	{
-		SOP_KEEP, /**< Leave the stencil buffer unchanged. */
-		SOP_ZERO, /**< Set the stencil value to zero. */
-		SOP_REPLACE, /**< Replace the stencil value with the reference value. */
-		SOP_INCREMENT, /**< Increase the stencil value by 1, clamping at the maximum value. */
-		SOP_DECREMENT, /**< Decrease the stencil value by 1, clamping at 0. */
-		SOP_INCREMENT_WRAP, /**< Increase the stencil value by 1, wrapping back to 0 when incrementing past the maximum value. */
-		SOP_DECREMENT_WRAP, /**< Decrease the stencil value by 1, wrapping when decrementing 0. */
-		SOP_INVERT /**< Invert the bits of the stencil buffer. */
-	};
-
-	/**
-	* @brief	These values represent a hint to the driver when locking a hardware buffer.
-	*
-	*			GBL_WRITE_ONLY - Allows you to write to the buffer. Can cause a CPU-GPU sync point
-	*			so avoid using it often (i.e. every frame) as that might limit your performance significantly.
-	*			GBL_WRITE_ONLY_DISCARD - Allows you to write to the buffer. Tells the driver to completely discard the contents of the 
-	*			buffer you are writing to. The driver will (most likely) internally allocate another buffer with same specifications 
-	*			(which is fairly fast) and you will avoid CPU-GPU stalls.
-	*			GBL_WRITE_ONLY_NO_OVERWRITE - Allows you to write to the buffer. Guarantees the driver that you will not be updating any part of 
-	*			the buffer that is currently used. This will also avoid CPU-GPU stalls, without requiring you to discard the entire buffer. However 
-	*			it is hard to guarantee when GPU has finished using a buffer.
-	*			GBL_READ_ONLY - Allows you to read from a buffer. Be aware that reading is usually a very slow operation.
-	*			GBL_READ_WRITE - Allows you to both read and write to a buffer. 
-	*/
-	enum GpuLockOptions
-	{
-        GBL_READ_WRITE,
-		GBL_WRITE_ONLY_DISCARD,
-		GBL_READ_ONLY,
-        GBL_WRITE_ONLY_NO_OVERWRITE,
-		GBL_WRITE_ONLY	
-	};
-
-	/**
-	 * @brief	Values that represent hardware buffer usage. These usually determine in what
-	 *			type of memory is buffer placed in, however that depends on rendering API.
-	 * 
-	 *			GBU_STATIC - Signifies that you don't plan on modifying the buffer often (or at all)
-	 *			after creation. Modifying such buffer will involve a larger performance hit.
-	 *			GBU_DYNAMIC - Signifies that you will modify this buffer fairly often.
-	 */
-	enum GpuBufferUsage 
-	{
-        GBU_STATIC = 1,
-		GBU_DYNAMIC = 2
-	};
-
-	/**
-	 * @brief	Types of generic GPU buffers that may be attached to GPU programs.
-	 *
-	 *			GBT_STRUCTURED - Buffer containing an array of structures. Structure parameters
-	 *			can usually be easily accessed from within the GPU program.
-	 *			GBT_RAW - Buffer containing raw bytes. It is up to the user to interpret the data.
-	 *			GBT_INDIRECTARGUMENT - Special type of buffer allowing you to specify arguments for
-	 *			draw operations inside the buffer instead of providing them directly. Useful when you want
-	 *			to control drawing directly from GPU.
-	 *			GBT_APPENDCONSUME - A stack-like buffer that allows you to add or remove elements to/from the buffer
-	 *			from within the GPU program.
-	 */
-	enum GpuBufferType
-	{
-		GBT_STRUCTURED,
-		GBT_RAW,
-		GBT_INDIRECTARGUMENT,
-		GBT_APPENDCONSUME
-	};
-
-	/**
-	 * @brief	Different types of GPU views that control how GPU sees a hardware buffer.
-	 *
-	 *			GVU_DEFAULT - Buffer is seen as a default shader resource, used primarily for reading. (e.g. a texture for sampling)
-	 *			GVU_RENDERTARGET - Buffer is seen as a render target that color pixels will be written to after pixel shader stage.
-	 *			GVU_DEPTHSTENCIL - Buffer is seen as a depth stencil target that depth and stencil information is written to.
-	 *			GVU_RANDOMWRITE - Buffer that allows you to write to any part of it from within a GPU program.
-	 */
-	enum GpuViewUsage
-	{
-		GVU_DEFAULT = 0x01,
-		GVU_RENDERTARGET = 0x02,
-		GVU_DEPTHSTENCIL = 0x04,
-		GVU_RANDOMWRITE = 0x08
-	};
-
-	/**
-	 * @brief	Type of parameter block usages. Signifies how often will parameter blocks be changed.
-	 *
-	 *			GPBU_STATIC - Buffer will be rarely, if ever, updated.
-	 *			GPBU_DYNAMIC - Buffer will be updated often (e.g. every frame).
-	 */
-	enum GpuParamBlockUsage
-	{
-		GPBU_STATIC,
-		GPBU_DYNAMIC
-	};
-
-	/**
-	 * @brief	Type of GPU parameter.
-	 *
-	 *			GPT_DATA - Raw data type like float, Vector3, Color, etc.
-	 *			GPT_OBJECT - Reference to some GPU object like Texture, Sampler, etc.
-	 */
-	enum GpuParamType
-	{
-		GPT_DATA,
-		GPT_TEXTURE,
-		GPT_BUFFER,
-		GPT_SAMPLER
-	};
-
-	/**
-	 * @brief	Type of GPU data parameters that can be used as inputs to a GPU program.
-	 */
-	enum GpuParamDataType
-	{
-		GPDT_FLOAT1 = 1,
-		GPDT_FLOAT2 = 2,
-		GPDT_FLOAT3 = 3,
-		GPDT_FLOAT4 = 4,
-		GPDT_MATRIX_2X2 = 11,
-		GPDT_MATRIX_2X3 = 12,
-		GPDT_MATRIX_2X4 = 13,
-		GPDT_MATRIX_3X2 = 14,
-		GPDT_MATRIX_3X3 = 15,
-		GPDT_MATRIX_3X4 = 16,
-		GPDT_MATRIX_4X2 = 17,
-		GPDT_MATRIX_4X3 = 18,
-		GPDT_MATRIX_4X4 = 19,
-		GPDT_INT1 = 20,
-		GPDT_INT2 = 21,
-		GPDT_INT3 = 22,
-		GPDT_INT4 = 23,
-		GPDT_BOOL = 24,
-		GPDT_STRUCT = 25,
-		GPDT_COLOR = 26, // Same as GPDT_FLOAT4, but can be used to better deduce usage
-		GPDT_COUNT = 27, // Keep at end before GPDT_UNKNOWN
-		GPDT_UNKNOWN = 0xffff
-	};
-
-	/**
-	 * @brief	Contains data about a type used for GPU data parameters.
-	 */
-	struct GpuParamDataTypeInfo
-	{
-		UINT32 baseTypeSize;
-		UINT32 size;
-		UINT32 alignment;
-		UINT32 numRows;
-		UINT32 numColumns;
-	};
-
-	/**
-	 * @brief	Contains a lookup table for various information of all types used for data GPU parameters. Sizes are in bytes.
-	 */
-	struct GpuDataParamInfos
-	{
-		GpuDataParamInfos()
-		{
-			memset(lookup, 0, sizeof(lookup));
-
-			lookup[(UINT32)GPDT_FLOAT1] = { 4, 4, 4, 1, 1 };
-			lookup[(UINT32)GPDT_FLOAT2] = { 4, 8, 8, 1, 2 };
-			lookup[(UINT32)GPDT_FLOAT3] = { 4, 16, 16, 1, 3 };
-			lookup[(UINT32)GPDT_FLOAT4] = { 4, 16, 16, 1, 4 };
-			lookup[(UINT32)GPDT_MATRIX_2X2] = { 4, 16, 8, 2, 2 };
-			lookup[(UINT32)GPDT_MATRIX_2X3] = { 4, 32, 16, 2, 3 };
-			lookup[(UINT32)GPDT_MATRIX_2X4] = { 4, 32, 16, 2, 4 };
-			lookup[(UINT32)GPDT_MATRIX_3X2] = { 4, 24, 8, 3, 2 };
-			lookup[(UINT32)GPDT_MATRIX_3X3] = { 4, 48, 16, 3, 3 };
-			lookup[(UINT32)GPDT_MATRIX_3X4] = { 4, 48, 16, 3, 4 };
-			lookup[(UINT32)GPDT_MATRIX_4X2] = { 4, 32, 8, 4, 2 };
-			lookup[(UINT32)GPDT_MATRIX_4X3] = { 4, 64, 16, 4, 3 };
-			lookup[(UINT32)GPDT_MATRIX_4X4] = { 4, 64, 16, 4, 4 };
-			lookup[(UINT32)GPDT_INT1] = { 4, 4, 4, 1, 1 };
-			lookup[(UINT32)GPDT_INT2] = { 4, 8, 8, 1, 2 };
-			lookup[(UINT32)GPDT_INT3] = { 4, 12, 16, 1, 3 };
-			lookup[(UINT32)GPDT_INT4] = { 4, 16, 16, 1, 4 };
-			lookup[(UINT32)GPDT_BOOL] = { 4, 4, 4, 1, 1 };
-		}
-
-		GpuParamDataTypeInfo lookup[GPDT_COUNT];
-	};
-
-	/**
-	 * @brief	Type of GPU object parameters that can be used as inputs to a GPU program.
-	 */
-	enum GpuParamObjectType
-	{
-		GPOT_SAMPLER1D = 1,
-		GPOT_SAMPLER2D = 2,
-		GPOT_SAMPLER3D = 3,
-		GPOT_SAMPLERCUBE = 4,
-		GPOT_SAMPLER2DMS = 5,
-		GPOT_TEXTURE1D = 11,
-		GPOT_TEXTURE2D = 12,
-		GPOT_TEXTURE3D = 13,
-		GPOT_TEXTURECUBE = 14,
-		GPOT_TEXTURE2DMS = 15,
-		GPOT_BYTE_BUFFER = 32,
-		GPOT_STRUCTURED_BUFFER = 33,
-		GPOT_RWTYPED_BUFFER = 41,
-		GPOT_RWBYTE_BUFFER = 42,
-		GPOT_RWSTRUCTURED_BUFFER = 43,
-		GPOT_RWSTRUCTURED_BUFFER_WITH_COUNTER = 44,
-		GPOT_RWAPPEND_BUFFER = 45,
-		GPOT_RWCONSUME_BUFFER = 46,
-		GPOT_UNKNOWN = 0xffff
-	};
-
-	/**
-	 * @brief	These values represent a hint to the driver when writing
-	 * 			to a GPU buffer.
-	 * 			
-	 *			Normal - Default flag with least restrictions. Can cause a CPU-GPU sync point
-	 *			so avoid using it often (i.e. every frame) as that might limit your performance significantly.
-	 *			Discard - Tells the driver to completely discard the contents of the buffer you are writing
-	 *			to. The driver will (most likely) internally allocate another buffer with same specifications (which is fairly fast)
-	 *			and you will avoid CPU-GPU stalls. 
-	 *			NoOverwrite - Guarantees the driver that you will not be updating any part of the buffer that is currently used.
-	 *			This will also avoid CPU-GPU stalls, without requiring you to discard the entire buffer. However it is hard to
-	 *			guarantee when GPU has finished using a buffer.
-	 */
-	enum class BufferWriteType
-	{
-		Normal,
-		Discard,
-		NoOverwrite
-	};
-
-	/**
-	 * @brief	Suggested queue priority numbers used for sorting objects in
-	 *			the render queue. Objects with higher priority will be renderer sooner.
-	 */
-	enum class QueuePriority
-	{
-		Opaque = 100000,
-		Transparent = 90000,
-		Skybox = 80000,
-		Overlay = 70000
-	};
-
-	/**
-	 * @brief	Type of sorting to perform on an object when added to a render queue.
-	 */
-	enum class QueueSortType
-	{
-		FrontToBack, /**< All objects with the same priority will be rendered front to back based on their center. */
-		BackToFront, /**< All objects with the same priority will be rendered back to front based on their center. */
-		None /**< Objects will not be sorted and will be processed in the order they were added to the queue. */
-	};
-
-	/**
-	 * @brief	Flags that may be assigned to a shader that let the renderer know how to interpret
-	 *			the shader.
-	 */
-	enum class ShaderFlags
-	{
-		Transparent = 0x1 /**< Signifies that the shader is rendering a transparent object. */
-	};
-
-	/**
-	 * @brief	Enum that defines possible window border styles.
-	 */
-	enum class WindowBorder
-	{
-		Normal,
-		None,
-		Fixed
-	};
-
-	/**
-	 * @brief	Texture addressing mode, per component.
-	 */
-	struct UVWAddressingMode
-	{
-		UVWAddressingMode()
-			:u(TAM_WRAP), v(TAM_WRAP), w(TAM_WRAP)
-		{ }
-
-		bool operator==(const UVWAddressingMode& rhs) const
-		{
-			return u == rhs.u && v == rhs.v && w == rhs.w;
-		}
-
-		TextureAddressingMode u, v, w;
-	};
-    
-	/**
-	 * @brief	References a subset of surfaces within a texture
-	 */
-	struct TextureSurface
-	{
-		TextureSurface(UINT32 mipLevel = 0, UINT32 numMipLevels = 1, 
-			UINT32 arraySlice = 0, UINT32 numArraySlices = 1)
-			:mipLevel(mipLevel), numMipLevels(numMipLevels), 
-			arraySlice(arraySlice), numArraySlices(numArraySlices)
-		{ }
-
-		UINT32 mipLevel;
-		UINT32 numMipLevels;
-		UINT32 arraySlice;
-		UINT32 numArraySlices;
-	};
-
-	/**
-	 * @brief	Helper class for syncing dirty data from sim CoreObject to
-	 *			core CoreObject and other way around.
-	 */
-	class CoreSyncData
-	{
-	public:
-		CoreSyncData()
-			:data(nullptr), size(0)
-		{ }
-
-		CoreSyncData(UINT8* data, UINT32 size)
-			:data(data), size(size)
-		{ }
-
-		/**
-		 * @brief	Gets the internal data and checks the data is of
-		 *			valid size.
-		 */
-		template<class T>
-		const T& getData() const
-		{
-			assert(sizeof(T) == size);
-
-			return *(T*)data;
-		}
-
-		/**
-		 * @brief	Returns a pointer to internal data buffer.
-		 */
-		UINT8* getBuffer() const { return data; }
-
-		/**
-		 * @brief	Returns the size of the internal data buffer.
-		 */
-		UINT32 getBufferSize() const { return size; }
-
-	private:
-		UINT8* data;
-		UINT32 size;
-	};
-
-	typedef Map<String, String> NameValuePairList;
+#pragma once
+
+namespace BansheeEngine 
+{
+	/**
+	 * @brief	Factors used when blending new pixels with existing pixels.
+	 */
+    enum BlendFactor
+    {
+		BF_ONE, /**< Use a value of one for all pixel components. */
+		BF_ZERO, /**< Use a value of zero for all pixel components. */
+		BF_DEST_COLOR, /**< Use the existing pixel value. */
+		BF_SOURCE_COLOR, /**< Use the newly generated pixel value. */
+		BF_INV_DEST_COLOR, /**< Use the inverse of the existing value. */
+		BF_INV_SOURCE_COLOR, /**< Use the inverse of the newly generated pixel value. */
+		BF_DEST_ALPHA, /**< Use the existing alpha value. */
+		BF_SOURCE_ALPHA, /**< Use the newly generated alpha value. */
+		BF_INV_DEST_ALPHA, /**< Use the inverse of the existing alpha value. */
+		BF_INV_SOURCE_ALPHA /**< Use the inverse of the newly generated alpha value. */
+    };
+
+	/**
+	 * @brief	Operations that determines how are blending factors combined.
+	 */
+	enum BlendOperation
+	{
+		BO_ADD, /**< Blend factors are added together. */
+		BO_SUBTRACT, /**< Blend factors are subtracted in "srcFactor - dstFactor" order. */
+		BO_REVERSE_SUBTRACT, /**< Blend factors are subtracted in "dstFactor - srcFactor" order. */
+		BO_MIN, /**< Minimum of the two factors is chosen. */
+		BO_MAX /**< Maximum of the two factors is chosen. */
+	};
+
+	/**
+	 * @brief	Comparison functions used for the depth/stencil buffer.
+	 */
+    enum CompareFunction
+    {
+		CMPF_ALWAYS_FAIL, /**< Operation will always fail. */
+		CMPF_ALWAYS_PASS, /**< Operation will always pass. */
+		CMPF_LESS, /**< Operation will pass if the new value is less than existing value. */
+        CMPF_LESS_EQUAL, /**< Operation will pass if the new value is less or equal than existing value. */
+        CMPF_EQUAL, /**< Operation will pass if the new value is equal to the existing value. */
+        CMPF_NOT_EQUAL, /**< Operation will pass if the new value is not equal to the existing value. */
+        CMPF_GREATER_EQUAL, /**< Operation will pass if the new value greater or equal than the existing value. */
+        CMPF_GREATER /**< Operation will pass if the new value greater than the existing value. */
+    };
+
+	/**
+	 * @brief	Types of texture addressing modes that determine what happens when texture
+	 *			coordinates are outside of the valid range.
+	 */
+    enum TextureAddressingMode
+    {
+		TAM_WRAP, /**< Coordinates wrap back to the valid range. */
+		TAM_MIRROR, /**< Coordinates flip every time the size of the valid range is passed. */
+		TAM_CLAMP, /**< Coordinates are clamped within the valid range. */
+		TAM_BORDER /**< Coordinates outside of the valid range will return a separately set border color. */
+    };
+
+	/**
+	 * @brief	Types of available filtering situations.
+	 */
+    enum FilterType
+    {
+		FT_MIN, /**< The filter used when shrinking a texture. */
+        FT_MAG, /**< The filter used when magnifying a texture. */
+        FT_MIP /**< The filter used when filtering between mipmaps. */
+    };
+
+	/**
+	 * @brief	Filtering options for textures.
+	 */
+    enum FilterOptions
+    {
+		FO_NONE = 0, /**< Use no filtering. Only relevant for mipmap filtering. */
+		FO_POINT = 1, /**< Filter using the nearest found pixel. Most basic filtering. */
+		FO_LINEAR = 2, /**< Average a 2x2 pixel area, signifies bilinear filtering for texture, trilinear for mipmaps. */
+		FO_ANISOTROPIC = 3, /**< More advanced filtering that improves quality when viewing textures at a steep angle */
+		FO_USE_COMPARISON = 4 /**< Specifies that the sampled values will be compared against existing sampled data. Should be OR-ed with other filtering options. */
+    };
+
+	/**
+	 * @brief	Types of frame buffers.
+	 */
+	enum FrameBufferType
+	{
+		FBT_COLOR = 0x1,
+		FBT_DEPTH = 0x2,
+		FBT_STENCIL = 0x4
+	};
+
+	/**
+	 * @brief	Types of culling that determine how (and if) hardware discards faces with certain
+	 *			winding order. Winding order can be used for determining front or back facing polygons by
+	 *			checking the order of its vertices from the render perspective.
+	 */
+    enum CullingMode
+    {
+		CULL_NONE = 0, /**< Hardware performs no culling and renders both sides. */
+		CULL_CLOCKWISE = 1, /**< Hardware culls faces that have a clockwise vertex ordering. */
+        CULL_COUNTERCLOCKWISE = 2 /**< Hardware culls faces that have a counter-clockwise vertex ordering. */
+    };
+
+	/**
+	 * @brief	Polygon mode to use when rasterizing.
+	 */
+    enum PolygonMode
+    {
+		PM_WIREFRAME = 1, /**< Render as wireframe showing only polygon outlines. */
+        PM_SOLID = 2 /**< Render as solid showing whole polygons. */
+    };
+
+	/**
+	 * @brief	Types of action that can happen on the stencil buffer.
+	 */
+	enum StencilOperation
+	{
+		SOP_KEEP, /**< Leave the stencil buffer unchanged. */
+		SOP_ZERO, /**< Set the stencil value to zero. */
+		SOP_REPLACE, /**< Replace the stencil value with the reference value. */
+		SOP_INCREMENT, /**< Increase the stencil value by 1, clamping at the maximum value. */
+		SOP_DECREMENT, /**< Decrease the stencil value by 1, clamping at 0. */
+		SOP_INCREMENT_WRAP, /**< Increase the stencil value by 1, wrapping back to 0 when incrementing past the maximum value. */
+		SOP_DECREMENT_WRAP, /**< Decrease the stencil value by 1, wrapping when decrementing 0. */
+		SOP_INVERT /**< Invert the bits of the stencil buffer. */
+	};
+
+	/**
+	* @brief	These values represent a hint to the driver when locking a hardware buffer.
+	*
+	*			GBL_WRITE_ONLY - Allows you to write to the buffer. Can cause a CPU-GPU sync point
+	*			so avoid using it often (i.e. every frame) as that might limit your performance significantly.
+	*			GBL_WRITE_ONLY_DISCARD - Allows you to write to the buffer. Tells the driver to completely discard the contents of the 
+	*			buffer you are writing to. The driver will (most likely) internally allocate another buffer with same specifications 
+	*			(which is fairly fast) and you will avoid CPU-GPU stalls.
+	*			GBL_WRITE_ONLY_NO_OVERWRITE - Allows you to write to the buffer. Guarantees the driver that you will not be updating any part of 
+	*			the buffer that is currently used. This will also avoid CPU-GPU stalls, without requiring you to discard the entire buffer. However 
+	*			it is hard to guarantee when GPU has finished using a buffer.
+	*			GBL_READ_ONLY - Allows you to read from a buffer. Be aware that reading is usually a very slow operation.
+	*			GBL_READ_WRITE - Allows you to both read and write to a buffer. 
+	*/
+	enum GpuLockOptions
+	{
+        GBL_READ_WRITE,
+		GBL_WRITE_ONLY_DISCARD,
+		GBL_READ_ONLY,
+        GBL_WRITE_ONLY_NO_OVERWRITE,
+		GBL_WRITE_ONLY	
+	};
+
+	/**
+	 * @brief	Values that represent hardware buffer usage. These usually determine in what
+	 *			type of memory is buffer placed in, however that depends on rendering API.
+	 * 
+	 *			GBU_STATIC - Signifies that you don't plan on modifying the buffer often (or at all)
+	 *			after creation. Modifying such buffer will involve a larger performance hit.
+	 *			GBU_DYNAMIC - Signifies that you will modify this buffer fairly often.
+	 */
+	enum GpuBufferUsage 
+	{
+        GBU_STATIC = 1,
+		GBU_DYNAMIC = 2
+	};
+
+	/**
+	 * @brief	Types of generic GPU buffers that may be attached to GPU programs.
+	 *
+	 *			GBT_STRUCTURED - Buffer containing an array of structures. Structure parameters
+	 *			can usually be easily accessed from within the GPU program.
+	 *			GBT_RAW - Buffer containing raw bytes. It is up to the user to interpret the data.
+	 *			GBT_INDIRECTARGUMENT - Special type of buffer allowing you to specify arguments for
+	 *			draw operations inside the buffer instead of providing them directly. Useful when you want
+	 *			to control drawing directly from GPU.
+	 *			GBT_APPENDCONSUME - A stack-like buffer that allows you to add or remove elements to/from the buffer
+	 *			from within the GPU program.
+	 */
+	enum GpuBufferType
+	{
+		GBT_STRUCTURED,
+		GBT_RAW,
+		GBT_INDIRECTARGUMENT,
+		GBT_APPENDCONSUME
+	};
+
+	/**
+	 * @brief	Different types of GPU views that control how GPU sees a hardware buffer.
+	 *
+	 *			GVU_DEFAULT - Buffer is seen as a default shader resource, used primarily for reading. (e.g. a texture for sampling)
+	 *			GVU_RENDERTARGET - Buffer is seen as a render target that color pixels will be written to after pixel shader stage.
+	 *			GVU_DEPTHSTENCIL - Buffer is seen as a depth stencil target that depth and stencil information is written to.
+	 *			GVU_RANDOMWRITE - Buffer that allows you to write to any part of it from within a GPU program.
+	 */
+	enum GpuViewUsage
+	{
+		GVU_DEFAULT = 0x01,
+		GVU_RENDERTARGET = 0x02,
+		GVU_DEPTHSTENCIL = 0x04,
+		GVU_RANDOMWRITE = 0x08
+	};
+
+	/**
+	 * @brief	Type of parameter block usages. Signifies how often will parameter blocks be changed.
+	 *
+	 *			GPBU_STATIC - Buffer will be rarely, if ever, updated.
+	 *			GPBU_DYNAMIC - Buffer will be updated often (e.g. every frame).
+	 */
+	enum GpuParamBlockUsage
+	{
+		GPBU_STATIC,
+		GPBU_DYNAMIC
+	};
+
+	/**
+	 * @brief	Type of GPU parameter.
+	 *
+	 *			GPT_DATA - Raw data type like float, Vector3, Color, etc.
+	 *			GPT_OBJECT - Reference to some GPU object like Texture, Sampler, etc.
+	 */
+	enum GpuParamType
+	{
+		GPT_DATA,
+		GPT_TEXTURE,
+		GPT_BUFFER,
+		GPT_SAMPLER
+	};
+
+	/**
+	 * @brief	Type of GPU data parameters that can be used as inputs to a GPU program.
+	 */
+	enum GpuParamDataType
+	{
+		GPDT_FLOAT1 = 1,
+		GPDT_FLOAT2 = 2,
+		GPDT_FLOAT3 = 3,
+		GPDT_FLOAT4 = 4,
+		GPDT_MATRIX_2X2 = 11,
+		GPDT_MATRIX_2X3 = 12,
+		GPDT_MATRIX_2X4 = 13,
+		GPDT_MATRIX_3X2 = 14,
+		GPDT_MATRIX_3X3 = 15,
+		GPDT_MATRIX_3X4 = 16,
+		GPDT_MATRIX_4X2 = 17,
+		GPDT_MATRIX_4X3 = 18,
+		GPDT_MATRIX_4X4 = 19,
+		GPDT_INT1 = 20,
+		GPDT_INT2 = 21,
+		GPDT_INT3 = 22,
+		GPDT_INT4 = 23,
+		GPDT_BOOL = 24,
+		GPDT_STRUCT = 25,
+		GPDT_COLOR = 26, // Same as GPDT_FLOAT4, but can be used to better deduce usage
+		GPDT_COUNT = 27, // Keep at end before GPDT_UNKNOWN
+		GPDT_UNKNOWN = 0xffff
+	};
+
+	/**
+	 * @brief	Contains data about a type used for GPU data parameters.
+	 */
+	struct GpuParamDataTypeInfo
+	{
+		UINT32 baseTypeSize;
+		UINT32 size;
+		UINT32 alignment;
+		UINT32 numRows;
+		UINT32 numColumns;
+	};
+
+	/**
+	 * @brief	Contains a lookup table for various information of all types used for data GPU parameters. Sizes are in bytes.
+	 */
+	struct GpuDataParamInfos
+	{
+		GpuDataParamInfos()
+		{
+			memset(lookup, 0, sizeof(lookup));
+
+			lookup[(UINT32)GPDT_FLOAT1] = { 4, 4, 4, 1, 1 };
+			lookup[(UINT32)GPDT_FLOAT2] = { 4, 8, 8, 1, 2 };
+			lookup[(UINT32)GPDT_FLOAT3] = { 4, 16, 16, 1, 3 };
+			lookup[(UINT32)GPDT_FLOAT4] = { 4, 16, 16, 1, 4 };
+			lookup[(UINT32)GPDT_MATRIX_2X2] = { 4, 16, 8, 2, 2 };
+			lookup[(UINT32)GPDT_MATRIX_2X3] = { 4, 32, 16, 2, 3 };
+			lookup[(UINT32)GPDT_MATRIX_2X4] = { 4, 32, 16, 2, 4 };
+			lookup[(UINT32)GPDT_MATRIX_3X2] = { 4, 24, 8, 3, 2 };
+			lookup[(UINT32)GPDT_MATRIX_3X3] = { 4, 48, 16, 3, 3 };
+			lookup[(UINT32)GPDT_MATRIX_3X4] = { 4, 48, 16, 3, 4 };
+			lookup[(UINT32)GPDT_MATRIX_4X2] = { 4, 32, 8, 4, 2 };
+			lookup[(UINT32)GPDT_MATRIX_4X3] = { 4, 64, 16, 4, 3 };
+			lookup[(UINT32)GPDT_MATRIX_4X4] = { 4, 64, 16, 4, 4 };
+			lookup[(UINT32)GPDT_INT1] = { 4, 4, 4, 1, 1 };
+			lookup[(UINT32)GPDT_INT2] = { 4, 8, 8, 1, 2 };
+			lookup[(UINT32)GPDT_INT3] = { 4, 12, 16, 1, 3 };
+			lookup[(UINT32)GPDT_INT4] = { 4, 16, 16, 1, 4 };
+			lookup[(UINT32)GPDT_BOOL] = { 4, 4, 4, 1, 1 };
+		}
+
+		GpuParamDataTypeInfo lookup[GPDT_COUNT];
+	};
+
+	/**
+	 * @brief	Type of GPU object parameters that can be used as inputs to a GPU program.
+	 */
+	enum GpuParamObjectType
+	{
+		GPOT_SAMPLER1D = 1,
+		GPOT_SAMPLER2D = 2,
+		GPOT_SAMPLER3D = 3,
+		GPOT_SAMPLERCUBE = 4,
+		GPOT_SAMPLER2DMS = 5,
+		GPOT_TEXTURE1D = 11,
+		GPOT_TEXTURE2D = 12,
+		GPOT_TEXTURE3D = 13,
+		GPOT_TEXTURECUBE = 14,
+		GPOT_TEXTURE2DMS = 15,
+		GPOT_BYTE_BUFFER = 32,
+		GPOT_STRUCTURED_BUFFER = 33,
+		GPOT_RWTYPED_BUFFER = 41,
+		GPOT_RWBYTE_BUFFER = 42,
+		GPOT_RWSTRUCTURED_BUFFER = 43,
+		GPOT_RWSTRUCTURED_BUFFER_WITH_COUNTER = 44,
+		GPOT_RWAPPEND_BUFFER = 45,
+		GPOT_RWCONSUME_BUFFER = 46,
+		GPOT_UNKNOWN = 0xffff
+	};
+
+	/**
+	 * @brief	These values represent a hint to the driver when writing
+	 * 			to a GPU buffer.
+	 * 			
+	 *			Normal - Default flag with least restrictions. Can cause a CPU-GPU sync point
+	 *			so avoid using it often (i.e. every frame) as that might limit your performance significantly.
+	 *			Discard - Tells the driver to completely discard the contents of the buffer you are writing
+	 *			to. The driver will (most likely) internally allocate another buffer with same specifications (which is fairly fast)
+	 *			and you will avoid CPU-GPU stalls. 
+	 *			NoOverwrite - Guarantees the driver that you will not be updating any part of the buffer that is currently used.
+	 *			This will also avoid CPU-GPU stalls, without requiring you to discard the entire buffer. However it is hard to
+	 *			guarantee when GPU has finished using a buffer.
+	 */
+	enum class BufferWriteType
+	{
+		Normal,
+		Discard,
+		NoOverwrite
+	};
+
+	/**
+	 * @brief	Suggested queue priority numbers used for sorting objects in
+	 *			the render queue. Objects with higher priority will be renderer sooner.
+	 */
+	enum class QueuePriority
+	{
+		Opaque = 100000,
+		Transparent = 90000,
+		Skybox = 80000,
+		Overlay = 70000
+	};
+
+	/**
+	 * @brief	Type of sorting to perform on an object when added to a render queue.
+	 */
+	enum class QueueSortType
+	{
+		FrontToBack, /**< All objects with the same priority will be rendered front to back based on their center. */
+		BackToFront, /**< All objects with the same priority will be rendered back to front based on their center. */
+		None /**< Objects will not be sorted and will be processed in the order they were added to the queue. */
+	};
+
+	/**
+	 * @brief	Flags that may be assigned to a shader that let the renderer know how to interpret
+	 *			the shader.
+	 */
+	enum class ShaderFlags
+	{
+		Transparent = 0x1 /**< Signifies that the shader is rendering a transparent object. */
+	};
+
+	/**
+	 * @brief	Enum that defines possible window border styles.
+	 */
+	enum class WindowBorder
+	{
+		Normal,
+		None,
+		Fixed
+	};
+
+	/**
+	 * @brief	Texture addressing mode, per component.
+	 */
+	struct UVWAddressingMode
+	{
+		UVWAddressingMode()
+			:u(TAM_WRAP), v(TAM_WRAP), w(TAM_WRAP)
+		{ }
+
+		bool operator==(const UVWAddressingMode& rhs) const
+		{
+			return u == rhs.u && v == rhs.v && w == rhs.w;
+		}
+
+		TextureAddressingMode u, v, w;
+	};
+    
+	/**
+	 * @brief	References a subset of surfaces within a texture.
+	 */
+	struct TextureSurface
+	{
+		TextureSurface(UINT32 mipLevel = 0, UINT32 numMipLevels = 1, 
+			UINT32 arraySlice = 0, UINT32 numArraySlices = 1)
+			:mipLevel(mipLevel), numMipLevels(numMipLevels), 
+			arraySlice(arraySlice), numArraySlices(numArraySlices)
+		{ }
+
+		UINT32 mipLevel;
+		UINT32 numMipLevels;
+		UINT32 arraySlice;
+		UINT32 numArraySlices;
+	};
+
+	/**
+	 * @brief	Helper class for syncing dirty data from sim CoreObject to
+	 *			core CoreObject and other way around.
+	 */
+	class CoreSyncData
+	{
+	public:
+		CoreSyncData()
+			:data(nullptr), size(0)
+		{ }
+
+		CoreSyncData(UINT8* data, UINT32 size)
+			:data(data), size(size)
+		{ }
+
+		/**
+		 * @brief	Gets the internal data and checks the data is of
+		 *			valid size.
+		 */
+		template<class T>
+		const T& getData() const
+		{
+			assert(sizeof(T) == size);
+
+			return *(T*)data;
+		}
+
+		/**
+		 * @brief	Returns a pointer to internal data buffer.
+		 */
+		UINT8* getBuffer() const { return data; }
+
+		/**
+		 * @brief	Returns the size of the internal data buffer.
+		 */
+		UINT32 getBufferSize() const { return size; }
+
+	private:
+		UINT8* data;
+		UINT32 size;
+	};
+
+	typedef Map<String, String> NameValuePairList;
 }

+ 120 - 0
BansheeCore/Include/BsMaterial.h

@@ -16,6 +16,8 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	class __MaterialParams;
+
 	/** Helper class containing parameters for all types of GPU programs used in a pass. */
 	template<bool Core>
 	class TPassParameters
@@ -520,6 +522,108 @@ namespace BansheeEngine
 		template <typename T>
 		void getParam(const String& name, TMaterialDataParam<T, Core>& output) const;
 
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		template <typename T>
+		TMaterialDataParam<T, false> createDataParam(const String& name, 
+			const SPtr<Vector<TGpuDataParam<T, false>>>& gpuParams) const
+		{
+			return TMaterialDataParam<T, false>(name, getCachedParams(), gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		template <typename T>
+		TMaterialDataParam<T, true> createDataParam(const String& name, 
+			const SPtr<Vector<TGpuDataParam<T, true>>>& gpuParams) const
+		{
+			return TMaterialDataParam<T, true>(gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamStruct<false> createStructParam(const String& name, 
+			const SPtr<Vector<TGpuParamStruct<false>>>& gpuParams) const
+		{
+			return TMaterialParamStruct<false>(name, getCachedParams(), gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamStruct<true> createStructParam(const String& name, 
+			const SPtr<Vector<TGpuParamStruct<true>>>& gpuParams) const
+		{
+			return TMaterialParamStruct<true>(gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamTexture<false> createTextureParam(const String& name, 
+			const SPtr<Vector<TGpuParamTexture<false>>>& gpuParams) const
+		{
+			return TMaterialParamTexture<false>(name, getCachedParams(), gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamTexture<true> createTextureParam(const String& name,
+			const SPtr<Vector<TGpuParamTexture<true>>>& gpuParams) const
+		{
+			return TMaterialParamTexture<true>(gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamLoadStoreTexture<false> createLoadStoreTextureParam(const String& name, 
+			const SPtr<Vector<TGpuParamLoadStoreTexture<false>>>& gpuParams) const
+		{
+			return TMaterialParamLoadStoreTexture<false>(name, getCachedParams(), gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamLoadStoreTexture<true> createLoadStoreTextureParam(const String& name,
+			const SPtr<Vector<TGpuParamLoadStoreTexture<true>>>& gpuParams) const
+		{
+			return TMaterialParamLoadStoreTexture<true>(gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamSampState<false> createSamplerStateParam(const String& name, 
+			const SPtr<Vector<TGpuParamSampState<false>>>& gpuParams) const
+		{
+			return TMaterialParamSampState<false>(name, getCachedParams(), gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamSampState<true> createSamplerStateParam(const String& name,
+			const SPtr<Vector<TGpuParamSampState<true>>>& gpuParams) const
+		{
+			return TMaterialParamSampState<true>(gpuParams);
+		}
+
 		/**
 		 * Assigns a value from a raw buffer to the parameter with the specified name. Buffer must be of sizeof(T) * 
 		 * numElements size and initialized.
@@ -529,6 +633,15 @@ namespace BansheeEngine
 		template <typename T>
 		void setParamValue(const String& name, UINT8* buffer, UINT32 numElements);
 
+		/** Called during initialization, creates enough space to cache all parameters (not used on core thread). */
+		void createCachedParams(const SPtr<ShaderCore>& shader) { /* Do nothing */}
+
+		/** Called during initialization, creates enough space to cache all parameters. */
+		virtual void createCachedParams(const HShader& shader) { }
+
+		/** Returns a list of all values assigned to material parameters. */
+		virtual SPtr<__MaterialParams> getCachedParams() const { return nullptr; }
+
 		/**
 		 * Initializes the material by using the best technique from the currently set shader. Shader must contain the 
 		 * technique that matches the current renderer and render system.
@@ -648,7 +761,14 @@ namespace BansheeEngine
 		/**	Performs material initialization when all resources are ready. */
 		void initializeIfLoaded();
 
+		/** @copydoc Material::createCachedParams */
+		void createCachedParams(const HShader& shader) override;
+
+		/** @copydoc Material::getCachedParams */
+		SPtr<__MaterialParams> getCachedParams() const override { return mCachedParams; }
+
 		UINT32 mLoadFlags;
+		SPtr<__MaterialParams> mCachedParams;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 166 - 23
BansheeCore/Include/BsMaterialParam.h

@@ -9,34 +9,104 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	class __MaterialParams;
+
 	/**
-	 * A wrapper class that allows you to manage multiple GPU parameters at once.
-	 *
-	 * @see		TGpuDataParam
+	 * A handle that allows you to set a Material parameter. Internally keeps a reference to the material parameters so that
+	 * possibly expensive lookup of parameter name can be avoided each time the parameter is accessed, and instead the 
+	 * handle can be cached.
+	 * 			
+	 * @note	
+	 * This is pretty much identical to GPU parameter version (e.g. TGpuDataParam), except that this will get/set parameter 
+	 * values on all GPU programs attached to the material, while TGpuDataParam works only for single GPU program's 
+	 * parameters. Also, additional parameters that might be optimized out in the GPU program will still exist here as long 
+	 * as they're  defined in the shader used by the material, which is not the case with TGpuDataParam.
+	 * @note
+	 * For core-thread version of this class no shader-based caching is done, and instead this represents just a wrapper
+	 * for multiple GPU parameters.
+	 * 
+	 * @see		Material
 	 */
 	template<class T, bool Core>
 	class BS_CORE_EXPORT TMaterialDataParam
+	{ };
+
+	/** @copydoc TMaterialDataParam */
+	template<class T>
+	class BS_CORE_EXPORT TMaterialDataParam<T, false>
 	{
 	public:
-		TMaterialDataParam(const SPtr<Vector<TGpuDataParam<T, Core>>>& params);
+		TMaterialDataParam(const String& name, const SPtr<__MaterialParams>& params, 
+			const SPtr<Vector<TGpuDataParam<T, false>>>& gpuParams);
 		TMaterialDataParam() { }
-		
+
 		/** @copydoc TGpuDataParam::set */
 		void set(const T& value, UINT32 arrayIdx = 0);
 
+		/** @copydoc TGpuDataParam::get */
+		T get(UINT32 arrayIdx = 0);
+
+	protected:
+		UINT32 mParamIndex;
+		UINT32 mArraySize;
+		SPtr<__MaterialParams> mMaterialParams;
+		SPtr<Vector<TGpuDataParam<T, false>>> mGPUParams;
+	};
+
+	/** @copydoc TMaterialDataParam */
+	template<class T>
+	class BS_CORE_EXPORT TMaterialDataParam<T, true>
+	{
+	public:
+		TMaterialDataParam(const SPtr<Vector<TGpuDataParam<T, true>>>& params);
+		TMaterialDataParam() { }
+
 		/** @copydoc TGpuDataParam::set */
+		void set(const T& value, UINT32 arrayIdx = 0);
+
+		/** @copydoc TGpuDataParam::get */
 		T get(UINT32 arrayIdx = 0);
 
 	protected:
-		SPtr<Vector<TGpuDataParam<T, Core>>> mParams;
+		SPtr<Vector<TGpuDataParam<T, true>>> mParams;
 	};
 
 	/** @copydoc TMaterialDataParam */
 	template<bool Core>
 	class BS_CORE_EXPORT TMaterialParamStruct
+	{ };
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamStruct<false>
+	{
+	public:
+		TMaterialParamStruct(const String& name, const SPtr<__MaterialParams>& params,
+			const SPtr<Vector<TGpuParamStruct<false>>>& gpuParams);
+		TMaterialParamStruct() { }
+
+		/** @copydoc TGpuParamStruct::set */
+		void set(const void* value, UINT32 sizeBytes, UINT32 arrayIdx = 0);
+
+		/** @copydoc TGpuParamStruct::get */
+		void get(void* value, UINT32 sizeBytes, UINT32 arrayIdx = 0);
+
+		/** @copydoc TGpuParamStruct::getElementSize */
+		UINT32 getElementSize() const;
+
+	protected:
+		UINT32 mParamIndex;
+		UINT32 mArraySize;
+		SPtr<__MaterialParams> mMaterialParams;
+		SPtr<Vector<TGpuParamStruct<false>>> mGPUParams;
+	};
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamStruct<true>
 	{
 	public:
-		TMaterialParamStruct(const SPtr<Vector<TGpuParamStruct<Core>>>& params);
+		TMaterialParamStruct(const SPtr<Vector<TGpuParamStruct<true>>>& params);
 		TMaterialParamStruct() { }
 
 		/** @copydoc TGpuParamStruct::set */
@@ -49,67 +119,140 @@ namespace BansheeEngine
 		UINT32 getElementSize() const;
 
 	protected:
-		SPtr<Vector<TGpuParamStruct<Core>>> mParams;
+		SPtr<Vector<TGpuParamStruct<true>>> mParams;
 	};
 
 	/** @copydoc TMaterialDataParam */
 	template<bool Core>
 	class BS_CORE_EXPORT TMaterialParamTexture
+	{ };
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamTexture<false>
 	{
 	public:
-		typedef typename TGpuParamTextureType<Core>::Type TextureType;
+		TMaterialParamTexture(const String& name, const SPtr<__MaterialParams>& params, 
+			const SPtr<Vector<TGpuParamTexture<false>>>& gpuParams);
+		TMaterialParamTexture() { }
 
-		TMaterialParamTexture(const SPtr<Vector<TGpuParamTexture<Core>>>& params);
+		/** @copydoc GpuParamTexture::set */
+		void set(const HTexture& texture);
+
+		/** @copydoc GpuParamTexture::get */
+		HTexture get();
+
+	protected:
+		UINT32 mParamIndex;
+		SPtr<__MaterialParams> mMaterialParams;
+		SPtr<Vector<TGpuParamTexture<false>>> mGPUParams;
+	};
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamTexture<true>
+	{
+	public:
+		TMaterialParamTexture(const SPtr<Vector<TGpuParamTexture<true>>>& params);
 		TMaterialParamTexture() { }
 
 		/** @copydoc GpuParamTexture::set */
-		void set(const TextureType& texture);
+		void set(const SPtr<TextureCore>& texture);
 
 		/** @copydoc GpuParamTexture::get */
-		TextureType get();
+		SPtr<TextureCore> get();
 
 	protected:
-		SPtr<Vector<TGpuParamTexture<Core>>> mParams;
+		SPtr<Vector<TGpuParamTexture<true>>> mParams;
 	};
 
 	/** @copydoc TMaterialDataParam */
 	template<bool Core>
 	class BS_CORE_EXPORT TMaterialParamLoadStoreTexture
+	{ };
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamLoadStoreTexture<false>
 	{
 	public:
-		typedef typename TGpuParamTextureType<Core>::Type TextureType;
+		TMaterialParamLoadStoreTexture(const String& name, const SPtr<__MaterialParams>& params,
+			const SPtr<Vector<TGpuParamLoadStoreTexture<false>>>& gpuParams);
+		TMaterialParamLoadStoreTexture() { }
+
+		/** @copydoc GpuParamLoadStoreTexture::set */
+		void set(const HTexture& texture, const TextureSurface& surface);
 
-		TMaterialParamLoadStoreTexture(const SPtr<Vector<TGpuParamLoadStoreTexture<Core>>>& params);
+		/** @copydoc GpuParamLoadStoreTexture::get */
+		HTexture get();
+
+	protected:
+		UINT32 mParamIndex;
+		SPtr<__MaterialParams> mMaterialParams;
+		SPtr<Vector<TGpuParamLoadStoreTexture<false>>> mGPUParams;
+	};
+
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamLoadStoreTexture<true>
+	{
+	public:
+		TMaterialParamLoadStoreTexture(const SPtr<Vector<TGpuParamLoadStoreTexture<true>>>& params);
 		TMaterialParamLoadStoreTexture() { }
 
 		/** @copydoc GpuParamLoadStoreTexture::set */
-		void set(const TextureType& texture, const TextureSurface& surface);
+		void set(const SPtr<TextureCore>& texture, const TextureSurface& surface);
 
 		/** @copydoc GpuParamLoadStoreTexture::get */
-		TextureType get();
+		SPtr<TextureCore> get();
 
 	protected:
-		SPtr<Vector<TGpuParamLoadStoreTexture<Core>>> mParams;
+		SPtr<Vector<TGpuParamLoadStoreTexture<true>>> mParams;
 	};
 
 	/** @copydoc TMaterialDataParam */
 	template<bool Core>
 	class BS_CORE_EXPORT TMaterialParamSampState
+	{ };
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamSampState<false>
 	{
 	public:
-		typedef typename TGpuParamSamplerStateType<Core>::Type SamplerType;
+		TMaterialParamSampState(const String& name, const SPtr<__MaterialParams>& params, 
+			const SPtr<Vector<TGpuParamSampState<false>>>& gpuParams);
+		TMaterialParamSampState() { }
+
+		/** @copydoc GpuParamSampState::set */
+		void set(const SPtr<SamplerState>& sampState);
+
+		/** @copydoc GpuParamSampState::get */
+		SPtr<SamplerState> get();
 
-		TMaterialParamSampState(const SPtr<Vector<TGpuParamSampState<Core>>>& params);
+	protected:
+		UINT32 mParamIndex;
+		SPtr<__MaterialParams> mMaterialParams;
+		SPtr<Vector<TGpuParamSampState<false>>> mGPUParams;
+	};
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamSampState<true>
+	{
+	public:
+		TMaterialParamSampState(const SPtr<Vector<TGpuParamSampState<true>>>& params);
 		TMaterialParamSampState() { }
 
 		/** @copydoc GpuParamSampState::set */
-		void set(const SamplerType& sampState);
+		void set(const SPtr<SamplerStateCore>& sampState);
 
 		/** @copydoc GpuParamSampState::get */
-		SamplerType get();
+		SPtr<SamplerStateCore> get();
 
 	protected:
-		SPtr<Vector<TGpuParamSampState<Core>>> mParams;
+		SPtr<Vector<TGpuParamSampState<true>>> mParams;
 	};
 
 	typedef TMaterialDataParam<float, false> MaterialParamFloat;

+ 375 - 0
BansheeCore/Include/BsMaterialParams.h

@@ -0,0 +1,375 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsStaticAlloc.h"
+#include "BsVector2.h"
+#include "BsVector3.h"
+#include "BsVector4.h"
+#include "BsVector2I.h"
+#include "BsVectorNI.h"
+#include "BsColor.h"
+#include "BsMatrix3.h"
+#include "BsMatrix4.h"
+#include "BsMatrixNxM.h"
+#include "BsMaterial.h"
+#include "BsShader.h"
+
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup Material
+	 *  @{
+	 */
+
+	/** 
+	 * Contains all parameter values set in a Material. This is similar to GpuParams which also stores parameter values,
+	 * however GpuParams are built for use on the GPU-side and don't store parameters that don't exist in a compiled GPU
+	 * program. This object on the other hand stores all parameters defined in a shader, regardless or not if they actually
+	 * exist in the GPU program. Additionally GpuParams are defined per-program (e.g. vertex, fragment) while this object
+	 * exists for the entire material.
+	 *
+	 * @note
+	 * This introduces redundancy as parameters stored by GpuParams and this object are duplicated. If this is an issue the
+	 * implementation can be modified to only store parameters not included in GpuParams.
+	 * @note
+	 * The reason why parameters in this class and GpuParams differ is most often compiler optimizations. If a compiler
+	 * optimizes out a variable in a GPU program we should still be able to store it, either for later when the variable
+	 * will be introduced, or for other techniques that might have that variable implemented.
+	 */
+	class BS_CORE_EXPORT __MaterialParams
+	{
+		/** Raw data for a single structure parameter. */
+		class BS_CORE_EXPORT StructParamData
+		{
+		public:
+			UINT8* data;
+			UINT32 dataSize;
+		};
+
+		/** Data for a single texture parameter. */
+		class BS_CORE_EXPORT TextureParamData
+		{
+		public:
+			HTexture value;
+			bool isLoadStore;
+			TextureSurface surface;
+		};
+
+	public:
+		/** Type of material parameter. */
+		enum class ParamType
+		{
+			Data, Texture, Sampler
+		};
+
+		/** Meta-data about a parameter. */
+		struct ParamData
+		{
+			ParamType type;
+			GpuParamDataType dataType;
+			UINT32 index;
+			UINT32 arraySize;
+		};
+
+		/** Creates a new material params object and initializes enough room for parameters from the provided shader. */
+		__MaterialParams(const HShader& shader);
+		~__MaterialParams();
+
+		/** 
+		 * Returns the value of a shader data parameter with the specified name at the specified array index. If the
+		 * parameter name, index or type is not valid a warning will be logged and output value will not be retrieved.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	arrayIdx	If the parameter is an array, index of the entry to access.
+		 * @param[out]	output		If successful, value of the parameter.
+		 *
+		 * @tparam		T			Native type of the parameter.
+		 */
+		template <typename T>
+		void getDataParam(const String& name, UINT32 arrayIdx, T& output) const
+		{
+			const ParamData* param = getParamData(name, ParamType::Data, getDataType(output), arrayIdx);
+			if (param == nullptr)
+				return;
+
+			getDataParam(param->index + arrayIdx, output);
+		}
+
+		/** 
+		 * Sets the value of a shader data parameter with the specified name at the specified array index. If the
+		 * parameter name, index or type is not valid a warning will be logged and output value will not be set.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	arrayIdx	If the parameter is an array, index of the entry to access.
+		 * @param[in]	input		New value of the parameter.
+		 *
+		 * @tparam		T			Native type of the parameter.
+		 */
+		template <typename T>
+		void setDataParam(const String& name, UINT32 arrayIdx, const T& input) const
+		{
+			const ParamData* param = getParamData(name, ParamType::Data, getDataType(input), arrayIdx);
+			if (param == nullptr)
+				return;
+
+			setDataParam(param->index + arrayIdx, input);
+		}
+
+		/** 
+		 * Returns the value of a shader structure parameter with the specified name at the specified array index. If the
+		 * parameter name, index or type is not valid a warning will be logged and output value will not be retrieved.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[out]	value		Pre-allocated buffer of @p size bytes where the value will be retrieved.
+		 * @param[in]	size		Size of the buffer into which to write the value. Must match parameter struct's size.
+		 * @param[in]	arrayIdx	If the parameter is an array, index of the entry to access.
+		 */
+		void getStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx);
+
+		/** 
+		 * Sets the value of a shader structure parameter with the specified name at the specified array index. If the
+		 * parameter name, index or type is not valid a warning will be logged and output value will not be retrieved.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	value		Buffer of @p size bytes containing the new value of the structure.
+		 * @param[in]	size		Size of the buffer from which to retrieve the value. Must match parameter struct's size.
+		 * @param[in]	arrayIdx	If the parameter is an array, index of the entry to access.
+		 */
+		void setStructData(const String& name, const void* value, UINT32 size, UINT32 arrayIdx);
+
+		/** 
+		 * Returns the value of a shader texture parameter with the specified name. If the parameter name or type is not 
+		 * valid a warning will be logged and output value will not be retrieved.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[out]	value		Output value of the parameter.
+		 */
+		void getTexture(const String& name, HTexture& value);
+
+		/** 
+		 * Sets the value of a shader texture parameter with the specified name. If the parameter name or type is not 
+		 * valid a warning will be logged and output value will not be set.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	value		New value of the parameter.
+		 */
+		void setTexture(const String& name, const HTexture& value);
+
+		/** 
+		 * Returns the value of a shader load/store texture parameter with the specified name. If the parameter name or 
+		 * type is not valid a warning will be logged and output value will not be retrieved.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[out]	value		Output value of the parameter.
+		 * @param[out]	surface		Surface describing which part of the texture is being accessed.
+		 */
+		void getLoadStoreTexture(const String& name, HTexture& value, TextureSurface& surface);
+
+		/** 
+		 * Sets the value of a shader load/store texture parameter with the specified name. If the parameter name or 
+		 * type is not valid a warning will be logged and the value will not be set.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	value		New value of the parameter.
+		 * @param[in]	surface		Surface describing which part of the texture is being accessed.
+		 */
+		void setLoadStoreTexture(const String& name, const HTexture& value, const TextureSurface& surface);
+
+		/** 
+		 * Sets the value of a shader sampler state parameter with the specified name. If the parameter name or type is not 
+		 * valid a warning will be logged and output value will not be set.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[out]	value		Output value of the parameter.
+		 */
+		void getSamplerState(const String& name, SamplerStatePtr& value);
+
+		/** 
+		 * Sets the value of a shader sampler state parameter with the specified name. If the parameter name or type is not 
+		 * valid a warning will be logged and output value will not be set.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	value		New value of the parameter.
+		 */
+		void setSamplerState(const String& name, const SamplerStatePtr& value);
+
+		/** 
+		 * Returns data about a parameter and reports an error if there is a type or size mismatch, or if the parameter
+		 * does exist.
+		 *
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	type		Type of the parameter retrieve. Error will be logged if actual type of the parameter 
+		 *							doesn't match.
+		 * @param[in]	dataType	Only relevant if the parameter is a data type. Determines exact data type of the parameter
+		 *							to retrieve. Error will be logged if the type of the parameter doesn't match.
+		 * @param[in]	arrayIdx	Array index of the entry to retrieve. Error will be logged if the array index is out
+		 *							side of the valid range.
+		 *
+		 * @return					If successful, object describing the parameter with an index to its data. Otherwise
+		 *							null.
+		 */
+		const ParamData* getParamData(const String& name, ParamType type, GpuParamDataType dataType, UINT32 arrayIdx);
+
+		/** Returns a value of a parameter using its iternal array index as returned by getParamData(). */
+		void getDataParam(UINT32 index, float& output) const { output = mFloatParams[index]; }
+
+		/** @copydoc getDataParam(UINT32, float&) */
+		void getDataParam(UINT32 index, Vector2& output) const { output = mVec2Params[index]; }
+
+		/** @copydoc getDataParam(UINT32, float&) */
+		void getDataParam(UINT32 index, Vector3& output) const { output = mVec3Params[index]; }
+
+		/** @copydoc getDataParam(UINT32, float&) */
+		void getDataParam(UINT32 index, Vector4& output) const { output = mVec4Params[index]; }
+
+		/** @copydoc getDataParam(UINT32, float&) */
+		void getDataParam(UINT32 index, Matrix3& output) const { output = mMat3Params[index]; }
+
+		/** @copydoc getDataParam(UINT32, float&) */
+		void getDataParam(UINT32 index, Matrix4& output) const { output = mMat4Params[index]; }
+
+		/** @copydoc getDataParam(UINT32, float&) */
+		void getDataParam(UINT32 index, Color& output) const { output = mColorParams[index]; }
+
+		/** Sets a value of a parameter using its iternal array index as returned by getParamData(). */
+		void setDataParam(UINT32 index, float input) { mFloatParams[index] = input; }
+
+		/** @copydoc setDataParam(UINT32, float&) */
+		void setDataParam(UINT32 index, Vector2 input) { mVec2Params[index] = input; }
+
+		/** @copydoc setDataParam(UINT32, float&) */
+		void setDataParam(UINT32 index, Vector3 input) { mVec3Params[index] = input; }
+
+		/** @copydoc setDataParam(UINT32, float&) */
+		void setDataParam(UINT32 index, Vector4 input) { mVec4Params[index] = input; }
+
+		/** @copydoc setDataParam(UINT32, float&) */
+		void setDataParam(UINT32 index, Matrix3 input) { mMat3Params[index] = input; }
+
+		/** @copydoc setDataParam(UINT32, float&) */
+		void setDataParam(UINT32 index, Matrix4 input) { mMat4Params[index] = input; }
+
+		/** @copydoc setDataParam(UINT32, float&) */
+		void setDataParam(UINT32 index, Color input) { mColorParams[index] = input; }
+
+		/** 
+		 * Equivalent to getStructData(const String&, UINT32, void*, UINT32) except it uses the internal parameter index
+		 * directly, avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void getStructData(UINT32 index, void* value, UINT32 size);
+
+		/** 
+		 * Equivalent to setStructData(const String&, UINT32, void*, UINT32) except it uses the internal parameter index
+		 * directly, avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void setStructData(UINT32 index, const void* value, UINT32 size);
+
+		/** 
+		 * Equivalent to getTexture(const String&, HTexture&) except it uses the internal parameter index directly, 
+		 * avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void getTexture(UINT32 index, HTexture& value);
+
+		/** 
+		 * Equivalent to setTexture(const String&, HTexture&) except it uses the internal parameter index directly, 
+		 * avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void setTexture(UINT32 index, const HTexture& value);
+
+		/** 
+		 * Equivalent to getLoadStoreTexture(const String&, HTexture&, TextureSurface&) except it uses the internal 
+		 * parameter index directly, avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void getLoadStoreTexture(UINT32 index, HTexture& value, TextureSurface& surface);
+
+		/** 
+		 * Equivalent to setLoadStoreTexture(const String&, HTexture&, TextureSurface&) except it uses the internal 
+		 * parameter index directly, avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void setLoadStoreTexture(UINT32 index, const HTexture& value, const TextureSurface& surface);
+
+		/** 
+		 * Equivalent to getSamplerState(const String&, SamplerStatePtr&) except it uses the internal parameter index 
+		 * directly, avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void getSamplerState(UINT32 index, SamplerStatePtr& value);
+
+		/** 
+		 * Equivalent to setSamplerState(const String&, SamplerStatePtr&) except it uses the internal parameter index 
+		 * directly, avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void setSamplerState(UINT32 index, const SamplerStatePtr& value);
+
+		static GpuParamDataType getDataType(const float& dummy) { return GPDT_FLOAT1; }
+		static GpuParamDataType getDataType(const Vector2& dummy) { return GPDT_FLOAT2; }
+		static GpuParamDataType getDataType(const Vector3& dummy) { return GPDT_FLOAT3; }
+		static GpuParamDataType getDataType(const Vector4& dummy) { return GPDT_FLOAT4; }
+		static GpuParamDataType getDataType(const int& dummy) { return GPDT_INT1; }
+		static GpuParamDataType getDataType(const Vector2I& dummy) { return GPDT_INT1; }
+		static GpuParamDataType getDataType(const Vector3I& dummy) { return GPDT_INT1; }
+		static GpuParamDataType getDataType(const Vector4I& dummy) { return GPDT_INT1; }
+		static GpuParamDataType getDataType(const Matrix2& dummy) { return GPDT_MATRIX_2X2; }
+		static GpuParamDataType getDataType(const Matrix2x3& dummy) { return GPDT_MATRIX_2X3; }
+		static GpuParamDataType getDataType(const Matrix2x4& dummy) { return GPDT_MATRIX_2X4; }
+		static GpuParamDataType getDataType(const Matrix3& dummy) { return GPDT_MATRIX_3X3; }
+		static GpuParamDataType getDataType(const Matrix3x2& dummy) { return GPDT_MATRIX_3X2; }
+		static GpuParamDataType getDataType(const Matrix3x4& dummy) { return GPDT_MATRIX_3X4; }
+		static GpuParamDataType getDataType(const Matrix4& dummy) { return GPDT_MATRIX_4X4; }
+		static GpuParamDataType getDataType(const Matrix4x2& dummy) { return GPDT_MATRIX_4X2; }
+		static GpuParamDataType getDataType(const Matrix4x3& dummy) { return GPDT_MATRIX_4X3; }
+		static GpuParamDataType getDataType(const Color& dummy) { return GPDT_COLOR; }
+	private:
+		const static UINT32 STATIC_BUFFER_SIZE = 256;
+
+		UnorderedMap<String, ParamData> mParams;
+
+		float* mFloatParams = nullptr;
+		Vector2* mVec2Params = nullptr;
+		Vector3* mVec3Params = nullptr;
+		Vector4* mVec4Params = nullptr;
+		int* mIntParams = nullptr;
+		Vector2I* mVec2IParams = nullptr;
+		Vector3I* mVec3IParams = nullptr;
+		Vector4I* mVec4IParams = nullptr;
+		Matrix2* mMat2Params = nullptr;
+		Matrix2x3* mMat2x3Params = nullptr;
+		Matrix2x4* mMat2x4Params = nullptr;
+		Matrix3* mMat3Params = nullptr;
+		Matrix3x2* mMat3x2Params = nullptr;
+		Matrix3x4* mMat3x4Params = nullptr;
+		Matrix4* mMat4Params = nullptr;
+		Matrix4x2* mMat4x2Params = nullptr;
+		Matrix4x3* mMat4x3Params = nullptr;
+		Color* mColorParams = nullptr;
+		StructParamData* mStructParams = nullptr;
+		TextureParamData* mTextureParams = nullptr;
+		SamplerStatePtr* mSamplerStateParams = nullptr;
+
+		UINT32 mNumFloatParams = 0;
+		UINT32 mNumVec2Params = 0;
+		UINT32 mNumVec3Params = 0;
+		UINT32 mNumVec4Params = 0;
+		UINT32 mNumIntParams = 0;
+		UINT32 mNumVec2IParams = 0;
+		UINT32 mNumVec3IParams = 0;
+		UINT32 mNumVec4IParams = 0;
+		UINT32 mNumMat2Params = 0;
+		UINT32 mNumMat2x3Params = 0;
+		UINT32 mNumMat2x4Params = 0;
+		UINT32 mNumMat3Params = 0;
+		UINT32 mNumMat3x2Params = 0;
+		UINT32 mNumMat3x4Params = 0;
+		UINT32 mNumMat4Params = 0;
+		UINT32 mNumMat4x2Params = 0;
+		UINT32 mNumMat4x3Params = 0;
+		UINT32 mNumColorParams = 0;
+		UINT32 mNumStructParams = 0;
+		UINT32 mNumTextureParams = 0;
+		UINT32 mNumSamplerParams = 0;
+
+		mutable StaticAlloc<STATIC_BUFFER_SIZE, STATIC_BUFFER_SIZE> mAlloc;
+	};
+
+	/** @} */
+	/** @endcond */
+}

+ 1465 - 1457
BansheeCore/Source/BsMaterial.cpp

@@ -1,1458 +1,1466 @@
-#include "BsMaterial.h"
-#include "BsException.h"
-#include "BsShader.h"
-#include "BsTechnique.h"
-#include "BsPass.h"
-#include "BsRenderAPI.h"
-#include "BsHardwareBufferManager.h"
-#include "BsGpuProgram.h"
-#include "BsGpuParamBlockBuffer.h"
-#include "BsGpuParamDesc.h"
-#include "BsMaterialRTTI.h"
-#include "BsMaterialManager.h"
-#include "BsDebug.h"
-#include "BsResources.h"
-#include "BsFrameAlloc.h"
-#include "BsMatrixNxM.h"
-#include "BsVectorNI.h"
-#include "BsMemorySerializer.h"
-
-namespace BansheeEngine
-{
-	struct ShaderBlockDesc
-	{
-		String name;
-		GpuParamBlockUsage usage;
-		int size;
-		bool create;
-	};
-
-	enum MaterialLoadFlags
-	{
-		Load_None	= 0,
-		Load_Shader	= 1,
-		Load_All	= 2
-	};
-
-	const UINT32 PassParameters::NUM_PARAMS = 6;
-	const UINT32 PassParametersCore::NUM_PARAMS = 6;
-	
-	SPtr<PassParametersCore> convertParamsToCore(const SPtr<PassParameters>& passParams)
-	{
-		SPtr<PassParametersCore> passParameters = bs_shared_ptr_new<PassParametersCore>();
-
-		if (passParams->mVertParams != nullptr)
-			passParameters->mVertParams = passParams->mVertParams->getCore();
-		else
-			passParameters->mVertParams = nullptr;
-
-		if (passParams->mFragParams != nullptr)
-			passParameters->mFragParams = passParams->mFragParams->getCore();
-		else
-			passParameters->mFragParams = nullptr;
-
-		if (passParams->mGeomParams != nullptr)
-			passParameters->mGeomParams = passParams->mGeomParams->getCore();
-		else
-			passParameters->mGeomParams = nullptr;
-
-		if (passParams->mHullParams != nullptr)
-			passParameters->mHullParams = passParams->mHullParams->getCore();
-		else
-			passParameters->mHullParams = nullptr;
-
-		if (passParams->mDomainParams != nullptr)
-			passParameters->mDomainParams = passParams->mDomainParams->getCore();
-		else
-			passParameters->mDomainParams = nullptr;
-
-		if (passParams->mComputeParams != nullptr)
-			passParameters->mComputeParams = passParams->mComputeParams->getCore();
-		else
-			passParameters->mComputeParams = nullptr;
-
-		return passParameters;
-	}
-
-	bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets)
-	{
-		bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize
-			&& paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride;
-
-		if (!ignoreBufferOffsets)
-			equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset;
-
-		return equal;
-	}
-
-	Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<GpuParamDescPtr>& paramDescs)
-	{
-		Map<String, const GpuParamDataDesc*> foundDataParams;
-		Map<String, bool> validParams;
-
-		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
-		{
-			const GpuParamDesc& curDesc = **iter;
-
-			// Check regular data params
-			for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
-			{
-				bool isParameterValid = true;
-				const GpuParamDataDesc& curParam = iter2->second;
-
-				auto dataFindIter = validParams.find(iter2->first);
-				if (dataFindIter == validParams.end())
-				{
-					validParams[iter2->first] = true;
-					foundDataParams[iter2->first] = &curParam;
-				}
-				else
-				{
-					if (validParams[iter2->first])
-					{
-						auto dataFindIter2 = foundDataParams.find(iter2->first);
-
-						const GpuParamDataDesc* otherParam = dataFindIter2->second;
-						if (!areParamsEqual(curParam, *otherParam, true))
-						{
-							validParams[iter2->first] = false;
-							foundDataParams.erase(dataFindIter2);
-						}
-					}
-				}
-			}
-		}
-
-		return foundDataParams;
-	}
-
-	Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs)
-	{
-		Vector<const GpuParamObjectDesc*> validParams;
-
-		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
-		{
-			const GpuParamDesc& curDesc = **iter;
-
-			// Check sampler params
-			for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
-			{
-				validParams.push_back(&iter2->second);
-			}
-
-			// Check texture params
-			for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
-			{
-				validParams.push_back(&iter2->second);
-			}
-
-			// Check buffer params
-			for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
-			{
-				validParams.push_back(&iter2->second);
-			}
-		}
-
-		return validParams;
-	}
-
-	Set<String> determineValidShareableParamBlocks(const Vector<GpuParamDescPtr>& paramDescs)
-	{
-		// Make sure param blocks with the same name actually are the same
-		Map<String, std::pair<String, GpuParamDescPtr>> uniqueParamBlocks;
-		Map<String, bool> validParamBlocks;
-
-		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
-		{
-			const GpuParamDesc& curDesc = **iter;
-			for (auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter)
-			{
-				bool isBlockValid = true;
-				const GpuParamBlockDesc& curBlock = blockIter->second;
-
-				if (!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names
-					continue;
-
-				auto iterFind = uniqueParamBlocks.find(blockIter->first);
-				if (iterFind == uniqueParamBlocks.end())
-				{
-					uniqueParamBlocks[blockIter->first] = std::make_pair(blockIter->first, *iter);
-					validParamBlocks[blockIter->first] = true;
-					continue;
-				}
-
-				String otherBlockName = iterFind->second.first;
-				GpuParamDescPtr otherDesc = iterFind->second.second;
-
-				for (auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter)
-				{
-					const GpuParamDataDesc& myParam = myParamIter->second;
-
-					if (myParam.paramBlockSlot != curBlock.slot)
-						continue; // Param is in another block, so we will check it when its time for that block
-
-					auto otherParamFind = otherDesc->params.find(myParamIter->first);
-
-					// Cannot find other param, blocks aren't equal
-					if (otherParamFind == otherDesc->params.end())
-					{
-						isBlockValid = false;
-						break;
-					}
-
-					const GpuParamDataDesc& otherParam = otherParamFind->second;
-
-					if (!areParamsEqual(myParam, otherParam, false) || curBlock.name != otherBlockName)
-					{
-						isBlockValid = false;
-						break;
-					}
-				}
-
-				if (!isBlockValid)
-				{
-					if (validParamBlocks[blockIter->first])
-					{
-						LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first);
-						validParamBlocks[blockIter->first] = false;
-					}
-				}
-			}
-		}
-
-		Set<String> validParamBlocksReturn;
-		for (auto iter = validParamBlocks.begin(); iter != validParamBlocks.end(); ++iter)
-		{
-			if (iter->second)
-				validParamBlocksReturn.insert(iter->first);
-		}
-
-		return validParamBlocksReturn;
-	}
-
-	Map<String, String> determineParameterToBlockMapping(const Vector<GpuParamDescPtr>& paramDescs)
-	{
-		Map<String, String> paramToParamBlock;
-
-		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
-		{
-			const GpuParamDesc& curDesc = **iter;
-			for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
-			{
-				const GpuParamDataDesc& curParam = iter2->second;
-
-				auto iterFind = paramToParamBlock.find(curParam.name);
-				if (iterFind != paramToParamBlock.end())
-					continue;
-
-				for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
-				{
-					if (iterBlock->second.slot == curParam.paramBlockSlot)
-					{
-						paramToParamBlock[curParam.name] = iterBlock->second.name;
-						break;
-					}
-				}
-			}
-		}
-
-		return paramToParamBlock;
-	}
-
-	Map<String, String> determineParamMappings(const Vector<GpuParamDescPtr>& paramDescs, 
-		const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
-		const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams,
-		const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferParams,
-		const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams)
-	{
-		Map<String, String> validParams;
-
-		Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(paramDescs);
-		Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(paramDescs);
-		Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(paramDescs);
-
-		// Create data param mappings
-		for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter)
-		{
-			auto findIter = validDataParameters.find(iter->second.gpuVariableName);
-
-			// Not valid so we skip it
-			if (findIter == validDataParameters.end())
-				continue;
-
-			if (findIter->second->type != iter->second.type && !(iter->second.type == GPDT_COLOR && findIter->second->type == GPDT_FLOAT4))
-			{
-				LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. "
-					+ "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
-				continue;
-			}
-
-			if (findIter->second->arraySize != iter->second.arraySize)
-			{
-				LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program."
-					+ "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
-				continue;
-			}
-
-			auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
-
-			if (findBlockIter == paramToParamBlockMap.end())
-				BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
-
-			validParams[iter->first] = iter->second.gpuVariableName;
-		}
-
-		// Create object param mappings
-		auto determineObjectMappings = [&](const Map<String, SHADER_OBJECT_PARAM_DESC>& params)
-		{
-			for (auto iter = params.begin(); iter != params.end(); ++iter)
-			{
-				const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
-				for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
-				{
-					for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
-					{
-						if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
-						{
-							validParams[iter->first] = *iter2;
-							break;
-						}
-					}
-				}
-			}
-		};
-
-		determineObjectMappings(textureParams);
-		determineObjectMappings(samplerParams);
-		determineObjectMappings(bufferParams);
-
-		return validParams;
-	}
-
-	Vector<ShaderBlockDesc> determineShaderBlockData(const Set<String>& paramBlocks, const Vector<GpuParamDescPtr>& paramDescs,
-		const Map<String, SHADER_PARAM_BLOCK_DESC>& shaderDesc)
-	{
-		Vector<ShaderBlockDesc> output;
-		for (auto iter = paramBlocks.begin(); iter != paramBlocks.end(); ++iter)
-		{
-			ShaderBlockDesc shaderBlockDesc;
-			shaderBlockDesc.create = true;
-			shaderBlockDesc.usage = GPBU_STATIC;
-			shaderBlockDesc.size = 0;
-			shaderBlockDesc.name = *iter;
-
-			auto iterFind = shaderDesc.find(*iter);
-			if (iterFind != shaderDesc.end())
-			{
-				shaderBlockDesc.create = !iterFind->second.shared && iterFind->second.rendererSemantic == StringID::NONE;
-				shaderBlockDesc.usage = iterFind->second.usage;
-			}
-
-			for (auto iter2 = paramDescs.begin(); iter2 != paramDescs.end(); ++iter2)
-			{
-				auto findParamBlockDesc = (*iter2)->paramBlocks.find(*iter);
-
-				if (findParamBlockDesc != (*iter2)->paramBlocks.end())
-				{
-					shaderBlockDesc.size = findParamBlockDesc->second.blockSize * sizeof(UINT32);
-					break;
-				}
-			}
-
-			output.push_back(shaderBlockDesc);
-		}
-
-		return output;
-	}
-
-	template<class T>
-	bool isShaderValid(const T& shader) { return false; }
-
-	template<>
-	bool isShaderValid(const HShader& shader) { return shader.isLoaded(); }
-
-	template<>
-	bool isShaderValid(const SPtr<ShaderCore>& shader) { return shader != nullptr; }
-
-	Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<Technique>& technique)
-	{
-		Vector<GpuParamDescPtr> allParamDescs;
-
-		// Make sure all gpu programs are fully loaded
-		for (UINT32 i = 0; i < technique->getNumPasses(); i++)
-		{
-			PassPtr curPass = technique->getPass(i);
-
-			GpuProgramPtr vertProgram = curPass->getVertexProgram();
-			if (vertProgram)
-			{
-				vertProgram->blockUntilCoreInitialized();
-				allParamDescs.push_back(vertProgram->getParamDesc());
-			}
-
-			GpuProgramPtr fragProgram = curPass->getFragmentProgram();
-			if (fragProgram)
-			{
-				fragProgram->blockUntilCoreInitialized();
-				allParamDescs.push_back(fragProgram->getParamDesc());
-			}
-
-			GpuProgramPtr geomProgram = curPass->getGeometryProgram();
-			if (geomProgram)
-			{
-				geomProgram->blockUntilCoreInitialized();
-				allParamDescs.push_back(geomProgram->getParamDesc());
-			}
-
-			GpuProgramPtr hullProgram = curPass->getHullProgram();
-			if (hullProgram)
-			{
-				hullProgram->blockUntilCoreInitialized();
-				allParamDescs.push_back(hullProgram->getParamDesc());
-			}
-
-			GpuProgramPtr domainProgram = curPass->getDomainProgram();
-			if (domainProgram)
-			{
-				domainProgram->blockUntilCoreInitialized();
-				allParamDescs.push_back(domainProgram->getParamDesc());
-			}
-
-			GpuProgramPtr computeProgram = curPass->getComputeProgram();
-			if (computeProgram)
-			{
-				computeProgram->blockUntilCoreInitialized();
-				allParamDescs.push_back(computeProgram->getParamDesc());
-			}
-		}
-
-		return allParamDescs;
-	}
-
-	Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<TechniqueCore>& technique)
-	{
-		Vector<GpuParamDescPtr> allParamDescs;
-
-		// Make sure all gpu programs are fully loaded
-		for (UINT32 i = 0; i < technique->getNumPasses(); i++)
-		{
-			SPtr<PassCore> curPass = technique->getPass(i);
-
-			SPtr<GpuProgramCore> vertProgram = curPass->getVertexProgram();
-			if (vertProgram)
-				allParamDescs.push_back(vertProgram->getParamDesc());
-
-			SPtr<GpuProgramCore> fragProgram = curPass->getFragmentProgram();
-			if (fragProgram)
-				allParamDescs.push_back(fragProgram->getParamDesc());
-
-			SPtr<GpuProgramCore> geomProgram = curPass->getGeometryProgram();
-			if (geomProgram)
-				allParamDescs.push_back(geomProgram->getParamDesc());
-
-			SPtr<GpuProgramCore> hullProgram = curPass->getHullProgram();
-			if (hullProgram)
-				allParamDescs.push_back(hullProgram->getParamDesc());
-
-			SPtr<GpuProgramCore> domainProgram = curPass->getDomainProgram();
-			if (domainProgram)
-				allParamDescs.push_back(domainProgram->getParamDesc());
-
-			SPtr<GpuProgramCore> computeProgram = curPass->getComputeProgram();
-			if (computeProgram)
-				allParamDescs.push_back(computeProgram->getParamDesc());
-		}
-
-		return allParamDescs;
-	}
-
-	template<bool Core>
-	UINT32 TMaterial<Core>::getNumPasses() const
-	{
-		if (mShader == nullptr)
-			return 0;
-
-		return mShader->getBestTechnique()->getNumPasses();
-	}
-
-	template<bool Core>
-	typename TMaterial<Core>::PassType TMaterial<Core>::getPass(UINT32 passIdx) const
-	{
-		if (passIdx < 0 || passIdx >= mShader->getBestTechnique()->getNumPasses())
-			BS_EXCEPT(InvalidParametersException, "Invalid pass index.");
-
-		return mShader->getBestTechnique()->getPass(passIdx);
-	}
-
-	template<bool Core>
-	TMaterialParamStruct<Core> TMaterial<Core>::getParamStruct(const String& name) const
-	{
-		throwIfNotInitialized();
-
-		auto iterFind = mValidParams.find(name);
-		if (iterFind == mValidParams.end())
-		{
-			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
-			return TMaterialParamStruct<Core>();
-		}
-
-		const String& gpuVarName = iterFind->second;
-		SPtr<Vector<TGpuParamStruct<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamStruct<Core>>>();
-
-		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-		{
-			SPtr<PassParamsType> params = *iter;
-
-			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-			{
-				GpuParamsType& paramPtr = params->getParamByIdx(i);
-				if (paramPtr)
-				{
-					if (paramPtr->hasParam(gpuVarName))
-					{
-						gpuParams->push_back(TGpuParamStruct<Core>());
-						paramPtr->getStructParam(gpuVarName, gpuParams->back());
-					}
-				}
-			}
-		}
-
-		return TMaterialParamStruct<Core>(gpuParams);
-	}
-
-	template<bool Core>
-	TMaterialParamTexture<Core> TMaterial<Core>::getParamTexture(const String& name) const
-	{
-		throwIfNotInitialized();
-
-		auto iterFind = mValidParams.find(name);
-		if (iterFind == mValidParams.end())
-		{
-			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
-			return TMaterialParamTexture<Core>();
-		}
-
-		const String& gpuVarName = iterFind->second;
-		SPtr<Vector<TGpuParamTexture<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamTexture<Core>>>();
-
-		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-		{
-			SPtr<PassParamsType> params = *iter;
-
-			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-			{
-				GpuParamsType& paramPtr = params->getParamByIdx(i);
-				if (paramPtr)
-				{
-					if (paramPtr->hasTexture(gpuVarName))
-					{
-						gpuParams->push_back(TGpuParamTexture<Core>());
-						paramPtr->getTextureParam(gpuVarName, gpuParams->back());
-					}
-				}
-			}
-		}
-
-		return TMaterialParamTexture<Core>(gpuParams);
-	}
-
-	template<bool Core>
-	TMaterialParamLoadStoreTexture<Core> TMaterial<Core>::getParamLoadStoreTexture(const String& name) const
-	{
-		throwIfNotInitialized();
-
-		auto iterFind = mValidParams.find(name);
-		if (iterFind == mValidParams.end())
-		{
-			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
-			return TMaterialParamLoadStoreTexture<Core>();
-		}
-
-		const String& gpuVarName = iterFind->second;
-		SPtr<Vector<TGpuParamLoadStoreTexture<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamLoadStoreTexture<Core>>>();
-
-		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-		{
-			SPtr<PassParamsType> params = *iter;
-
-			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-			{
-				GpuParamsType& paramPtr = params->getParamByIdx(i);
-				if (paramPtr)
-				{
-					if (paramPtr->hasTexture(gpuVarName))
-					{
-						gpuParams->push_back(TGpuParamLoadStoreTexture<Core>());
-						paramPtr->getLoadStoreTextureParam(gpuVarName, gpuParams->back());
-					}
-				}
-			}
-		}
-
-		return TMaterialParamLoadStoreTexture<Core>(gpuParams);
-	}
-
-	template<bool Core>
-	TMaterialParamSampState<Core> TMaterial<Core>::getParamSamplerState(const String& name) const
-	{
-		throwIfNotInitialized();
-
-		auto iterFind = mValidParams.find(name);
-		if (iterFind == mValidParams.end())
-		{
-			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
-			return TMaterialParamSampState<Core>();
-		}
-
-		const String& gpuVarName = iterFind->second;
-		SPtr<Vector<TGpuParamSampState<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamSampState<Core>>>();
-		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-		{
-			SPtr<PassParamsType> params = *iter;
-
-			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-			{
-				GpuParamsType& paramPtr = params->getParamByIdx(i);
-				if (paramPtr)
-				{
-					if (paramPtr->hasSamplerState(gpuVarName))
-					{
-						gpuParams->push_back(TGpuParamSampState<Core>());
-						paramPtr->getSamplerStateParam(gpuVarName, gpuParams->back());
-					}
-				}
-			}
-		}
-
-		return TMaterialParamSampState<Core>(gpuParams);
-	}
-
-	template<bool Core>
-	void TMaterial<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock)
-	{
-		auto iterFind = mValidShareableParamBlocks.find(name);
-		if (iterFind == mValidShareableParamBlocks.end())
-		{
-			LOGWRN_VERBOSE("Material doesn't have a parameter block named " + name);
-			return;
-		}
-
-		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-		{
-			SPtr<PassParamsType> params = *iter;
-
-			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-			{
-				GpuParamsType& paramPtr = params->getParamByIdx(i);
-				if (paramPtr)
-				{
-					if (paramPtr->hasParamBlock(name))
-						paramPtr->setParamBlockBuffer(name, paramBlock);
-				}
-			}
-		}
-	}
-
-	template<bool Core>
-	void TMaterial<Core>::initBestTechnique()
-	{
-		mBestTechnique = nullptr;
-		mParametersPerPass.clear();
-
-		if (isShaderValid(mShader))
-		{
-			mBestTechnique = mShader->getBestTechnique();
-
-			if (mBestTechnique == nullptr)
-				return;
-
-			mValidShareableParamBlocks.clear();
-			Vector<GpuParamDescPtr> allParamDescs = getAllParamDescs(mBestTechnique);
-
-			mValidParams = determineParamMappings(allParamDescs, mShader->getDataParams(), mShader->getTextureParams(),
-				mShader->getBufferParams(), mShader->getSamplerParams());
-
-			// Fill out various helper structures
-			Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
-			Vector<ShaderBlockDesc> paramBlockData = determineShaderBlockData(validShareableParamBlocks, allParamDescs, mShader->getParamBlocks());
-
-			Map<String, ParamBlockPtrType> paramBlockBuffers;
-
-			// Create param blocks
-			for (auto& paramBlock : paramBlockData)
-			{
-				ParamBlockPtrType newParamBlockBuffer;
-				if (paramBlock.create)
-				{
-					newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
-				}
-
-				paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
-				mValidShareableParamBlocks.insert(paramBlock.name);
-			}
-
-			for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
-			{
-				PassType curPass = mBestTechnique->getPass(i);
-				SPtr<PassParamsType> params = SPtr<PassParamsType>(new PassParamsType());
-
-				GpuProgramType vertProgram = curPass->getVertexProgram();
-				if (vertProgram)
-					params->mVertParams = vertProgram->createParameters();
-
-				GpuProgramType fragProgram = curPass->getFragmentProgram();
-				if (fragProgram)
-					params->mFragParams = fragProgram->createParameters();
-
-				GpuProgramType geomProgram = curPass->getGeometryProgram();
-				if (geomProgram)
-					params->mGeomParams = geomProgram->createParameters();
-
-				GpuProgramType hullProgram = curPass->getHullProgram();
-				if (hullProgram)
-					params->mHullParams = hullProgram->createParameters();
-
-				GpuProgramType domainProgram = curPass->getDomainProgram();
-				if (domainProgram)
-					params->mDomainParams = domainProgram->createParameters();
-
-				GpuProgramType computeProgram = curPass->getComputeProgram();
-				if (computeProgram)
-					params->mComputeParams = computeProgram->createParameters();
-
-				mParametersPerPass.push_back(params);
-			}
-
-			// Assign param block buffers
-			for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-			{
-				SPtr<PassParamsType> params = *iter;
-
-				for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-				{
-					GpuParamsType& paramPtr = params->getParamByIdx(i);
-					if (paramPtr)
-					{
-						// Assign shareable buffers
-						for (auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock)
-						{
-							const String& paramBlockName = *iterBlock;
-							if (paramPtr->hasParamBlock(paramBlockName))
-							{
-								ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
-
-								paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
-							}
-						}
-
-						// Create non-shareable ones
-						const GpuParamDesc& desc = paramPtr->getParamDesc();
-						for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
-						{
-							if (!iterBlockDesc->second.isShareable)
-							{
-								ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32));
-
-								paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
-							}
-						}
-					}
-				}
-			}
-
-			// Assign default parameters
-			initDefaultParameters();
-		}
-
-		_markDependenciesDirty();
-	}
-
-	template <bool Core>
-	template <typename T>
-	void TMaterial<Core>::setParamValue(const String& name, UINT8* buffer, UINT32 numElements)
-	{
-		TMaterialDataParam<T, Core> param;
-		getParam(name, param);
-
-		T* ptr = (T*)buffer;
-		for (UINT32 i = 0; i < numElements; i++)
-			param.set(ptr[i], i);
-	}
-
-	template <bool Core>
-	void TMaterial<Core>::initDefaultParameters()
-	{
-		const Map<String, SHADER_DATA_PARAM_DESC>& dataParams = mShader->getDataParams();
-		for (auto& paramData : dataParams)
-		{
-			if (paramData.second.defaultValueIdx == (UINT32)-1)
-				continue;
-
-			auto iterFind = mValidParams.find(paramData.first);
-			if (iterFind == mValidParams.end())
-				continue;
-			
-			UINT8* buffer = (UINT8*)mShader->getDefaultValue(paramData.second.defaultValueIdx);
-			if (buffer == nullptr)
-				continue;
-
-			switch (paramData.second.type)
-			{
-			case GPDT_FLOAT1: 
-				setParamValue<float>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_FLOAT2:
-				setParamValue<Vector2>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_FLOAT3:
-				setParamValue<Vector3>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_FLOAT4:
-				setParamValue<Vector4>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_2X2:
-				setParamValue<Matrix2>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_2X3:
-				setParamValue<Matrix2x3>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_2X4:
-				setParamValue<Matrix2x4>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_3X2:
-				setParamValue<Matrix3x2>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_3X3:
-				setParamValue<Matrix3>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_3X4:
-				setParamValue<Matrix3x4>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_4X2:
-				setParamValue<Matrix4x2>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_4X3:
-				setParamValue<Matrix4x3>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_MATRIX_4X4:
-				setParamValue<Matrix4>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_INT1:
-				setParamValue<int>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_INT2:
-				setParamValue<Vector2I>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_INT3:
-				setParamValue<Vector3I>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_INT4:
-				setParamValue<Vector4I>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_BOOL:
-				setParamValue<int>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_COLOR:
-				setParamValue<Color>(iterFind->first, buffer, paramData.second.arraySize);
-				break;
-			case GPDT_STRUCT:
-			{
-				TMaterialParamStruct<Core> param = getParamStruct(paramData.first);
-
-				UINT32 elementSizeBytes = paramData.second.elementSize * sizeof(UINT32);
-				UINT8* ptr = buffer;
-				for (UINT32 i = 0; i < paramData.second.arraySize; i++)
-				{
-					param.set(ptr, elementSizeBytes, i);
-					ptr += elementSizeBytes;
-				}
-			}
-			break;
-			}
-		}
-
-		const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams = mShader->getTextureParams();
-		for (auto& param : textureParams)
-		{
-			if (param.second.defaultValueIdx == (UINT32)-1)
-				continue;
-
-			auto iterFind = mValidParams.find(param.first);
-			if (iterFind == mValidParams.end())
-				continue;
-
-			TextureType defaultTex = mShader->getDefaultTexture(param.second.defaultValueIdx);
-			getParamTexture(param.first).set(defaultTex);
-		}
-
-		const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams = mShader->getSamplerParams();
-		for (auto& param : samplerParams)
-		{
-			if (param.second.defaultValueIdx == (UINT32)-1)
-				continue;
-
-			auto iterFind = mValidParams.find(param.first);
-			if (iterFind == mValidParams.end())
-				continue;
-
-			SamplerStateType defaultSampler = mShader->getDefaultSampler(param.second.defaultValueIdx);
-			getParamSamplerState(param.first).set(defaultSampler);
-		}
-	}
-
-	template <bool Core>
-	template <typename T>
-	void TMaterial<Core>::getParam(const String& name, TMaterialDataParam<T, Core>& output) const
-	{
-		throwIfNotInitialized();
-
-		auto iterFind = mValidParams.find(name);
-		if (iterFind == mValidParams.end())
-		{
-			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
-			return;
-		}
-
-		const String& gpuVarName = iterFind->second;
-		SPtr<Vector<TGpuDataParam<T, Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuDataParam<T, Core>>>();
-
-		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
-		{
-			SPtr<PassParamsType> params = *iter;
-
-			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
-			{
-				GpuParamsType& paramPtr = params->getParamByIdx(i);
-				if (paramPtr)
-				{
-					if (paramPtr->hasParam(gpuVarName))
-					{
-						gpuParams->push_back(TGpuDataParam<T, Core>());
-						paramPtr->getParam<T>(gpuVarName, gpuParams->back());
-					}
-				}
-			}
-		}
-
-		output = TMaterialDataParam<T, Core>(gpuParams);
-	}
-
-	template<bool Core>
-	void TMaterial<Core>::throwIfNotInitialized() const
-	{
-		if (mShader == nullptr)
-		{
-			BS_EXCEPT(InternalErrorException, "Material does not have shader set.");
-		}
-
-		if (mBestTechnique == nullptr)
-		{
-			BS_EXCEPT(InternalErrorException, "Shader does not contain a supported technique.");
-		}
-	}
-
-	template class TMaterial < false > ;
-	template class TMaterial < true > ;
-
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<float, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<int, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Color, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector2, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector3, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector4, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector2I, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector3I, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector4I, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix2, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix2x3, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix2x4, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3x2, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3x4, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4x2, false>&) const;
-	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4x3, false>&) const;
-
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<float, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<int, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Color, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector2, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector3, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector4, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector2I, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector3I, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector4I, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix2, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix2x3, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix2x4, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3x2, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3x4, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4x2, true>&) const;
-	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4x3, true>&) const;
-
-	MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader)
-	{
-		setShader(shader);
-	}
-
-	MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader, const SPtr<TechniqueCore>& bestTechnique,
-		const Set<String>& validShareableParamBlocks, const Map<String, String>& validParams,
-		const Vector<SPtr<PassParametersCore>>& passParams)
-	{
-		mShader = shader;
-		mBestTechnique = bestTechnique;
-		mValidShareableParamBlocks = validShareableParamBlocks;
-		mValidParams = validParams;
-
-		UINT32 numPassParams = (UINT32)passParams.size();
-		mParametersPerPass.resize(numPassParams);
-		for (UINT32 i = 0; i < numPassParams; i++)
-			mParametersPerPass[i] = passParams[i];
-	}
-
-	void MaterialCore::setShader(const SPtr<ShaderCore>& shader)
-	{
-		mShader = shader;
-
-		initBestTechnique();
-
-		_markCoreDirty();
-	}
-
-	void MaterialCore::syncToCore(const CoreSyncData& data)
-	{
-		char* dataPtr = (char*)data.getBuffer();
-
-		mValidShareableParamBlocks.clear();
-		mValidParams.clear();
-		mParametersPerPass.clear();
-
-		UINT32 numPasses = 0;
-
-		dataPtr = rttiReadElem(mValidShareableParamBlocks, dataPtr);
-		dataPtr = rttiReadElem(mValidParams, dataPtr);
-		dataPtr = rttiReadElem(numPasses, dataPtr);
-
-		for (UINT32 i = 0; i < numPasses; i++)
-		{
-			SPtr<PassParametersCore>* passParameters = (SPtr<PassParametersCore>*)dataPtr;
-
-			mParametersPerPass.push_back(*passParameters);
-
-			passParameters->~SPtr<PassParametersCore>();
-			dataPtr += sizeof(SPtr<PassParametersCore>);
-		}
-
-		SPtr<ShaderCore>* shader = (SPtr<ShaderCore>*)dataPtr;
-		mShader = *shader;
-		shader->~SPtr<ShaderCore>();
-		dataPtr += sizeof(SPtr<ShaderCore>);
-
-		SPtr<TechniqueCore>* technique = (SPtr<TechniqueCore>*)dataPtr;
-		mBestTechnique = *technique;
-		technique->~SPtr<TechniqueCore>();
-		dataPtr += sizeof(SPtr<TechniqueCore>);
-	}
-
-	SPtr<MaterialCore> MaterialCore::create(const SPtr<ShaderCore>& shader)
-	{
-		MaterialCore* material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
-		SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore>(material);
-		materialPtr->_setThisPtr(materialPtr);
-		materialPtr->initialize();
-
-		return materialPtr;
-	}
-
-	Material::Material()
-		:mLoadFlags(Load_None)
-	{ }
-
-	Material::Material(const HShader& shader)
-		:mLoadFlags(Load_None)
-	{
-		mShader = shader;
-	}
-
-	void Material::initialize()
-	{
-		setShader(mShader); // Not calling directly in constructor because it calls virtual methods
-
-		Resource::initialize();
-	}
-
-	void Material::setShader(const HShader& shader)
-	{
-		//if (mShader == shader)
-		//	return;
-
-		mShader = shader;
-		mBestTechnique = nullptr;
-		mLoadFlags = Load_None;
-		_markResourcesDirty();
-
-		initializeIfLoaded();
-	}
-
-	void Material::_markCoreDirty()
-	{
-		markCoreDirty();
-	}
-
-	void Material::_markDependenciesDirty()
-	{
-		markDependenciesDirty();
-	}
-
-	void Material::_markResourcesDirty()
-	{
-		markListenerResourcesDirty();
-	}
-
-	SPtr<MaterialCore> Material::getCore() const
-	{
-		return std::static_pointer_cast<MaterialCore>(mCoreSpecific);
-	}
-
-	SPtr<CoreObjectCore> Material::createCore() const
-	{
-		MaterialCore* material = nullptr;
-
-		SPtr<ShaderCore> shader;
-		if (mShader.isLoaded())
-		{
-			shader = mShader->getCore();
-
-			if (mBestTechnique != nullptr)
-			{
-				SPtr<TechniqueCore> technique = mBestTechnique->getCore();
-
-				Vector<SPtr<PassParametersCore>> passParams;
-				for (auto& passParam : mParametersPerPass)
-					passParams.push_back(convertParamsToCore(passParam));
-
-				material = new (bs_alloc<MaterialCore>()) MaterialCore(shader, technique, mValidShareableParamBlocks, mValidParams, passParams);
-			}
-		}
-		
-		if (material == nullptr)
-			material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
-
-		SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore>(material);
-		materialPtr->_setThisPtr(materialPtr);
-
-		return materialPtr;
-	}
-
-	CoreSyncData Material::syncToCore(FrameAlloc* allocator)
-	{
-		UINT32 numPasses = (UINT32)mParametersPerPass.size();
-
-		UINT32 size = sizeof(UINT32) + numPasses * sizeof(SPtr<PassParametersCore>)
-			+ sizeof(SPtr<ShaderCore>) + sizeof(SPtr<TechniqueCore>) + rttiGetElemSize(mValidShareableParamBlocks)
-			+ rttiGetElemSize(mValidParams);
-
-		UINT8* buffer = allocator->alloc(size);
-		char* dataPtr = (char*)buffer;
-		dataPtr = rttiWriteElem(mValidShareableParamBlocks, dataPtr);
-		dataPtr = rttiWriteElem(mValidParams, dataPtr);
-		dataPtr = rttiWriteElem(numPasses, dataPtr);
-
-		for (UINT32 i = 0; i < numPasses; i++)
-		{
-			SPtr<PassParametersCore>* passParameters = new (dataPtr) SPtr<PassParametersCore>();
-			*passParameters = convertParamsToCore(mParametersPerPass[i]);
-
-			dataPtr += sizeof(SPtr<PassParametersCore>);
-		}
-
-		SPtr<ShaderCore>* shader = new (dataPtr)SPtr<ShaderCore>();
-		if (mShader.isLoaded(false))
-			*shader = mShader->getCore();
-		else
-			*shader = nullptr;
-
-		dataPtr += sizeof(SPtr<ShaderCore>);
-
-		SPtr<TechniqueCore>* technique = new (dataPtr)SPtr<TechniqueCore>();
-		if (mBestTechnique != nullptr)
-			*technique = mBestTechnique->getCore();
-		else
-			*technique = nullptr;
-
-		dataPtr += sizeof(SPtr<TechniqueCore>);
-
-		return CoreSyncData(buffer, size);
-	}
-
-	void Material::getCoreDependencies(Vector<CoreObject*>& dependencies)
-	{
-		if (mShader.isLoaded())
-			dependencies.push_back(mShader.get());
-
-		for (auto& params : mParametersPerPass)
-		{
-			for (UINT32 i = 0; i < PassParameters::NUM_PARAMS; i++)
-			{
-				GpuParamsPtr gpuParams = params->getParamByIdx(i);
-				if (gpuParams != nullptr)
-					dependencies.push_back(gpuParams.get());
-			}
-		}
-	}
-
-	void Material::getListenerResources(Vector<HResource>& resources)
-	{
-		if (mShader != nullptr)
-			resources.push_back(mShader);
-	}
-
-	void Material::getResourceDependencies(FrameVector<HResource>& dependencies) const
-	{
-		if (mShader != nullptr)
-			dependencies.push_back(mShader);
-
-		if (mShader.isLoaded())
-		{
-			const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams = mShader->getTextureParams();
-
-			for (auto& param : textureParams)
-			{
-				if (param.second.defaultValueIdx != (UINT32)-1)
-				{
-					HTexture defaultTex = mShader->getDefaultTexture(param.second.defaultValueIdx);
-					if (defaultTex != nullptr)
-						dependencies.push_back(defaultTex);
-				}
-			}
-		}
-	}
-
-	void Material::initializeIfLoaded()
-	{
-		if (areDependenciesLoaded())
-		{
-			if (mLoadFlags != Load_All)
-			{
-				mLoadFlags = Load_All;
-
-				initBestTechnique();
-				markCoreDirty();
-			}
-		}
-		else
-		{
-			if (mShader.isLoaded() && mLoadFlags == Load_None)
-			{
-				mLoadFlags = Load_Shader;
-				markListenerResourcesDirty(); // Need to register resources dependent on shader now
-			}
-		}
-	}
-
-	void Material::notifyResourceLoaded(const HResource& resource)
-	{
-		initializeIfLoaded();
-	}
-
-	template<class T>
-	void copyParam(SPtr<GpuParams>& from, SPtr<GpuParams>& to, const String& name, UINT32 arraySize)
-	{
-		TGpuDataParam<T, false> newParam;
-		to->getParam(name, newParam);
-
-		TGpuDataParam<T, false> oldParam;
-		from->getParam(name, oldParam);
-
-		for (UINT32 i = 0; i < arraySize; i++)
-			newParam.set(oldParam.get(i), i);
-	}
-
-	void Material::notifyResourceChanged(const HResource& resource)
-	{
-		// Shader changed, so save parameters, rebuild material and restore parameters
-		Vector<SPtr<PassParameters>> oldPassParams = mParametersPerPass;
-
-		mLoadFlags = Load_None;
-		initializeIfLoaded();
-
-		for (UINT32 i = 0; i < (UINT32)oldPassParams.size(); i++)
-		{
-			if (i >= (UINT32)mParametersPerPass.size())
-				continue;
-
-			SPtr<PassParameters> oldParams = oldPassParams[i];
-			SPtr<PassParameters> newParams = mParametersPerPass[i];
-
-			for (UINT32 j = 0; j < PassParameters::NUM_PARAMS; j++)
-			{
-				SPtr<GpuParams>& oldGpuParams = oldParams->getParamByIdx(j);
-				SPtr<GpuParams>& newGpuParams = newParams->getParamByIdx(j);
-				if (oldGpuParams == nullptr || newGpuParams == nullptr)
-					continue;
-
-				const GpuParamDesc& oldDesc = oldGpuParams->getParamDesc();
-				const GpuParamDesc& newDesc = newGpuParams->getParamDesc();
-
-				for (auto& param : oldDesc.params)
-				{
-					auto iterFind = newDesc.params.find(param.first);
-					if (iterFind == newDesc.params.end())
-						continue;
-
-					if (param.second.type != iterFind->second.type)
-						continue;
-
-					UINT32 arraySize = std::min(param.second.arraySize, iterFind->second.arraySize);
-					
-					switch (param.second.type)
-					{
-					case GPDT_FLOAT1:
-						copyParam<float>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_FLOAT2:
-						copyParam<Vector2>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_FLOAT3:
-						copyParam<Vector3>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_FLOAT4:
-						copyParam<Vector4>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_2X2:
-						copyParam<Matrix2>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_2X3:
-						copyParam<Matrix2x3>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_2X4:
-						copyParam<Matrix2x4>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_3X2:
-						copyParam<Matrix3x2>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_3X3:
-						copyParam<Matrix3>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_3X4:
-						copyParam<Matrix3x4>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_4X2:
-						copyParam<Matrix4x2>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_4X3:
-						copyParam<Matrix4x3>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_MATRIX_4X4:
-						copyParam<Matrix4>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_INT1:
-					case GPDT_BOOL:
-						copyParam<int>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_INT2:
-						copyParam<Vector2I>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_INT3:
-						copyParam<Vector3I>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_INT4:
-						copyParam<Vector4I>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_COLOR:
-						copyParam<Color>(oldGpuParams, newGpuParams, param.first, arraySize);
-						break;
-					case GPDT_STRUCT:
-					{
-						GpuParamStruct newParam;
-						newGpuParams->getStructParam(param.first, newParam);
-
-						GpuParamStruct oldParam;
-						oldGpuParams->getStructParam(param.first, oldParam);
-
-						if (param.second.elementSize == iterFind->second.elementSize)
-						{
-							for (UINT32 k = 0; k < arraySize; k++)
-							{
-								UINT8* data = (UINT8*)bs_stack_alloc(param.second.elementSize);
-								oldParam.get(data, param.second.elementSize, k);
-								newParam.set(data, param.second.elementSize, k);
-								bs_stack_free(data);
-							}
-						}
-					}
-					break;
-					}
-				}
-
-				for (auto& param : oldDesc.textures)
-				{
-					auto iterFind = newDesc.textures.find(param.first);
-					if (iterFind == newDesc.textures.end())
-						continue;
-
-					UINT32 oldSlot = param.second.slot;
-					UINT32 newSlot = iterFind->second.slot;
-
-					bool isLoadStore = oldGpuParams->isLoadStoreTexture(oldSlot);
-
-					if (!isLoadStore)
-						newGpuParams->setTexture(newSlot, oldGpuParams->getTexture(oldSlot));
-					else
-					{
-						newGpuParams->setIsLoadStoreTexture(newSlot, true);
-						newGpuParams->setLoadStoreSurface(newSlot, oldGpuParams->getLoadStoreSurface(oldSlot));
-					}
-				}
-
-				for (auto& param : oldDesc.samplers)
-				{
-					auto iterFind = newDesc.samplers.find(param.first);
-					if (iterFind == newDesc.samplers.end())
-						continue;
-
-					newGpuParams->setSamplerState(iterFind->second.slot, oldGpuParams->getSamplerState(param.second.slot));
-				}
-			}
-		}
-	}
-
-	HMaterial Material::clone()
-	{
-		UINT32 bufferSize = 0;
-
-		MemorySerializer serializer;
-		UINT8* buffer = serializer.encode(this, bufferSize, (void*(*)(UINT32))&bs_alloc);
-
-		std::shared_ptr<Material> cloneObj = std::static_pointer_cast<Material>(serializer.decode(buffer, bufferSize));
-		bs_free(buffer);
-
-		return static_resource_cast<Material>(gResources()._createResourceHandle(cloneObj));
-	}
-
-	HMaterial Material::create()
-	{
-		MaterialPtr materialPtr = MaterialManager::instance().create();
-
-		return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
-	}
-
-	HMaterial Material::create(const HShader& shader)
-	{
-		MaterialPtr materialPtr = MaterialManager::instance().create(shader);
-
-		return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
-	}
-
-	RTTITypeBase* Material::getRTTIStatic()
-	{
-		return MaterialRTTI::instance();
-	}
-
-	RTTITypeBase* Material::getRTTI() const
-	{
-		return Material::getRTTIStatic();
-	}
+#include "BsMaterial.h"
+#include "BsException.h"
+#include "BsShader.h"
+#include "BsTechnique.h"
+#include "BsPass.h"
+#include "BsRenderAPI.h"
+#include "BsHardwareBufferManager.h"
+#include "BsGpuProgram.h"
+#include "BsGpuParamBlockBuffer.h"
+#include "BsGpuParamDesc.h"
+#include "BsMaterialRTTI.h"
+#include "BsMaterialManager.h"
+#include "BsDebug.h"
+#include "BsResources.h"
+#include "BsFrameAlloc.h"
+#include "BsMatrixNxM.h"
+#include "BsVectorNI.h"
+#include "BsMemorySerializer.h"
+#include "BsMaterialParams.h"
+
+namespace BansheeEngine
+{
+	struct ShaderBlockDesc
+	{
+		String name;
+		GpuParamBlockUsage usage;
+		int size;
+		bool create;
+	};
+
+	enum MaterialLoadFlags
+	{
+		Load_None	= 0,
+		Load_Shader	= 1,
+		Load_All	= 2
+	};
+
+	const UINT32 PassParameters::NUM_PARAMS = 6;
+	const UINT32 PassParametersCore::NUM_PARAMS = 6;
+	
+	SPtr<PassParametersCore> convertParamsToCore(const SPtr<PassParameters>& passParams)
+	{
+		SPtr<PassParametersCore> passParameters = bs_shared_ptr_new<PassParametersCore>();
+
+		if (passParams->mVertParams != nullptr)
+			passParameters->mVertParams = passParams->mVertParams->getCore();
+		else
+			passParameters->mVertParams = nullptr;
+
+		if (passParams->mFragParams != nullptr)
+			passParameters->mFragParams = passParams->mFragParams->getCore();
+		else
+			passParameters->mFragParams = nullptr;
+
+		if (passParams->mGeomParams != nullptr)
+			passParameters->mGeomParams = passParams->mGeomParams->getCore();
+		else
+			passParameters->mGeomParams = nullptr;
+
+		if (passParams->mHullParams != nullptr)
+			passParameters->mHullParams = passParams->mHullParams->getCore();
+		else
+			passParameters->mHullParams = nullptr;
+
+		if (passParams->mDomainParams != nullptr)
+			passParameters->mDomainParams = passParams->mDomainParams->getCore();
+		else
+			passParameters->mDomainParams = nullptr;
+
+		if (passParams->mComputeParams != nullptr)
+			passParameters->mComputeParams = passParams->mComputeParams->getCore();
+		else
+			passParameters->mComputeParams = nullptr;
+
+		return passParameters;
+	}
+
+	bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets)
+	{
+		bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize
+			&& paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride;
+
+		if (!ignoreBufferOffsets)
+			equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset;
+
+		return equal;
+	}
+
+	Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<GpuParamDescPtr>& paramDescs)
+	{
+		Map<String, const GpuParamDataDesc*> foundDataParams;
+		Map<String, bool> validParams;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+
+			// Check regular data params
+			for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
+			{
+				bool isParameterValid = true;
+				const GpuParamDataDesc& curParam = iter2->second;
+
+				auto dataFindIter = validParams.find(iter2->first);
+				if (dataFindIter == validParams.end())
+				{
+					validParams[iter2->first] = true;
+					foundDataParams[iter2->first] = &curParam;
+				}
+				else
+				{
+					if (validParams[iter2->first])
+					{
+						auto dataFindIter2 = foundDataParams.find(iter2->first);
+
+						const GpuParamDataDesc* otherParam = dataFindIter2->second;
+						if (!areParamsEqual(curParam, *otherParam, true))
+						{
+							validParams[iter2->first] = false;
+							foundDataParams.erase(dataFindIter2);
+						}
+					}
+				}
+			}
+		}
+
+		return foundDataParams;
+	}
+
+	Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs)
+	{
+		Vector<const GpuParamObjectDesc*> validParams;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+
+			// Check sampler params
+			for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+
+			// Check texture params
+			for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+
+			// Check buffer params
+			for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+		}
+
+		return validParams;
+	}
+
+	Set<String> determineValidShareableParamBlocks(const Vector<GpuParamDescPtr>& paramDescs)
+	{
+		// Make sure param blocks with the same name actually are the same
+		Map<String, std::pair<String, GpuParamDescPtr>> uniqueParamBlocks;
+		Map<String, bool> validParamBlocks;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+			for (auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter)
+			{
+				bool isBlockValid = true;
+				const GpuParamBlockDesc& curBlock = blockIter->second;
+
+				if (!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names
+					continue;
+
+				auto iterFind = uniqueParamBlocks.find(blockIter->first);
+				if (iterFind == uniqueParamBlocks.end())
+				{
+					uniqueParamBlocks[blockIter->first] = std::make_pair(blockIter->first, *iter);
+					validParamBlocks[blockIter->first] = true;
+					continue;
+				}
+
+				String otherBlockName = iterFind->second.first;
+				GpuParamDescPtr otherDesc = iterFind->second.second;
+
+				for (auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter)
+				{
+					const GpuParamDataDesc& myParam = myParamIter->second;
+
+					if (myParam.paramBlockSlot != curBlock.slot)
+						continue; // Param is in another block, so we will check it when its time for that block
+
+					auto otherParamFind = otherDesc->params.find(myParamIter->first);
+
+					// Cannot find other param, blocks aren't equal
+					if (otherParamFind == otherDesc->params.end())
+					{
+						isBlockValid = false;
+						break;
+					}
+
+					const GpuParamDataDesc& otherParam = otherParamFind->second;
+
+					if (!areParamsEqual(myParam, otherParam, false) || curBlock.name != otherBlockName)
+					{
+						isBlockValid = false;
+						break;
+					}
+				}
+
+				if (!isBlockValid)
+				{
+					if (validParamBlocks[blockIter->first])
+					{
+						LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first);
+						validParamBlocks[blockIter->first] = false;
+					}
+				}
+			}
+		}
+
+		Set<String> validParamBlocksReturn;
+		for (auto iter = validParamBlocks.begin(); iter != validParamBlocks.end(); ++iter)
+		{
+			if (iter->second)
+				validParamBlocksReturn.insert(iter->first);
+		}
+
+		return validParamBlocksReturn;
+	}
+
+	Map<String, String> determineParameterToBlockMapping(const Vector<GpuParamDescPtr>& paramDescs)
+	{
+		Map<String, String> paramToParamBlock;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+			for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
+			{
+				const GpuParamDataDesc& curParam = iter2->second;
+
+				auto iterFind = paramToParamBlock.find(curParam.name);
+				if (iterFind != paramToParamBlock.end())
+					continue;
+
+				for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
+				{
+					if (iterBlock->second.slot == curParam.paramBlockSlot)
+					{
+						paramToParamBlock[curParam.name] = iterBlock->second.name;
+						break;
+					}
+				}
+			}
+		}
+
+		return paramToParamBlock;
+	}
+
+	Map<String, String> determineParamMappings(const Vector<GpuParamDescPtr>& paramDescs, 
+		const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams,
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferParams,
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams)
+	{
+		Map<String, String> validParams;
+
+		Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(paramDescs);
+		Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(paramDescs);
+		Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(paramDescs);
+
+		// Create data param mappings
+		for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter)
+		{
+			auto findIter = validDataParameters.find(iter->second.gpuVariableName);
+
+			// Not valid so we skip it
+			if (findIter == validDataParameters.end())
+				continue;
+
+			if (findIter->second->type != iter->second.type && !(iter->second.type == GPDT_COLOR && findIter->second->type == GPDT_FLOAT4))
+			{
+				LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. "
+					+ "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
+				continue;
+			}
+
+			if (findIter->second->arraySize != iter->second.arraySize)
+			{
+				LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program."
+					+ "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
+				continue;
+			}
+
+			auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
+
+			if (findBlockIter == paramToParamBlockMap.end())
+				BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
+
+			validParams[iter->first] = iter->second.gpuVariableName;
+		}
+
+		// Create object param mappings
+		auto determineObjectMappings = [&](const Map<String, SHADER_OBJECT_PARAM_DESC>& params)
+		{
+			for (auto iter = params.begin(); iter != params.end(); ++iter)
+			{
+				const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
+				for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
+				{
+					for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
+					{
+						if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
+						{
+							validParams[iter->first] = *iter2;
+							break;
+						}
+					}
+				}
+			}
+		};
+
+		determineObjectMappings(textureParams);
+		determineObjectMappings(samplerParams);
+		determineObjectMappings(bufferParams);
+
+		return validParams;
+	}
+
+	Vector<ShaderBlockDesc> determineShaderBlockData(const Set<String>& paramBlocks, const Vector<GpuParamDescPtr>& paramDescs,
+		const Map<String, SHADER_PARAM_BLOCK_DESC>& shaderDesc)
+	{
+		Vector<ShaderBlockDesc> output;
+		for (auto iter = paramBlocks.begin(); iter != paramBlocks.end(); ++iter)
+		{
+			ShaderBlockDesc shaderBlockDesc;
+			shaderBlockDesc.create = true;
+			shaderBlockDesc.usage = GPBU_STATIC;
+			shaderBlockDesc.size = 0;
+			shaderBlockDesc.name = *iter;
+
+			auto iterFind = shaderDesc.find(*iter);
+			if (iterFind != shaderDesc.end())
+			{
+				shaderBlockDesc.create = !iterFind->second.shared && iterFind->second.rendererSemantic == StringID::NONE;
+				shaderBlockDesc.usage = iterFind->second.usage;
+			}
+
+			for (auto iter2 = paramDescs.begin(); iter2 != paramDescs.end(); ++iter2)
+			{
+				auto findParamBlockDesc = (*iter2)->paramBlocks.find(*iter);
+
+				if (findParamBlockDesc != (*iter2)->paramBlocks.end())
+				{
+					shaderBlockDesc.size = findParamBlockDesc->second.blockSize * sizeof(UINT32);
+					break;
+				}
+			}
+
+			output.push_back(shaderBlockDesc);
+		}
+
+		return output;
+	}
+
+	template<class T>
+	bool isShaderValid(const T& shader) { return false; }
+
+	template<>
+	bool isShaderValid(const HShader& shader) { return shader.isLoaded(); }
+
+	template<>
+	bool isShaderValid(const SPtr<ShaderCore>& shader) { return shader != nullptr; }
+
+	Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<Technique>& technique)
+	{
+		Vector<GpuParamDescPtr> allParamDescs;
+
+		// Make sure all gpu programs are fully loaded
+		for (UINT32 i = 0; i < technique->getNumPasses(); i++)
+		{
+			PassPtr curPass = technique->getPass(i);
+
+			GpuProgramPtr vertProgram = curPass->getVertexProgram();
+			if (vertProgram)
+			{
+				vertProgram->blockUntilCoreInitialized();
+				allParamDescs.push_back(vertProgram->getParamDesc());
+			}
+
+			GpuProgramPtr fragProgram = curPass->getFragmentProgram();
+			if (fragProgram)
+			{
+				fragProgram->blockUntilCoreInitialized();
+				allParamDescs.push_back(fragProgram->getParamDesc());
+			}
+
+			GpuProgramPtr geomProgram = curPass->getGeometryProgram();
+			if (geomProgram)
+			{
+				geomProgram->blockUntilCoreInitialized();
+				allParamDescs.push_back(geomProgram->getParamDesc());
+			}
+
+			GpuProgramPtr hullProgram = curPass->getHullProgram();
+			if (hullProgram)
+			{
+				hullProgram->blockUntilCoreInitialized();
+				allParamDescs.push_back(hullProgram->getParamDesc());
+			}
+
+			GpuProgramPtr domainProgram = curPass->getDomainProgram();
+			if (domainProgram)
+			{
+				domainProgram->blockUntilCoreInitialized();
+				allParamDescs.push_back(domainProgram->getParamDesc());
+			}
+
+			GpuProgramPtr computeProgram = curPass->getComputeProgram();
+			if (computeProgram)
+			{
+				computeProgram->blockUntilCoreInitialized();
+				allParamDescs.push_back(computeProgram->getParamDesc());
+			}
+		}
+
+		return allParamDescs;
+	}
+
+	Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<TechniqueCore>& technique)
+	{
+		Vector<GpuParamDescPtr> allParamDescs;
+
+		// Make sure all gpu programs are fully loaded
+		for (UINT32 i = 0; i < technique->getNumPasses(); i++)
+		{
+			SPtr<PassCore> curPass = technique->getPass(i);
+
+			SPtr<GpuProgramCore> vertProgram = curPass->getVertexProgram();
+			if (vertProgram)
+				allParamDescs.push_back(vertProgram->getParamDesc());
+
+			SPtr<GpuProgramCore> fragProgram = curPass->getFragmentProgram();
+			if (fragProgram)
+				allParamDescs.push_back(fragProgram->getParamDesc());
+
+			SPtr<GpuProgramCore> geomProgram = curPass->getGeometryProgram();
+			if (geomProgram)
+				allParamDescs.push_back(geomProgram->getParamDesc());
+
+			SPtr<GpuProgramCore> hullProgram = curPass->getHullProgram();
+			if (hullProgram)
+				allParamDescs.push_back(hullProgram->getParamDesc());
+
+			SPtr<GpuProgramCore> domainProgram = curPass->getDomainProgram();
+			if (domainProgram)
+				allParamDescs.push_back(domainProgram->getParamDesc());
+
+			SPtr<GpuProgramCore> computeProgram = curPass->getComputeProgram();
+			if (computeProgram)
+				allParamDescs.push_back(computeProgram->getParamDesc());
+		}
+
+		return allParamDescs;
+	}
+
+	template<bool Core>
+	UINT32 TMaterial<Core>::getNumPasses() const
+	{
+		if (mShader == nullptr)
+			return 0;
+
+		return mShader->getBestTechnique()->getNumPasses();
+	}
+
+	template<bool Core>
+	typename TMaterial<Core>::PassType TMaterial<Core>::getPass(UINT32 passIdx) const
+	{
+		if (passIdx < 0 || passIdx >= mShader->getBestTechnique()->getNumPasses())
+			BS_EXCEPT(InvalidParametersException, "Invalid pass index.");
+
+		return mShader->getBestTechnique()->getPass(passIdx);
+	}
+
+	template<bool Core>
+	TMaterialParamStruct<Core> TMaterial<Core>::getParamStruct(const String& name) const
+	{
+		throwIfNotInitialized();
+
+		auto iterFind = mValidParams.find(name);
+		if (iterFind == mValidParams.end())
+		{
+			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
+			return TMaterialParamStruct<Core>();
+		}
+
+		const String& gpuVarName = iterFind->second;
+		SPtr<Vector<TGpuParamStruct<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamStruct<Core>>>();
+
+		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+		{
+			SPtr<PassParamsType> params = *iter;
+
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+			{
+				GpuParamsType& paramPtr = params->getParamByIdx(i);
+				if (paramPtr)
+				{
+					if (paramPtr->hasParam(gpuVarName))
+					{
+						gpuParams->push_back(TGpuParamStruct<Core>());
+						paramPtr->getStructParam(gpuVarName, gpuParams->back());
+					}
+				}
+			}
+		}
+
+		return createStructParam(name, gpuParams);
+	}
+
+	template<bool Core>
+	TMaterialParamTexture<Core> TMaterial<Core>::getParamTexture(const String& name) const
+	{
+		throwIfNotInitialized();
+
+		auto iterFind = mValidParams.find(name);
+		if (iterFind == mValidParams.end())
+		{
+			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
+			return TMaterialParamTexture<Core>();
+		}
+
+		const String& gpuVarName = iterFind->second;
+		SPtr<Vector<TGpuParamTexture<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamTexture<Core>>>();
+
+		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+		{
+			SPtr<PassParamsType> params = *iter;
+
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+			{
+				GpuParamsType& paramPtr = params->getParamByIdx(i);
+				if (paramPtr)
+				{
+					if (paramPtr->hasTexture(gpuVarName))
+					{
+						gpuParams->push_back(TGpuParamTexture<Core>());
+						paramPtr->getTextureParam(gpuVarName, gpuParams->back());
+					}
+				}
+			}
+		}
+
+		return createTextureParam(name, gpuParams);
+	}
+
+	template<bool Core>
+	TMaterialParamLoadStoreTexture<Core> TMaterial<Core>::getParamLoadStoreTexture(const String& name) const
+	{
+		throwIfNotInitialized();
+
+		auto iterFind = mValidParams.find(name);
+		if (iterFind == mValidParams.end())
+		{
+			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
+			return TMaterialParamLoadStoreTexture<Core>();
+		}
+
+		const String& gpuVarName = iterFind->second;
+		SPtr<Vector<TGpuParamLoadStoreTexture<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamLoadStoreTexture<Core>>>();
+
+		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+		{
+			SPtr<PassParamsType> params = *iter;
+
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+			{
+				GpuParamsType& paramPtr = params->getParamByIdx(i);
+				if (paramPtr)
+				{
+					if (paramPtr->hasTexture(gpuVarName))
+					{
+						gpuParams->push_back(TGpuParamLoadStoreTexture<Core>());
+						paramPtr->getLoadStoreTextureParam(gpuVarName, gpuParams->back());
+					}
+				}
+			}
+		}
+
+		return createLoadStoreTextureParam(name, gpuParams);
+	}
+
+	template<bool Core>
+	TMaterialParamSampState<Core> TMaterial<Core>::getParamSamplerState(const String& name) const
+	{
+		throwIfNotInitialized();
+
+		auto iterFind = mValidParams.find(name);
+		if (iterFind == mValidParams.end())
+		{
+			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
+			return TMaterialParamSampState<Core>();
+		}
+
+		const String& gpuVarName = iterFind->second;
+		SPtr<Vector<TGpuParamSampState<Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuParamSampState<Core>>>();
+		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+		{
+			SPtr<PassParamsType> params = *iter;
+
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+			{
+				GpuParamsType& paramPtr = params->getParamByIdx(i);
+				if (paramPtr)
+				{
+					if (paramPtr->hasSamplerState(gpuVarName))
+					{
+						gpuParams->push_back(TGpuParamSampState<Core>());
+						paramPtr->getSamplerStateParam(gpuVarName, gpuParams->back());
+					}
+				}
+			}
+		}
+
+		return createSamplerStateParam(name, gpuParams);
+	}
+
+	template<bool Core>
+	void TMaterial<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock)
+	{
+		auto iterFind = mValidShareableParamBlocks.find(name);
+		if (iterFind == mValidShareableParamBlocks.end())
+		{
+			LOGWRN_VERBOSE("Material doesn't have a parameter block named " + name);
+			return;
+		}
+
+		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+		{
+			SPtr<PassParamsType> params = *iter;
+
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+			{
+				GpuParamsType& paramPtr = params->getParamByIdx(i);
+				if (paramPtr)
+				{
+					if (paramPtr->hasParamBlock(name))
+						paramPtr->setParamBlockBuffer(name, paramBlock);
+				}
+			}
+		}
+	}
+
+	template<bool Core>
+	void TMaterial<Core>::initBestTechnique()
+	{
+		mBestTechnique = nullptr;
+		mParametersPerPass.clear();
+
+		if (isShaderValid(mShader))
+		{
+			createCachedParams(mShader);
+
+			mBestTechnique = mShader->getBestTechnique();
+
+			if (mBestTechnique == nullptr)
+				return;
+
+			mValidShareableParamBlocks.clear();
+			Vector<GpuParamDescPtr> allParamDescs = getAllParamDescs(mBestTechnique);
+
+			mValidParams = determineParamMappings(allParamDescs, mShader->getDataParams(), mShader->getTextureParams(),
+				mShader->getBufferParams(), mShader->getSamplerParams());
+
+			// Fill out various helper structures
+			Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
+			Vector<ShaderBlockDesc> paramBlockData = determineShaderBlockData(validShareableParamBlocks, allParamDescs, mShader->getParamBlocks());
+
+			Map<String, ParamBlockPtrType> paramBlockBuffers;
+
+			// Create param blocks
+			for (auto& paramBlock : paramBlockData)
+			{
+				ParamBlockPtrType newParamBlockBuffer;
+				if (paramBlock.create)
+				{
+					newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
+				}
+
+				paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
+				mValidShareableParamBlocks.insert(paramBlock.name);
+			}
+
+			for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
+			{
+				PassType curPass = mBestTechnique->getPass(i);
+				SPtr<PassParamsType> params = SPtr<PassParamsType>(new PassParamsType());
+
+				GpuProgramType vertProgram = curPass->getVertexProgram();
+				if (vertProgram)
+					params->mVertParams = vertProgram->createParameters();
+
+				GpuProgramType fragProgram = curPass->getFragmentProgram();
+				if (fragProgram)
+					params->mFragParams = fragProgram->createParameters();
+
+				GpuProgramType geomProgram = curPass->getGeometryProgram();
+				if (geomProgram)
+					params->mGeomParams = geomProgram->createParameters();
+
+				GpuProgramType hullProgram = curPass->getHullProgram();
+				if (hullProgram)
+					params->mHullParams = hullProgram->createParameters();
+
+				GpuProgramType domainProgram = curPass->getDomainProgram();
+				if (domainProgram)
+					params->mDomainParams = domainProgram->createParameters();
+
+				GpuProgramType computeProgram = curPass->getComputeProgram();
+				if (computeProgram)
+					params->mComputeParams = computeProgram->createParameters();
+
+				mParametersPerPass.push_back(params);
+			}
+
+			// Assign param block buffers
+			for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+			{
+				SPtr<PassParamsType> params = *iter;
+
+				for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+				{
+					GpuParamsType& paramPtr = params->getParamByIdx(i);
+					if (paramPtr)
+					{
+						// Assign shareable buffers
+						for (auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock)
+						{
+							const String& paramBlockName = *iterBlock;
+							if (paramPtr->hasParamBlock(paramBlockName))
+							{
+								ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
+
+								paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
+							}
+						}
+
+						// Create non-shareable ones
+						const GpuParamDesc& desc = paramPtr->getParamDesc();
+						for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
+						{
+							if (!iterBlockDesc->second.isShareable)
+							{
+								ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32));
+
+								paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
+							}
+						}
+					}
+				}
+			}
+
+			// Assign default parameters
+			initDefaultParameters();
+		}
+
+		_markDependenciesDirty();
+	}
+
+	template <bool Core>
+	template <typename T>
+	void TMaterial<Core>::setParamValue(const String& name, UINT8* buffer, UINT32 numElements)
+	{
+		TMaterialDataParam<T, Core> param;
+		getParam(name, param);
+
+		T* ptr = (T*)buffer;
+		for (UINT32 i = 0; i < numElements; i++)
+			param.set(ptr[i], i);
+	}
+
+	template <bool Core>
+	void TMaterial<Core>::initDefaultParameters()
+	{
+		const Map<String, SHADER_DATA_PARAM_DESC>& dataParams = mShader->getDataParams();
+		for (auto& paramData : dataParams)
+		{
+			if (paramData.second.defaultValueIdx == (UINT32)-1)
+				continue;
+
+			auto iterFind = mValidParams.find(paramData.first);
+			if (iterFind == mValidParams.end())
+				continue;
+			
+			UINT8* buffer = (UINT8*)mShader->getDefaultValue(paramData.second.defaultValueIdx);
+			if (buffer == nullptr)
+				continue;
+
+			switch (paramData.second.type)
+			{
+			case GPDT_FLOAT1: 
+				setParamValue<float>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_FLOAT2:
+				setParamValue<Vector2>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_FLOAT3:
+				setParamValue<Vector3>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_FLOAT4:
+				setParamValue<Vector4>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_2X2:
+				setParamValue<Matrix2>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_2X3:
+				setParamValue<Matrix2x3>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_2X4:
+				setParamValue<Matrix2x4>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_3X2:
+				setParamValue<Matrix3x2>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_3X3:
+				setParamValue<Matrix3>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_3X4:
+				setParamValue<Matrix3x4>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_4X2:
+				setParamValue<Matrix4x2>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_4X3:
+				setParamValue<Matrix4x3>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_MATRIX_4X4:
+				setParamValue<Matrix4>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_INT1:
+				setParamValue<int>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_INT2:
+				setParamValue<Vector2I>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_INT3:
+				setParamValue<Vector3I>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_INT4:
+				setParamValue<Vector4I>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_BOOL:
+				setParamValue<int>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_COLOR:
+				setParamValue<Color>(iterFind->first, buffer, paramData.second.arraySize);
+				break;
+			case GPDT_STRUCT:
+			{
+				TMaterialParamStruct<Core> param = getParamStruct(paramData.first);
+
+				UINT32 elementSizeBytes = paramData.second.elementSize * sizeof(UINT32);
+				UINT8* ptr = buffer;
+				for (UINT32 i = 0; i < paramData.second.arraySize; i++)
+				{
+					param.set(ptr, elementSizeBytes, i);
+					ptr += elementSizeBytes;
+				}
+			}
+			break;
+			}
+		}
+
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams = mShader->getTextureParams();
+		for (auto& param : textureParams)
+		{
+			if (param.second.defaultValueIdx == (UINT32)-1)
+				continue;
+
+			auto iterFind = mValidParams.find(param.first);
+			if (iterFind == mValidParams.end())
+				continue;
+
+			TextureType defaultTex = mShader->getDefaultTexture(param.second.defaultValueIdx);
+			getParamTexture(param.first).set(defaultTex);
+		}
+
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams = mShader->getSamplerParams();
+		for (auto& param : samplerParams)
+		{
+			if (param.second.defaultValueIdx == (UINT32)-1)
+				continue;
+
+			auto iterFind = mValidParams.find(param.first);
+			if (iterFind == mValidParams.end())
+				continue;
+
+			SamplerStateType defaultSampler = mShader->getDefaultSampler(param.second.defaultValueIdx);
+			getParamSamplerState(param.first).set(defaultSampler);
+		}
+	}
+
+	template <bool Core>
+	template <typename T>
+	void TMaterial<Core>::getParam(const String& name, TMaterialDataParam<T, Core>& output) const
+	{
+		throwIfNotInitialized();
+
+		auto iterFind = mValidParams.find(name);
+		if (iterFind == mValidParams.end())
+		{
+			LOGWRN_VERBOSE("Material doesn't have a parameter named " + name);
+			return;
+		}
+
+		const String& gpuVarName = iterFind->second;
+		SPtr<Vector<TGpuDataParam<T, Core>>> gpuParams = bs_shared_ptr_new<Vector<TGpuDataParam<T, Core>>>();
+
+		for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+		{
+			SPtr<PassParamsType> params = *iter;
+
+			for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+			{
+				GpuParamsType& paramPtr = params->getParamByIdx(i);
+				if (paramPtr)
+				{
+					if (paramPtr->hasParam(gpuVarName))
+					{
+						gpuParams->push_back(TGpuDataParam<T, Core>());
+						paramPtr->getParam<T>(gpuVarName, gpuParams->back());
+					}
+				}
+			}
+		}
+
+		output = createDataParam(name, gpuParams);
+	}
+
+	template<bool Core>
+	void TMaterial<Core>::throwIfNotInitialized() const
+	{
+		if (mShader == nullptr)
+		{
+			BS_EXCEPT(InternalErrorException, "Material does not have shader set.");
+		}
+
+		if (mBestTechnique == nullptr)
+		{
+			BS_EXCEPT(InternalErrorException, "Shader does not contain a supported technique.");
+		}
+	}
+
+	template class TMaterial < false > ;
+	template class TMaterial < true > ;
+
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<float, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<int, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Color, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector2, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector3, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector4, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector2I, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector3I, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector4I, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix2, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix2x3, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix2x4, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3x2, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3x4, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4x2, false>&) const;
+	template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4x3, false>&) const;
+
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<float, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<int, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Color, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector2, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector3, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector4, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector2I, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector3I, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector4I, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix2, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix2x3, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix2x4, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3x2, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3x4, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4x2, true>&) const;
+	template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4x3, true>&) const;
+
+	MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader)
+	{
+		setShader(shader);
+	}
+
+	MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader, const SPtr<TechniqueCore>& bestTechnique,
+		const Set<String>& validShareableParamBlocks, const Map<String, String>& validParams,
+		const Vector<SPtr<PassParametersCore>>& passParams)
+	{
+		mShader = shader;
+		mBestTechnique = bestTechnique;
+		mValidShareableParamBlocks = validShareableParamBlocks;
+		mValidParams = validParams;
+
+		UINT32 numPassParams = (UINT32)passParams.size();
+		mParametersPerPass.resize(numPassParams);
+		for (UINT32 i = 0; i < numPassParams; i++)
+			mParametersPerPass[i] = passParams[i];
+	}
+
+	void MaterialCore::setShader(const SPtr<ShaderCore>& shader)
+	{
+		mShader = shader;
+
+		initBestTechnique();
+
+		_markCoreDirty();
+	}
+
+	void MaterialCore::syncToCore(const CoreSyncData& data)
+	{
+		char* dataPtr = (char*)data.getBuffer();
+
+		mValidShareableParamBlocks.clear();
+		mValidParams.clear();
+		mParametersPerPass.clear();
+
+		UINT32 numPasses = 0;
+
+		dataPtr = rttiReadElem(mValidShareableParamBlocks, dataPtr);
+		dataPtr = rttiReadElem(mValidParams, dataPtr);
+		dataPtr = rttiReadElem(numPasses, dataPtr);
+
+		for (UINT32 i = 0; i < numPasses; i++)
+		{
+			SPtr<PassParametersCore>* passParameters = (SPtr<PassParametersCore>*)dataPtr;
+
+			mParametersPerPass.push_back(*passParameters);
+
+			passParameters->~SPtr<PassParametersCore>();
+			dataPtr += sizeof(SPtr<PassParametersCore>);
+		}
+
+		SPtr<ShaderCore>* shader = (SPtr<ShaderCore>*)dataPtr;
+		mShader = *shader;
+		shader->~SPtr<ShaderCore>();
+		dataPtr += sizeof(SPtr<ShaderCore>);
+
+		SPtr<TechniqueCore>* technique = (SPtr<TechniqueCore>*)dataPtr;
+		mBestTechnique = *technique;
+		technique->~SPtr<TechniqueCore>();
+		dataPtr += sizeof(SPtr<TechniqueCore>);
+	}
+
+	SPtr<MaterialCore> MaterialCore::create(const SPtr<ShaderCore>& shader)
+	{
+		MaterialCore* material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
+		SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore>(material);
+		materialPtr->_setThisPtr(materialPtr);
+		materialPtr->initialize();
+
+		return materialPtr;
+	}
+
+	Material::Material()
+		:mLoadFlags(Load_None)
+	{ }
+
+	Material::Material(const HShader& shader)
+		:mLoadFlags(Load_None)
+	{
+		mShader = shader;
+	}
+
+	void Material::initialize()
+	{
+		setShader(mShader); // Not calling directly in constructor because it calls virtual methods
+
+		Resource::initialize();
+	}
+
+	void Material::setShader(const HShader& shader)
+	{
+		//if (mShader == shader)
+		//	return;
+
+		mShader = shader;
+		mBestTechnique = nullptr;
+		mLoadFlags = Load_None;
+		_markResourcesDirty();
+
+		initializeIfLoaded();
+	}
+
+	void Material::_markCoreDirty()
+	{
+		markCoreDirty();
+	}
+
+	void Material::_markDependenciesDirty()
+	{
+		markDependenciesDirty();
+	}
+
+	void Material::_markResourcesDirty()
+	{
+		markListenerResourcesDirty();
+	}
+
+	SPtr<MaterialCore> Material::getCore() const
+	{
+		return std::static_pointer_cast<MaterialCore>(mCoreSpecific);
+	}
+
+	SPtr<CoreObjectCore> Material::createCore() const
+	{
+		MaterialCore* material = nullptr;
+
+		SPtr<ShaderCore> shader;
+		if (mShader.isLoaded())
+		{
+			shader = mShader->getCore();
+
+			if (mBestTechnique != nullptr)
+			{
+				SPtr<TechniqueCore> technique = mBestTechnique->getCore();
+
+				Vector<SPtr<PassParametersCore>> passParams;
+				for (auto& passParam : mParametersPerPass)
+					passParams.push_back(convertParamsToCore(passParam));
+
+				material = new (bs_alloc<MaterialCore>()) MaterialCore(shader, technique, mValidShareableParamBlocks, mValidParams, passParams);
+			}
+		}
+		
+		if (material == nullptr)
+			material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
+
+		SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore>(material);
+		materialPtr->_setThisPtr(materialPtr);
+
+		return materialPtr;
+	}
+
+	CoreSyncData Material::syncToCore(FrameAlloc* allocator)
+	{
+		UINT32 numPasses = (UINT32)mParametersPerPass.size();
+
+		UINT32 size = sizeof(UINT32) + numPasses * sizeof(SPtr<PassParametersCore>)
+			+ sizeof(SPtr<ShaderCore>) + sizeof(SPtr<TechniqueCore>) + rttiGetElemSize(mValidShareableParamBlocks)
+			+ rttiGetElemSize(mValidParams);
+
+		UINT8* buffer = allocator->alloc(size);
+		char* dataPtr = (char*)buffer;
+		dataPtr = rttiWriteElem(mValidShareableParamBlocks, dataPtr);
+		dataPtr = rttiWriteElem(mValidParams, dataPtr);
+		dataPtr = rttiWriteElem(numPasses, dataPtr);
+
+		for (UINT32 i = 0; i < numPasses; i++)
+		{
+			SPtr<PassParametersCore>* passParameters = new (dataPtr) SPtr<PassParametersCore>();
+			*passParameters = convertParamsToCore(mParametersPerPass[i]);
+
+			dataPtr += sizeof(SPtr<PassParametersCore>);
+		}
+
+		SPtr<ShaderCore>* shader = new (dataPtr)SPtr<ShaderCore>();
+		if (mShader.isLoaded(false))
+			*shader = mShader->getCore();
+		else
+			*shader = nullptr;
+
+		dataPtr += sizeof(SPtr<ShaderCore>);
+
+		SPtr<TechniqueCore>* technique = new (dataPtr)SPtr<TechniqueCore>();
+		if (mBestTechnique != nullptr)
+			*technique = mBestTechnique->getCore();
+		else
+			*technique = nullptr;
+
+		dataPtr += sizeof(SPtr<TechniqueCore>);
+
+		return CoreSyncData(buffer, size);
+	}
+
+	void Material::getCoreDependencies(Vector<CoreObject*>& dependencies)
+	{
+		if (mShader.isLoaded())
+			dependencies.push_back(mShader.get());
+
+		for (auto& params : mParametersPerPass)
+		{
+			for (UINT32 i = 0; i < PassParameters::NUM_PARAMS; i++)
+			{
+				GpuParamsPtr gpuParams = params->getParamByIdx(i);
+				if (gpuParams != nullptr)
+					dependencies.push_back(gpuParams.get());
+			}
+		}
+	}
+
+	void Material::getListenerResources(Vector<HResource>& resources)
+	{
+		if (mShader != nullptr)
+			resources.push_back(mShader);
+	}
+
+	void Material::getResourceDependencies(FrameVector<HResource>& dependencies) const
+	{
+		if (mShader != nullptr)
+			dependencies.push_back(mShader);
+
+		if (mShader.isLoaded())
+		{
+			const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams = mShader->getTextureParams();
+
+			for (auto& param : textureParams)
+			{
+				if (param.second.defaultValueIdx != (UINT32)-1)
+				{
+					HTexture defaultTex = mShader->getDefaultTexture(param.second.defaultValueIdx);
+					if (defaultTex != nullptr)
+						dependencies.push_back(defaultTex);
+				}
+			}
+		}
+	}
+
+	void Material::initializeIfLoaded()
+	{
+		if (areDependenciesLoaded())
+		{
+			if (mLoadFlags != Load_All)
+			{
+				mLoadFlags = Load_All;
+
+				initBestTechnique();
+				markCoreDirty();
+			}
+		}
+		else
+		{
+			if (mShader.isLoaded() && mLoadFlags == Load_None)
+			{
+				mLoadFlags = Load_Shader;
+				markListenerResourcesDirty(); // Need to register resources dependent on shader now
+			}
+		}
+	}
+
+	void Material::createCachedParams(const HShader& shader)
+	{
+		mCachedParams = bs_shared_ptr_new<__MaterialParams>(shader);
+	}
+
+	void Material::notifyResourceLoaded(const HResource& resource)
+	{
+		initializeIfLoaded();
+	}
+
+	template<class T>
+	void copyParam(SPtr<GpuParams>& from, SPtr<GpuParams>& to, const String& name, UINT32 arraySize)
+	{
+		TGpuDataParam<T, false> newParam;
+		to->getParam(name, newParam);
+
+		TGpuDataParam<T, false> oldParam;
+		from->getParam(name, oldParam);
+
+		for (UINT32 i = 0; i < arraySize; i++)
+			newParam.set(oldParam.get(i), i);
+	}
+
+	void Material::notifyResourceChanged(const HResource& resource)
+	{
+		// Shader changed, so save parameters, rebuild material and restore parameters
+		Vector<SPtr<PassParameters>> oldPassParams = mParametersPerPass;
+
+		mLoadFlags = Load_None;
+		initializeIfLoaded();
+
+		for (UINT32 i = 0; i < (UINT32)oldPassParams.size(); i++)
+		{
+			if (i >= (UINT32)mParametersPerPass.size())
+				continue;
+
+			SPtr<PassParameters> oldParams = oldPassParams[i];
+			SPtr<PassParameters> newParams = mParametersPerPass[i];
+
+			for (UINT32 j = 0; j < PassParameters::NUM_PARAMS; j++)
+			{
+				SPtr<GpuParams>& oldGpuParams = oldParams->getParamByIdx(j);
+				SPtr<GpuParams>& newGpuParams = newParams->getParamByIdx(j);
+				if (oldGpuParams == nullptr || newGpuParams == nullptr)
+					continue;
+
+				const GpuParamDesc& oldDesc = oldGpuParams->getParamDesc();
+				const GpuParamDesc& newDesc = newGpuParams->getParamDesc();
+
+				for (auto& param : oldDesc.params)
+				{
+					auto iterFind = newDesc.params.find(param.first);
+					if (iterFind == newDesc.params.end())
+						continue;
+
+					if (param.second.type != iterFind->second.type)
+						continue;
+
+					UINT32 arraySize = std::min(param.second.arraySize, iterFind->second.arraySize);
+					
+					switch (param.second.type)
+					{
+					case GPDT_FLOAT1:
+						copyParam<float>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_FLOAT2:
+						copyParam<Vector2>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_FLOAT3:
+						copyParam<Vector3>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_FLOAT4:
+						copyParam<Vector4>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_2X2:
+						copyParam<Matrix2>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_2X3:
+						copyParam<Matrix2x3>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_2X4:
+						copyParam<Matrix2x4>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_3X2:
+						copyParam<Matrix3x2>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_3X3:
+						copyParam<Matrix3>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_3X4:
+						copyParam<Matrix3x4>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_4X2:
+						copyParam<Matrix4x2>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_4X3:
+						copyParam<Matrix4x3>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_MATRIX_4X4:
+						copyParam<Matrix4>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_INT1:
+					case GPDT_BOOL:
+						copyParam<int>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_INT2:
+						copyParam<Vector2I>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_INT3:
+						copyParam<Vector3I>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_INT4:
+						copyParam<Vector4I>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_COLOR:
+						copyParam<Color>(oldGpuParams, newGpuParams, param.first, arraySize);
+						break;
+					case GPDT_STRUCT:
+					{
+						GpuParamStruct newParam;
+						newGpuParams->getStructParam(param.first, newParam);
+
+						GpuParamStruct oldParam;
+						oldGpuParams->getStructParam(param.first, oldParam);
+
+						if (param.second.elementSize == iterFind->second.elementSize)
+						{
+							for (UINT32 k = 0; k < arraySize; k++)
+							{
+								UINT8* data = (UINT8*)bs_stack_alloc(param.second.elementSize);
+								oldParam.get(data, param.second.elementSize, k);
+								newParam.set(data, param.second.elementSize, k);
+								bs_stack_free(data);
+							}
+						}
+					}
+					break;
+					}
+				}
+
+				for (auto& param : oldDesc.textures)
+				{
+					auto iterFind = newDesc.textures.find(param.first);
+					if (iterFind == newDesc.textures.end())
+						continue;
+
+					UINT32 oldSlot = param.second.slot;
+					UINT32 newSlot = iterFind->second.slot;
+
+					bool isLoadStore = oldGpuParams->isLoadStoreTexture(oldSlot);
+
+					if (!isLoadStore)
+						newGpuParams->setTexture(newSlot, oldGpuParams->getTexture(oldSlot));
+					else
+					{
+						newGpuParams->setIsLoadStoreTexture(newSlot, true);
+						newGpuParams->setLoadStoreSurface(newSlot, oldGpuParams->getLoadStoreSurface(oldSlot));
+					}
+				}
+
+				for (auto& param : oldDesc.samplers)
+				{
+					auto iterFind = newDesc.samplers.find(param.first);
+					if (iterFind == newDesc.samplers.end())
+						continue;
+
+					newGpuParams->setSamplerState(iterFind->second.slot, oldGpuParams->getSamplerState(param.second.slot));
+				}
+			}
+		}
+	}
+
+	HMaterial Material::clone()
+	{
+		UINT32 bufferSize = 0;
+
+		MemorySerializer serializer;
+		UINT8* buffer = serializer.encode(this, bufferSize, (void*(*)(UINT32))&bs_alloc);
+
+		std::shared_ptr<Material> cloneObj = std::static_pointer_cast<Material>(serializer.decode(buffer, bufferSize));
+		bs_free(buffer);
+
+		return static_resource_cast<Material>(gResources()._createResourceHandle(cloneObj));
+	}
+
+	HMaterial Material::create()
+	{
+		MaterialPtr materialPtr = MaterialManager::instance().create();
+
+		return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
+	}
+
+	HMaterial Material::create(const HShader& shader)
+	{
+		MaterialPtr materialPtr = MaterialManager::instance().create(shader);
+
+		return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
+	}
+
+	RTTITypeBase* Material::getRTTIStatic()
+	{
+		return MaterialRTTI::instance();
+	}
+
+	RTTITypeBase* Material::getRTTI() const
+	{
+		return Material::getRTTIStatic();
+	}
 }

+ 389 - 187
BansheeCore/Source/BsMaterialParam.cpp

@@ -1,188 +1,390 @@
-#include "BsMaterialParam.h"
-#include "BsVector2I.h"
-#include "BsVectorNI.h"
-
-namespace BansheeEngine
-{
-	template<class T, bool Core>
-	TMaterialDataParam<T, Core>::TMaterialDataParam(const SPtr<Vector<TGpuDataParam<T, Core>>>& params)
-		:mParams(params)
-	{ }
-
-	template<class T, bool Core>
-	void TMaterialDataParam<T, Core>::set(const T& value, UINT32 arrayIdx)
-	{
-		if (mParams == nullptr)
-			return;
-
-		for (auto& param : *mParams)
-			param.set(value, arrayIdx);
-	}
-
-	template<class T, bool Core>
-	T TMaterialDataParam<T, Core>::get(UINT32 arrayIdx)
-	{
-		if (mParams == nullptr || mParams->size() == 0)
-			return T();
-
-		return (*mParams)[0].get(arrayIdx); // They should all have the same value
-	}
-
-	template<bool Core>
-	TMaterialParamStruct<Core>::TMaterialParamStruct(const SPtr<Vector<TGpuParamStruct<Core>>>& params)
-		:mParams(params)
-	{ }
-
-	template<bool Core>
-	void TMaterialParamStruct<Core>::set(const void* value, UINT32 sizeBytes, UINT32 arrayIdx)
-	{
-		if (mParams == nullptr)
-			return;
-
-		for (auto& param : *mParams)
-			param.set(value, sizeBytes, arrayIdx);
-	}
-
-	template<bool Core>
-	void TMaterialParamStruct<Core>::get(void* value, UINT32 sizeBytes, UINT32 arrayIdx)
-	{
-		if (mParams == nullptr || mParams->size() == 0)
-		{
-			value = nullptr;
-			return;
-		}
-
-		return (*mParams)[0].get(value, sizeBytes, arrayIdx); // They should all have the same value
-	}
-
-	template<bool Core>
-	UINT32 TMaterialParamStruct<Core>::getElementSize() const
-	{
-		if (mParams == nullptr || mParams->size() == 0)
-			return 0;
-
-		return (*mParams)[0].getElementSize();
-	}
-
-	template<bool Core>
-	TMaterialParamTexture<Core>::TMaterialParamTexture(const SPtr<Vector<TGpuParamTexture<Core>>>& params)
-		:mParams(params)
-	{ }
-
-	template<bool Core>
-	void TMaterialParamTexture<Core>::set(const TextureType& texture)
-	{
-		if (mParams == nullptr)
-			return;
-
-		for (auto& param : *mParams)
-			param.set(texture);
-	}
-
-	template<bool Core>
-	typename TMaterialParamTexture<Core>::TextureType TMaterialParamTexture<Core>::get()
-	{
-		if (mParams == nullptr || mParams->size() == 0)
-			return TextureType();
-
-		return (*mParams)[0].get(); // They should all have the same value
-	}
-
-	template<bool Core>
-	TMaterialParamLoadStoreTexture<Core>::TMaterialParamLoadStoreTexture(const SPtr<Vector<TGpuParamLoadStoreTexture<Core>>>& params)
-		:mParams(params)
-	{ }
-
-	template<bool Core>
-	void TMaterialParamLoadStoreTexture<Core>::set(const TextureType& texture, const TextureSurface& surface)
-	{
-		if (mParams == nullptr)
-			return;
-
-		for (auto& param : *mParams)
-			param.set(texture, surface);
-	}
-
-	template<bool Core>
-	typename TMaterialParamLoadStoreTexture<Core>::TextureType TMaterialParamLoadStoreTexture<Core>::get()
-	{
-		if (mParams == nullptr || mParams->size() == 0)
-			return TextureType();
-
-		return (*mParams)[0].get(); // They should all have the same value
-	}
-
-	template<bool Core>
-	TMaterialParamSampState<Core>::TMaterialParamSampState(const SPtr<Vector<TGpuParamSampState<Core>>>& params)
-		:mParams(params)
-	{ }
-
-	template<bool Core>
-	void TMaterialParamSampState<Core>::set(const SamplerType& sampState)
-	{
-		if (mParams == nullptr)
-			return;
-
-		for (auto& param : *mParams)
-			param.set(sampState);
-	}
-
-	template<bool Core>
-	typename TMaterialParamSampState<Core>::SamplerType TMaterialParamSampState<Core>::get()
-	{
-		if (mParams == nullptr || mParams->size() == 0)
-			return SamplerType();
-
-		return (*mParams)[0].get(); // They should all have the same value
-	}
-
-	template class TMaterialDataParam<float, false>;
-	template class TMaterialDataParam<int, false>;
-	template class TMaterialDataParam<Color, false>;
-	template class TMaterialDataParam<Vector2, false>;
-	template class TMaterialDataParam<Vector3, false>;
-	template class TMaterialDataParam<Vector4, false>;
-	template class TMaterialDataParam<Vector2I, false>;
-	template class TMaterialDataParam<Vector3I, false>;
-	template class TMaterialDataParam<Vector4I, false>;
-	template class TMaterialDataParam<Matrix2, false>;
-	template class TMaterialDataParam<Matrix2x3, false>;
-	template class TMaterialDataParam<Matrix2x4, false>;
-	template class TMaterialDataParam<Matrix3, false>;
-	template class TMaterialDataParam<Matrix3x2, false>;
-	template class TMaterialDataParam<Matrix3x4, false>;
-	template class TMaterialDataParam<Matrix4, false>;
-	template class TMaterialDataParam<Matrix4x2, false>;
-	template class TMaterialDataParam<Matrix4x3, false>;
-
-	template class TMaterialDataParam<float, true>;
-	template class TMaterialDataParam<int, true>;
-	template class TMaterialDataParam<Color, true>;
-	template class TMaterialDataParam<Vector2, true>;
-	template class TMaterialDataParam<Vector3, true>;
-	template class TMaterialDataParam<Vector4, true>;
-	template class TMaterialDataParam<Vector2I, true>;
-	template class TMaterialDataParam<Vector3I, true>;
-	template class TMaterialDataParam<Vector4I, true>;
-	template class TMaterialDataParam<Matrix2, true>;
-	template class TMaterialDataParam<Matrix2x3, true>;
-	template class TMaterialDataParam<Matrix2x4, true>;
-	template class TMaterialDataParam<Matrix3, true>;
-	template class TMaterialDataParam<Matrix3x2, true>;
-	template class TMaterialDataParam<Matrix3x4, true>;
-	template class TMaterialDataParam<Matrix4, true>;
-	template class TMaterialDataParam<Matrix4x2, true>;
-	template class TMaterialDataParam<Matrix4x3, true>;
-
-	template class TMaterialParamStruct<false>;
-	template class TMaterialParamStruct<true>;
-
-	template class TMaterialParamTexture<false>;
-	template class TMaterialParamTexture<true>;
-
-	template class TMaterialParamLoadStoreTexture<false>;
-	template class TMaterialParamLoadStoreTexture<true>;
-
-	template class TMaterialParamSampState<false>;
-	template class TMaterialParamSampState<true>;
+#include "BsMaterialParam.h"
+#include "BsVector2I.h"
+#include "BsVectorNI.h"
+#include "BsMaterialParams.h"
+
+namespace BansheeEngine
+{
+	template<class T>
+	TMaterialDataParam<T, false>::TMaterialDataParam(const String& name, const SPtr<__MaterialParams>& params,
+		const SPtr<Vector<TGpuDataParam<T, false>>>& gpuParams)
+		:mParamIndex(0), mArraySize(0), mMaterialParams(params), mGPUParams(gpuParams)
+	{
+		if(params != nullptr)
+		{
+			const __MaterialParams::ParamData* data = params->getParamData(name, __MaterialParams::ParamType::Data, 
+				__MaterialParams::getDataType(T()), 0);
+
+			if(data != nullptr)
+			{
+				mParamIndex = data->index;
+				mArraySize = data->arraySize;
+			}
+		}
+	}
+
+	template<class T>
+	void TMaterialDataParam<T, false>::set(const T& value, UINT32 arrayIdx)
+	{
+		if (mMaterialParams == nullptr)
+			return;
+
+		if(arrayIdx >= mArraySize)
+		{
+			LOGWRN("Array index out of range. Provided index was " + toString(arrayIdx) + 
+				" but array length is " + toString(mArraySize));
+			return;
+		}
+
+		mMaterialParams->setDataParam(mParamIndex + arrayIdx, value);
+
+		if (mGPUParams != nullptr)
+		{
+			for (auto& param : *mGPUParams)
+				param.set(value, arrayIdx);
+		}
+	}
+
+	template<class T>
+	T TMaterialDataParam<T, false>::get(UINT32 arrayIdx)
+	{
+		T output;
+		if (mMaterialParams == nullptr || arrayIdx >= mArraySize)
+			return output;
+
+		mMaterialParams->getDataParam(mParamIndex + arrayIdx, output);
+		return output;
+	}
+
+	template<class T>
+	TMaterialDataParam<T, true>::TMaterialDataParam(const SPtr<Vector<TGpuDataParam<T, true>>>& params)
+		:mParams(params)
+	{ }
+
+	template<class T>
+	void TMaterialDataParam<T, true>::set(const T& value, UINT32 arrayIdx)
+	{
+		if (mParams == nullptr)
+			return;
+
+		for (auto& param : *mParams)
+			param.set(value, arrayIdx);
+	}
+
+	template<class T>
+	T TMaterialDataParam<T, true>::get(UINT32 arrayIdx)
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+			return T();
+
+		return (*mParams)[0].get(arrayIdx); // They should all have the same value
+	}
+
+	TMaterialParamStruct<false>::TMaterialParamStruct(const String& name, const SPtr<__MaterialParams>& params, 
+		const SPtr<Vector<TGpuParamStruct<false>>>& gpuParams)
+		:mParamIndex(0), mArraySize(0), mMaterialParams(params), mGPUParams(gpuParams)
+	{
+		if (params != nullptr)
+		{
+			const __MaterialParams::ParamData* data = params->getParamData(name, __MaterialParams::ParamType::Data,
+				GPDT_STRUCT, 0);
+
+			if (data != nullptr)
+			{
+				mParamIndex = data->index;
+				mArraySize = data->arraySize;
+			}
+		}
+	}
+
+	void TMaterialParamStruct<false>::set(const void* value, UINT32 sizeBytes, UINT32 arrayIdx)
+	{
+		if (mMaterialParams == nullptr)
+			return;
+
+		if (arrayIdx >= mArraySize)
+		{
+			LOGWRN("Array index out of range. Provided index was " + toString(arrayIdx) +
+				" but array length is " + toString(mArraySize));
+			return;
+		}
+
+		mMaterialParams->setStructData(mParamIndex + arrayIdx, value, sizeBytes);
+
+		if (mGPUParams != nullptr)
+		{
+			for (auto& param : *mGPUParams)
+				param.set(value, sizeBytes, arrayIdx);
+		}
+	}
+
+	void TMaterialParamStruct<false>::get(void* value, UINT32 sizeBytes, UINT32 arrayIdx)
+	{
+		if (mMaterialParams == nullptr || arrayIdx >= mArraySize)
+			return;
+
+		mMaterialParams->getStructData(mParamIndex + arrayIdx, value, sizeBytes);
+	}
+
+	TMaterialParamStruct<true>::TMaterialParamStruct(const SPtr<Vector<TGpuParamStruct<true>>>& params)
+		:mParams(params)
+	{ }
+
+	void TMaterialParamStruct<true>::set(const void* value, UINT32 sizeBytes, UINT32 arrayIdx)
+	{
+		if (mParams == nullptr)
+			return;
+
+		for (auto& param : *mParams)
+			param.set(value, sizeBytes, arrayIdx);
+	}
+
+	void TMaterialParamStruct<true>::get(void* value, UINT32 sizeBytes, UINT32 arrayIdx)
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+		{
+			value = nullptr;
+			return;
+		}
+
+		return (*mParams)[0].get(value, sizeBytes, arrayIdx); // They should all have the same value
+	}
+
+	UINT32 TMaterialParamStruct<true>::getElementSize() const
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+			return 0;
+
+		return (*mParams)[0].getElementSize();
+	}
+
+	TMaterialParamTexture<false>::TMaterialParamTexture(const String& name, const SPtr<__MaterialParams>& params, 
+		const SPtr<Vector<TGpuParamTexture<false>>>& gpuParams)
+		:mParamIndex(0), mMaterialParams(params), mGPUParams(gpuParams)
+	{
+		if (params != nullptr)
+		{
+			const __MaterialParams::ParamData* data = params->getParamData(name, __MaterialParams::ParamType::Texture,
+				GPDT_UNKNOWN, 0);
+
+			if (data != nullptr)
+				mParamIndex = data->index;
+		}
+	}
+
+	void TMaterialParamTexture<false>::set(const HTexture& texture)
+	{
+		if (mMaterialParams == nullptr)
+			return;
+
+		mMaterialParams->setTexture(mParamIndex, texture);
+
+		if (mGPUParams != nullptr)
+		{
+			for (auto& param : *mGPUParams)
+				param.set(texture);
+		}
+	}
+
+	HTexture TMaterialParamTexture<false>::get()
+	{
+		HTexture texture;
+		if (mMaterialParams == nullptr)
+			return texture;
+
+		mMaterialParams->getTexture(mParamIndex, texture);
+
+		return texture;
+	}
+
+	TMaterialParamTexture<true>::TMaterialParamTexture(const SPtr<Vector<TGpuParamTexture<true>>>& params)
+		:mParams(params)
+	{ }
+
+	void TMaterialParamTexture<true>::set(const SPtr<TextureCore>& texture)
+	{
+		if (mParams == nullptr)
+			return;
+
+		for (auto& param : *mParams)
+			param.set(texture);
+	}
+
+	SPtr<TextureCore> TMaterialParamTexture<true>::get()
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+			return SPtr<TextureCore>();
+
+		return (*mParams)[0].get(); // They should all have the same value
+	}
+
+	TMaterialParamLoadStoreTexture<false>::TMaterialParamLoadStoreTexture(const String& name, const SPtr<__MaterialParams>& params, 
+		const SPtr<Vector<TGpuParamLoadStoreTexture<false>>>& gpuParams)
+		:mParamIndex(0), mMaterialParams(params), mGPUParams(gpuParams)
+	{
+		if (params != nullptr)
+		{
+			const __MaterialParams::ParamData* data = params->getParamData(name, __MaterialParams::ParamType::Texture,
+				GPDT_UNKNOWN, 0);
+
+			if (data != nullptr)
+				mParamIndex = data->index;
+		}
+	}
+
+	void TMaterialParamLoadStoreTexture<false>::set(const HTexture& texture, const TextureSurface& surface)
+	{
+		if (mMaterialParams == nullptr)
+			return;
+
+		mMaterialParams->setLoadStoreTexture(mParamIndex, texture, surface);
+
+		if (mGPUParams != nullptr)
+		{
+			for (auto& param : *mGPUParams)
+				param.set(texture, surface);
+		}
+	}
+
+	HTexture TMaterialParamLoadStoreTexture<false>::get()
+	{
+		HTexture texture;
+		if (mMaterialParams == nullptr)
+			return texture;
+
+		TextureSurface surface;
+		mMaterialParams->getLoadStoreTexture(mParamIndex, texture, surface);
+
+		return texture;
+	}
+
+	TMaterialParamLoadStoreTexture<true>::TMaterialParamLoadStoreTexture(const SPtr<Vector<TGpuParamLoadStoreTexture<true>>>& params)
+		:mParams(params)
+	{ }
+
+	void TMaterialParamLoadStoreTexture<true>::set(const SPtr<TextureCore>& texture, const TextureSurface& surface)
+	{
+		if (mParams == nullptr)
+			return;
+
+		for (auto& param : *mParams)
+			param.set(texture, surface);
+	}
+
+	SPtr<TextureCore> TMaterialParamLoadStoreTexture<true>::get()
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+			return SPtr<TextureCore>();
+
+		return (*mParams)[0].get(); // They should all have the same value
+	}
+
+	TMaterialParamSampState<false>::TMaterialParamSampState(const String& name, const SPtr<__MaterialParams>& params, 
+		const SPtr<Vector<TGpuParamSampState<false>>>& gpuParams)
+		:mParamIndex(0), mMaterialParams(params), mGPUParams(gpuParams)
+	{
+		if (params != nullptr)
+		{
+			const __MaterialParams::ParamData* data = params->getParamData(name, __MaterialParams::ParamType::Sampler,
+				GPDT_UNKNOWN, 0);
+
+			if (data != nullptr)
+				mParamIndex = data->index;
+		}
+	}
+
+	void TMaterialParamSampState<false>::set(const SPtr<SamplerState>& sampState)
+	{
+		if (mMaterialParams == nullptr)
+			return;
+
+		mMaterialParams->setSamplerState(mParamIndex, sampState);
+
+		if (mGPUParams != nullptr)
+		{
+			for (auto& param : *mGPUParams)
+				param.set(sampState);
+		}
+	}
+
+	SPtr<SamplerState> TMaterialParamSampState<false>::get()
+	{
+		SPtr<SamplerState> samplerState;
+		if (mMaterialParams == nullptr)
+			return samplerState;
+
+		mMaterialParams->getSamplerState(mParamIndex, samplerState);
+		return samplerState;
+	}
+
+	TMaterialParamSampState<true>::TMaterialParamSampState(const SPtr<Vector<TGpuParamSampState<true>>>& params)
+		:mParams(params)
+	{ }
+
+	void TMaterialParamSampState<true>::set(const SPtr<SamplerStateCore>& sampState)
+	{
+		if (mParams == nullptr)
+			return;
+
+		for (auto& param : *mParams)
+			param.set(sampState);
+	}
+
+	SPtr<SamplerStateCore> TMaterialParamSampState<true>::get()
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+			return SPtr<SamplerStateCore>();
+
+		return (*mParams)[0].get(); // They should all have the same value
+	}
+
+	template class TMaterialDataParam<float, false>;
+	template class TMaterialDataParam<int, false>;
+	template class TMaterialDataParam<Color, false>;
+	template class TMaterialDataParam<Vector2, false>;
+	template class TMaterialDataParam<Vector3, false>;
+	template class TMaterialDataParam<Vector4, false>;
+	template class TMaterialDataParam<Vector2I, false>;
+	template class TMaterialDataParam<Vector3I, false>;
+	template class TMaterialDataParam<Vector4I, false>;
+	template class TMaterialDataParam<Matrix2, false>;
+	template class TMaterialDataParam<Matrix2x3, false>;
+	template class TMaterialDataParam<Matrix2x4, false>;
+	template class TMaterialDataParam<Matrix3, false>;
+	template class TMaterialDataParam<Matrix3x2, false>;
+	template class TMaterialDataParam<Matrix3x4, false>;
+	template class TMaterialDataParam<Matrix4, false>;
+	template class TMaterialDataParam<Matrix4x2, false>;
+	template class TMaterialDataParam<Matrix4x3, false>;
+
+	template class TMaterialDataParam<float, true>;
+	template class TMaterialDataParam<int, true>;
+	template class TMaterialDataParam<Color, true>;
+	template class TMaterialDataParam<Vector2, true>;
+	template class TMaterialDataParam<Vector3, true>;
+	template class TMaterialDataParam<Vector4, true>;
+	template class TMaterialDataParam<Vector2I, true>;
+	template class TMaterialDataParam<Vector3I, true>;
+	template class TMaterialDataParam<Vector4I, true>;
+	template class TMaterialDataParam<Matrix2, true>;
+	template class TMaterialDataParam<Matrix2x3, true>;
+	template class TMaterialDataParam<Matrix2x4, true>;
+	template class TMaterialDataParam<Matrix3, true>;
+	template class TMaterialDataParam<Matrix3x2, true>;
+	template class TMaterialDataParam<Matrix3x4, true>;
+	template class TMaterialDataParam<Matrix4, true>;
+	template class TMaterialDataParam<Matrix4x2, true>;
+	template class TMaterialDataParam<Matrix4x3, true>;
+
+	template class TMaterialParamStruct<false>;
+	template class TMaterialParamStruct<true>;
+
+	template class TMaterialParamTexture<false>;
+	template class TMaterialParamTexture<true>;
+
+	template class TMaterialParamLoadStoreTexture<false>;
+	template class TMaterialParamLoadStoreTexture<true>;
+
+	template class TMaterialParamSampState<false>;
+	template class TMaterialParamSampState<true>;
 }

+ 411 - 0
BansheeCore/Source/BsMaterialParams.cpp

@@ -0,0 +1,411 @@
+#include "BsMaterialParams.h"
+
+namespace BansheeEngine
+{
+	__MaterialParams::__MaterialParams(const HShader& shader)
+	{
+		GpuParamDataType dataTypes[] = { GPDT_FLOAT1, GPDT_FLOAT2, GPDT_FLOAT3, GPDT_FLOAT4, GPDT_INT1, GPDT_INT2, GPDT_INT3,
+			GPDT_INT4, GPDT_MATRIX_2X2, GPDT_MATRIX_2X3, GPDT_MATRIX_2X4, GPDT_MATRIX_3X3, GPDT_MATRIX_3X2, GPDT_MATRIX_3X4,
+			GPDT_MATRIX_4X4, GPDT_MATRIX_4X2, GPDT_MATRIX_4X3, GPDT_COLOR, GPDT_STRUCT };
+		UINT32* dataCounts[] = { &mNumFloatParams, &mNumVec2Params, &mNumVec3Params, &mNumVec4Params, &mNumIntParams, 
+			&mNumVec2IParams, &mNumVec3IParams, &mNumVec4IParams, &mNumMat2Params, &mNumMat2x3Params, &mNumMat2x4Params, 
+			&mNumMat3Params, &mNumMat3x2Params, &mNumMat3x4Params, &mNumMat4Params, &mNumMat4x2Params, &mNumMat4x3Params, 
+			&mNumColorParams, &mNumStructParams };
+
+		auto& dataParams = shader->getDataParams();
+		for (auto& param : dataParams)
+		{
+			for (UINT32 i = 0; i < sizeof(dataTypes); i++)
+			{
+				if (param.second.type == dataTypes[i])
+				{
+					UINT32 count = param.second.arraySize > 1 ? param.second.arraySize : 1;
+
+					*dataCounts[i] += count;
+					break;
+				}
+			}
+		}
+
+		auto& textureParams = shader->getTextureParams();
+		auto& samplerParams = shader->getSamplerParams();
+
+		mNumTextureParams = (UINT32)textureParams.size();
+		mNumSamplerParams = (UINT32)samplerParams.size();
+
+		mFloatParams = mAlloc.construct<float>(mNumFloatParams);
+		mVec2Params = mAlloc.construct<Vector2>(mNumVec2Params);
+		mVec3Params = mAlloc.construct<Vector3>(mNumVec3Params);
+		mVec4Params = mAlloc.construct<Vector4>(mNumVec4Params);
+
+		mIntParams = mAlloc.construct<int>(mNumIntParams);
+		mVec2IParams = mAlloc.construct<Vector2I>(mNumVec2IParams);
+		mVec3IParams = mAlloc.construct<Vector3I>(mNumVec3IParams);
+		mVec4IParams = mAlloc.construct<Vector4I>(mNumVec4IParams);
+
+		mMat2Params = mAlloc.construct<Matrix2>(mNumMat2Params);
+		mMat2x3Params = mAlloc.construct<Matrix2x3>(mNumMat2x3Params);
+		mMat2x4Params = mAlloc.construct<Matrix2x4>(mNumMat2x4Params);
+		mMat3Params = mAlloc.construct<Matrix3>(mNumMat3Params);
+		mMat3x2Params = mAlloc.construct<Matrix3x2>(mNumMat3x2Params);
+		mMat3x4Params = mAlloc.construct<Matrix3x4>(mNumMat3x4Params);
+		mMat4Params = mAlloc.construct<Matrix4>(mNumMat4Params);
+		mMat4x2Params = mAlloc.construct<Matrix4x2>(mNumMat4x2Params);
+		mMat4x3Params = mAlloc.construct<Matrix4x3>(mNumMat4x3Params);
+
+		mColorParams = mAlloc.construct<Color>(mNumColorParams);
+		mStructParams = mAlloc.construct<StructParamData>(mNumStructParams);
+		mTextureParams = mAlloc.construct<TextureParamData>(mNumTextureParams);
+		mSamplerStateParams = mAlloc.construct<SamplerStatePtr>(mNumSamplerParams);
+
+		UINT32 mFloatIdx = 0;
+		UINT32 mVec2Idx = 0;
+		UINT32 mVec3Idx = 0;
+		UINT32 mVec4Idx = 0;
+		UINT32 mIntIdx = 0;
+		UINT32 mVec2IIdx = 0;
+		UINT32 mVec3IIdx = 0;
+		UINT32 mVec4IIdx = 0;
+		UINT32 mMat2Idx = 0;
+		UINT32 mMat2x3Idx = 0;
+		UINT32 mMat2x4Idx = 0;
+		UINT32 mMat3Idx = 0;
+		UINT32 mMat3x2Idx = 0;
+		UINT32 mMat3x4Idx = 0;
+		UINT32 mMat4Idx = 0;
+		UINT32 mMat4x2Idx = 0;
+		UINT32 mMat4x3Idx = 0;
+		UINT32 mColorIdx = 0;
+		UINT32 mStructIdx = 0;
+		UINT32 mTextureIdx = 0;
+		UINT32 mSamplerIdx = 0;
+
+		for (auto& entry : dataParams)
+		{
+			ParamData& dataParam = mParams[entry.first];
+
+			UINT32 arraySize = entry.second.arraySize > 1 ? entry.second.arraySize : 1;
+			dataParam.arraySize = arraySize;
+			dataParam.type = ParamType::Data;
+			dataParam.dataType = entry.second.type;
+			dataParam.index = 0;
+
+			switch (entry.second.type)
+			{
+			case GPDT_FLOAT1:
+				for (UINT32 i = 0; i < arraySize; i++)
+					mFloatParams[mFloatIdx + i] = 0.0f;
+
+				dataParam.index = mFloatIdx;
+				mFloatIdx += arraySize;
+				break;
+			case GPDT_FLOAT2:
+				dataParam.index = mVec2Idx;
+				mVec2Idx += arraySize;
+				break;
+			case GPDT_FLOAT3:
+				dataParam.index = mVec3Idx;
+				mVec3Idx += arraySize;
+				break;
+			case GPDT_FLOAT4:
+				dataParam.index = mVec4Idx;
+				mVec4Idx += arraySize;
+				break;
+			case GPDT_INT1:
+				dataParam.index = mIntIdx;
+				mIntIdx += arraySize;
+				break;
+			case GPDT_INT2:
+				dataParam.index = mVec2IIdx;
+				mVec2IIdx += arraySize;
+				break;
+			case GPDT_INT3:
+				dataParam.index = mVec3IIdx;
+				mVec3IIdx += arraySize;
+				break;
+			case GPDT_INT4:
+				dataParam.index = mVec4IIdx;
+				mVec4IIdx += arraySize;
+				break;
+			case GPDT_MATRIX_2X2:
+				dataParam.index = mMat2Idx;
+				mMat2Idx += arraySize;
+				break;
+			case GPDT_MATRIX_2X3:
+				dataParam.index = mMat2x3Idx;
+				mMat2x3Idx += arraySize;
+				break;
+			case GPDT_MATRIX_2X4:
+				dataParam.index = mMat2x4Idx;
+				mMat2x4Idx += arraySize;
+				break;
+			case GPDT_MATRIX_3X3:
+				dataParam.index = mMat3Idx;
+				mMat3Idx += arraySize;
+				break;
+			case GPDT_MATRIX_3X2:
+				dataParam.index = mMat3x2Idx;
+				mMat3x2Idx += arraySize;
+				break;
+			case GPDT_MATRIX_3X4:
+				dataParam.index = mMat3x4Idx;
+				mMat3x4Idx += arraySize;
+				break;
+			case GPDT_MATRIX_4X4:
+				dataParam.index = mMat4Idx;
+				mMat4Idx += arraySize;
+				break;
+			case GPDT_MATRIX_4X2:
+				dataParam.index = mMat4x2Idx;
+				mMat4x2Idx += arraySize;
+				break;
+			case GPDT_MATRIX_4X3:
+				dataParam.index = mMat4x3Idx;
+				mMat4x3Idx += arraySize;
+				break;
+			case GPDT_COLOR:
+				dataParam.index = mColorIdx;
+				mColorIdx += arraySize;
+				break;
+			case GPDT_STRUCT:
+			{
+				StructParamData& param = mStructParams[mStructIdx];
+				param.dataSize = entry.second.elementSize;
+				param.data = mAlloc.alloc(param.dataSize);
+
+				dataParam.index = mStructIdx;
+				mStructIdx += arraySize;
+			}
+			break;
+			}
+		}
+
+		for (auto& entry : textureParams)
+		{
+			ParamData& dataParam = mParams[entry.first];
+
+			dataParam.arraySize = 1;
+			dataParam.type = ParamType::Texture;
+			dataParam.dataType = GPDT_UNKNOWN;
+			dataParam.index = mTextureIdx;
+
+			TextureParamData& param = mTextureParams[mTextureIdx];
+			param.isLoadStore = false;
+
+			mTextureIdx++;
+		}
+
+		for (auto& entry : samplerParams)
+		{
+			ParamData& dataParam = mParams[entry.first];
+
+			dataParam.arraySize = 1;
+			dataParam.type = ParamType::Sampler;
+			dataParam.dataType = GPDT_UNKNOWN;
+			dataParam.index = mSamplerIdx;
+
+			mSamplerIdx++;
+		}
+	}
+
+	__MaterialParams::~__MaterialParams()
+	{
+		if (mStructParams != nullptr)
+		{
+			for (UINT32 i = 0; mNumStructParams; i++)
+				mAlloc.free(mStructParams[i].data);
+		}
+
+		mAlloc.destruct(mFloatParams, mNumFloatParams);
+		mAlloc.destruct(mVec2Params, mNumVec2Params);
+		mAlloc.destruct(mVec3Params, mNumVec3Params);
+		mAlloc.destruct(mVec4Params, mNumVec4Params);
+
+		mAlloc.destruct(mIntParams, mNumIntParams);
+		mAlloc.destruct(mVec2IParams, mNumVec2IParams);
+		mAlloc.destruct(mVec3IParams, mNumVec3IParams);
+		mAlloc.destruct(mVec4IParams, mNumVec4IParams);
+
+		mAlloc.destruct(mMat2Params, mNumMat2Params);
+		mAlloc.destruct(mMat2x3Params, mNumMat2x3Params);
+		mAlloc.destruct(mMat2x4Params, mNumMat2x4Params);
+
+		mAlloc.destruct(mMat3Params, mNumMat3Params);
+		mAlloc.destruct(mMat3x2Params, mNumMat3x2Params);
+		mAlloc.destruct(mMat3x4Params, mNumMat3x4Params);
+
+		mAlloc.destruct(mMat4Params, mNumMat4Params);
+		mAlloc.destruct(mMat4x2Params, mNumMat4x2Params);
+		mAlloc.destruct(mMat4x3Params, mNumMat4x3Params);
+
+		mAlloc.destruct(mColorParams, mNumColorParams);
+		mAlloc.destruct(mStructParams, mNumStructParams);
+		mAlloc.destruct(mTextureParams, mNumTextureParams);
+		mAlloc.destruct(mSamplerStateParams, mNumSamplerParams);
+
+		mAlloc.clear();
+	}
+
+	void __MaterialParams::getStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx)
+	{
+		const ParamData* param = getParamData(name, ParamType::Data, GPDT_STRUCT, arrayIdx);
+		if (param == nullptr)
+			return;
+
+		getStructData(param->index + arrayIdx, value, size);
+	}
+
+	void __MaterialParams::setStructData(const String& name, const void* value, UINT32 size, UINT32 arrayIdx)
+	{
+		const ParamData* param = getParamData(name, ParamType::Data, GPDT_STRUCT, arrayIdx);
+		if (param == nullptr)
+			return;
+
+		setStructData(param->index + arrayIdx, value, size);
+	}
+
+	void __MaterialParams::getTexture(const String& name, HTexture& value)
+	{
+		const ParamData* param = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0);
+		if (param == nullptr)
+			return;
+
+		getTexture(param->index, value);
+	}
+
+	void __MaterialParams::setTexture(const String& name, const HTexture& value)
+	{
+		const ParamData* param = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0);
+		if (param == nullptr)
+			return;
+
+		setTexture(param->index, value);
+	}
+
+	void __MaterialParams::getLoadStoreTexture(const String& name, HTexture& value, TextureSurface& surface)
+	{
+		const ParamData* param = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0);
+		if (param == nullptr)
+			return;
+
+		getLoadStoreTexture(param->index, value, surface);
+	}
+
+	void __MaterialParams::setLoadStoreTexture(const String& name, const HTexture& value, const TextureSurface& surface)
+	{
+		const ParamData* param = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0);
+		if (param == nullptr)
+			return;
+
+		setLoadStoreTexture(param->index, value, surface);
+	}
+
+	void __MaterialParams::getSamplerState(const String& name, SamplerStatePtr& value)
+	{
+		const ParamData* param = getParamData(name, ParamType::Sampler, GPDT_UNKNOWN, 0);
+		if (param == nullptr)
+			return;
+
+		getSamplerState(param->index, value);
+	}
+
+	void __MaterialParams::setSamplerState(const String& name, const SamplerStatePtr& value)
+	{
+		const ParamData* param = getParamData(name, ParamType::Sampler, GPDT_UNKNOWN, 0);
+		if (param == nullptr)
+			return;
+
+		setSamplerState(param->index, value);
+	}
+
+	const __MaterialParams::ParamData* __MaterialParams::getParamData(const String& name, ParamType type, GpuParamDataType dataType,
+		UINT32 arrayIdx)
+	{
+		auto iterFind = mParams.find(name);
+		if (iterFind == mParams.end())
+		{
+			LOGWRN("Material doesn't have a parameter named " + name + ".");
+			return nullptr;
+		}
+
+		const ParamData& param = iterFind->second;
+		if (param.type != type || (type == ParamType::Data && param.dataType != dataType))
+		{
+			LOGWRN("Parameter \"" + name + "\" is not of the requested type.");
+			return nullptr;
+		}
+
+		if (arrayIdx >= param.arraySize)
+		{
+			LOGWRN("Parameter \"" + name + "\" array index " + toString(arrayIdx) + " out of range. Array length is " +
+				toString(param.arraySize) + ".");
+			return nullptr;
+		}
+
+		return &param;
+	}
+
+	void __MaterialParams::getStructData(UINT32 index, void* value, UINT32 size)
+	{
+		const StructParamData& structParam = mStructParams[index];
+		if (structParam.dataSize != size)
+		{
+			LOGWRN("Size mismatch when writing to a struct. Provided size was " + toString(size) + " bytes but the "
+				"struct size is" + toString(structParam.dataSize) + " bytes");
+			return;
+		}
+
+		memcpy(value, structParam.data, structParam.dataSize);
+	}
+
+	void __MaterialParams::setStructData(UINT32 index, const void* value, UINT32 size)
+	{
+		const StructParamData& structParam = mStructParams[index];
+		if (structParam.dataSize != size)
+		{
+			LOGWRN("Size mismatch when writing to a struct. Provided size was " + toString(size) + " bytes but the "
+				"struct size is" + toString(structParam.dataSize) + " bytes");
+			return;
+		}
+
+		memcpy(structParam.data, value, structParam.dataSize);
+	}
+
+	void __MaterialParams::getTexture(UINT32 index, HTexture& value)
+	{
+		TextureParamData& textureParam = mTextureParams[index];
+		value = textureParam.value;
+	}
+
+	void __MaterialParams::setTexture(UINT32 index, const HTexture& value)
+	{
+		TextureParamData& textureParam = mTextureParams[index];
+		textureParam.value = value;
+		textureParam.isLoadStore = false;
+	}
+
+	void __MaterialParams::getLoadStoreTexture(UINT32 index, HTexture& value, TextureSurface& surface)
+	{
+		TextureParamData& textureParam = mTextureParams[index];
+		value = textureParam.value;
+		surface = textureParam.surface;
+	}
+
+	void __MaterialParams::setLoadStoreTexture(UINT32 index, const HTexture& value, const TextureSurface& surface)
+	{
+		TextureParamData& textureParam = mTextureParams[index];
+		textureParam.value = value;
+		textureParam.isLoadStore = true;
+		textureParam.surface = surface;
+	}
+
+	void __MaterialParams::getSamplerState(UINT32 index, SamplerStatePtr& value)
+	{
+		value = mSamplerStateParams[index];
+	}
+
+	void __MaterialParams::setSamplerState(UINT32 index, const SamplerStatePtr& value)
+	{
+		mSamplerStateParams[index] = value;
+	}
+}

+ 53 - 0
BansheeUtility/Include/BsStaticAlloc.h

@@ -77,6 +77,9 @@ namespace BansheeEngine
 		 */
 		UINT8* alloc(UINT32 amount)
 		{
+			if (amount == 0)
+				return nullptr;
+
 #if BS_DEBUG_MODE
 			amount += sizeof(UINT32);
 #endif
@@ -102,6 +105,9 @@ namespace BansheeEngine
 		/** Deallocates a previously allocated piece of memory. */
 		void free(void* data)
 		{
+			if (data == nullptr)
+				return;
+
 			// Dealloc is only used for debug and can be removed if needed. All the actual deallocation
 			// happens in clear()
 
@@ -114,6 +120,53 @@ namespace BansheeEngine
 #endif
 		}
 
+		/**
+		 * Allocates enough memory to hold the object(s) of specified type using the static allocator, and constructs them.
+		 */
+		template<class T>
+		T* construct(UINT32 count = 0)
+		{
+			T* data = (T*)alloc(sizeof(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 static allocator, and constructs them.
+		 */
+		template<class T, class... Args>
+		T* construct(Args &&...args, UINT32 count = 0)
+		{
+			T* data = (T*)alloc(sizeof(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 static allocator. */
+		template<class T>
+		void destruct(T* data)
+		{
+			data->~T();
+
+			free(data);
+		}
+
+		/** Destructs and deallocates an array of objects allocated with the static frame allocator. */
+		template<class T>
+		void destruct(T* data, UINT32 count)
+		{
+			for(unsigned int i = 0; i < count; i++)
+				data[i].~T();
+
+			free(data);
+		}
+
 		/** Frees the internal memory buffers. All external allocations must be freed before calling this. */
 		void clear()
 		{