Ver Fonte

Add support to custom uniforms

Daniele Bartolini há 12 anos atrás
pai
commit
be86e86f48

+ 3 - 0
engine/Config.h.in

@@ -43,3 +43,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 #define CROWN_MAX_SHADERS			1024
 #define CROWN_MAX_GPU_PROGRAMS		1024
 #define CROWN_MAX_UNIFORMS			128
+
+// Including NUL character
+#define CROWN_MAX_UNIFORM_NAME_LENGTH	64

+ 1 - 28
engine/renderers/CommandBuffer.h

@@ -27,40 +27,13 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "Assert.h"
+#include "RendererTypes.h"
 
 namespace crown
 {
 
 #define MAX_COMMAND_BUFFER_SIZE 1024 * 1024
 
-enum CommandType
-{
-	COMMAND_INIT_RENDERER,
-	COMMAND_SHUTDOWN_RENDERER,
-
-	COMMAND_CREATE_VERTEX_BUFFER,
-	COMMAND_UPDATE_VERTEX_BUFFER,
-	COMMAND_DESTROY_VERTEX_BUFFER,
-
-	COMMAND_CREATE_INDEX_BUFFER,
-	COMMAND_DESTROY_INDEX_BUFFER,
-
-	COMMAND_CREATE_TEXTURE,
-	COMMAND_UPDATE_TEXTURE,
-	COMMAND_DESTROY_TEXTURE,
-
-	COMMAND_CREATE_SHADER,
-	COMMAND_DESTROY_SHADER,
-
-	COMMAND_CREATE_GPU_PROGRAM,
-	COMMAND_DESTROY_GPU_PROGRAM,
-
-	COMMAND_CREATE_UNIFORM,
-	COMMAND_DESTROY_UNIFORM,
-
-	COMMAND_END
-};
-
 class CommandBuffer
 {
 public:

+ 3 - 31
engine/renderers/ConstantBuffer.h

@@ -27,42 +27,14 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "Assert.h"
+#include "RendererTypes.h"
 
 namespace crown
 {
 
-#define MAX_CONSTANT_BUFFER_SIZE 1024 * 1024
-
-enum UniformType
-{
-	UNIFORM_INTEGER_1,
-	UNIFORM_INTEGER_2,
-	UNIFORM_INTEGER_3,
-	UNIFORM_INTEGER_4,
-	UNIFORM_FLOAT_1,
-	UNIFORM_FLOAT_2,
-	UNIFORM_FLOAT_3,
-	UNIFORM_FLOAT_4,
-	UNIFORM_FLOAT_3_X_3,
-	UNIFORM_FLOAT_4_X_4,
-	UNIFORM_END
-};
+extern const size_t UNIFORM_SIZE_TABLE[UNIFORM_END];
 
-const size_t UNIFORM_SIZE_TABLE[UNIFORM_END] =
-{
-	sizeof(int32_t) * 1,
-	sizeof(int32_t) * 2,
-	sizeof(int32_t) * 3,
-	sizeof(int32_t) * 4,
-	sizeof(float) * 1,
-	sizeof(float) * 2,
-	sizeof(float) * 3,
-	sizeof(float) * 4,
-	sizeof(float) * 9,
-	sizeof(float) * 16
-};
-
-typedef Id UniformId;
+#define MAX_CONSTANT_BUFFER_SIZE 1024 * 1024
 
 class ConstantBuffer
 {

+ 1 - 68
engine/renderers/PixelFormat.h

@@ -27,78 +27,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "Types.h"
+#include "RendererTypes.h"
 
 namespace crown
 {
 
-// [0 - 2]		-> 8-bit
-// [3 - 11] 	-> 16-bit
-// [12 - 13]	-> 24-bit
-// [14 - 23]	-> 32-bit
-// [24 - 25]	-> 48-bit
-// [26 - 31]	-> 64-bit
-// [32 - 35]	-> 96-bit
-// [36 - 39]	-> 128-bit
-// 40			-> Unknown (0-bit)
-
-
-/// Enumerates pixel formats.
-enum PixelFormat
-{
-	PF_L_8 = 0,				///< Luminance only, 8-bit
-	PF_L_16 = 3,			///< Luminance only, 16-bit
-	PF_L_32 = 14,			///< Luminance only, 32-bit integer
-	PF_L_FLOAT_32 = 15,		///< Luminance only, 32-bit flaoting point
-
-	PF_LA_8 = 4,			///< Luminance and alpha, 8-bit each
-	PF_LA_16 = 16,			///< Luminance and alpha, 16-bit each
-	PF_LA_32 = 26,			///< Luminance and alpha, 32-bit integer each
-	PF_LA_FLOAT_32 = 27,	///< Luminance and alpha, 32-bit floating point each
-
-	PF_AL_8 = 5,			///< Luminance and alpha, 8-bit each
-	PF_AL_16 = 17,			///< Luminance and alpha, 16-bit each
-	PF_AL_32 = 28,			///< Luminance and alpha, 32-bit integer each
-	PF_AL_FLOAT_32 = 29,	///< Luminance and alpha, 32-bit floating point each
-
-	PF_RGB_8 = 12,			///< RGB values, 8-bit each
-	PF_RGB_16 = 24,			///< RGB values, 16-bit each
-	PF_RGB_32 = 32,			///< RGB values, 32-bit integer each
-	PF_RGB_FLOAT_32 = 33,	///< RGB values, 32-bit floating point each
-
-	PF_RGB_3_3_2 = 1,		///< Packed 8-bit RGB values
-	PF_RGB_5_6_5 = 6,		///< Packed 16-bit RGB values
-
-	PF_BGR_8 = 13,			///< BGR values, 8-bit each
-	PF_BGR_16 = 25,			///< BGR values, 16-bit each
-	PF_BGR_32 = 34,			///< BGR values, 32-bit integer each
-	PF_BGR_FLOAT_32 = 35,	///< BGR values, 32-bit floating point each
-
-	PF_BGR_2_3_3 = 2,		///< Packed 8-bit BGR values
-	PF_BGR_5_6_5 = 7,		///< Packed 16-bit BGR values
-
-	PF_RGBA_8 = 18,			///< RGBA values, 8-bit each
-	PF_RGBA_16 = 30,		///< RGBA values, 16-bit each
-	PF_RGBA_32 = 36,		///< RGBA values, 32-bit integer each
-	PF_RGBA_FLOAT_32 = 37,	///< RGBA values, 32-bit floating point each
-
-	PF_RGBA_4_4_4_4 = 8,	///< Packed 16-bit RGBA values
-	PF_RGBA_5_5_5_1 = 9,	///< Packed 16-bit RGBA values
-	PF_RGBA_8_8_8_8 = 19,	///< Packed 32-bit RGBA values
-	PF_RGBA_10_10_10_2 = 20,///< Packed 32-bit RGBA values
-
-	PF_ABGR_8 = 21,			///< ABGR values, 8-bit each
-	PF_ABGR_16 = 31,		///< ABGR values, 16-bit each
-	PF_ABGR_32 = 38,		///< ABGR values, 32-bit integer each
-	PF_ABGR_FLOAT_32 = 39,	///< ABGR values, 32-bit floating point each
-
-	PF_ABGR_4_4_4_4 = 10,	///< Packed 16-bit ABGR values
-	PF_ABGR_1_5_5_5 = 11,	///< Packed 16-bit ABGR values
-	PF_ABGR_8_8_8_8 = 22,	///< Packed 32-bit ABGR values
-	PF_ABGR_2_10_10_10 = 23,///< Packed 32-bit ABGR values
-
-	PF_UNKNOWN = 40
-};
-
 class Pixel
 {
 public:

+ 4 - 15
engine/renderers/RenderContext.h

@@ -31,24 +31,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "IdTable.h"
 #include "CommandBuffer.h"
 #include "ConstantBuffer.h"
+#include "RendererTypes.h"
 
 namespace crown
 {
 
-typedef Id VertexBufferId;
-typedef Id IndexBufferId;
-typedef Id RenderTargetId;
-typedef Id TextureId;
-typedef Id ShaderId;
-typedef Id GPUProgramId;
-typedef Id UniformId;
-
-enum ShaderType
-{
-	SHADER_VERTEX,
-	SHADER_FRAGMENT
-};
-
 #define MAX_RENDER_LAYERS			32
 #define MAX_RENDER_STATES			1024
 
@@ -228,13 +215,15 @@ struct RenderContext
 		m_constants.write_constant(id, type, value, num);
 	}
 
-	void set_texture(uint8_t unit, TextureId texture, uint32_t flags)
+	void set_texture(uint8_t unit, UniformId sampler_uniform, TextureId texture, uint32_t flags)
 	{
 		m_flags |= STATE_TEXTURE_0 << unit;
 
 		Sampler& sampler = m_state.samplers[unit];
 		sampler.sampler_id = texture;
 		sampler.flags |= SAMPLER_TEXTURE | flags;
+
+		set_uniform(sampler_uniform, UNIFORM_INTEGER_1, &unit, 1);
 	}
 
 	void set_layer_render_target(uint8_t layer, RenderTargetId target)

+ 2 - 9
engine/renderers/Renderer.h

@@ -36,13 +36,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-enum RenderTargetFormat
-{
-	RTF_RGB_8,		///< RGB values, 8-bit each
-	RTF_RGBA_8,		///< RGBA values, 8-bit each
-	RTF_D24			///< Depth
-};
-
 class RendererImplementation;
 
 class Renderer
@@ -511,9 +504,9 @@ public:
 		m_submit->set_uniform(id, type, value, num);
 	}
 
-	inline void set_texture(uint8_t unit, TextureId texture, uint32_t flags)
+	inline void set_texture(uint8_t unit, UniformId sampler_uniform, TextureId texture, uint32_t flags)
 	{
-		m_submit->set_texture(unit, texture, flags);
+		m_submit->set_texture(unit, sampler_uniform, texture, flags);
 	}
 
 	inline void set_layer_render_target(uint8_t layer, RenderTargetId target)

+ 205 - 0
engine/renderers/RendererTypes.h

@@ -0,0 +1,205 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include "IdTable.h"
+
+namespace crown
+{
+
+typedef Id VertexBufferId;
+typedef Id IndexBufferId;
+typedef Id RenderTargetId;
+typedef Id TextureId;
+typedef Id ShaderId;
+typedef Id GPUProgramId;
+typedef Id UniformId;
+
+enum ShaderType
+{
+	SHADER_VERTEX,
+	SHADER_FRAGMENT
+};
+
+enum UniformType
+{
+	UNIFORM_INTEGER_1,
+	UNIFORM_INTEGER_2,
+	UNIFORM_INTEGER_3,
+	UNIFORM_INTEGER_4,
+	UNIFORM_FLOAT_1,
+	UNIFORM_FLOAT_2,
+	UNIFORM_FLOAT_3,
+	UNIFORM_FLOAT_4,
+	UNIFORM_FLOAT_3_X_3,
+	UNIFORM_FLOAT_4_X_4,
+	UNIFORM_END
+};
+
+enum RenderTargetFormat
+{
+	RTF_RGB_8,		///< RGB values, 8-bit each
+	RTF_RGBA_8,		///< RGBA values, 8-bit each
+	RTF_D24			///< Depth
+};
+
+enum ShaderUniform
+{
+	UNIFORM_VIEW					= 0,
+	UNIFORM_MODEL					= 1,
+	UNIFORM_MODEL_VIEW				= 2,
+	UNIFORM_MODEL_VIEW_PROJECTION	= 3,
+	UNIFORM_TIME_SINCE_START		= 4,
+	UNIFORM_COUNT
+};
+
+enum ShaderAttrib
+{
+	ATTRIB_POSITION			= 0,
+	ATTRIB_NORMAL			= 1,
+	ATTRIB_COLOR			= 2,
+	ATTRIB_TEX_COORD0		= 3,
+	ATTRIB_TEX_COORD1		= 4,
+	ATTRIB_TEX_COORD2		= 5,
+	ATTRIB_TEX_COORD3		= 6,
+	ATTRIB_COUNT
+};
+
+enum VertexFormat
+{
+	VERTEX_P2 = 0,
+	VERTEX_P2_N3,
+	VERTEX_P2_C4,
+	VERTEX_P2_T2,
+	VERTEX_P2_N3_C4,
+	VERTEX_P2_N3_C4_T2,
+
+	VERTEX_P3,
+	VERTEX_P3_N3,
+	VERTEX_P3_C4,
+	VERTEX_P3_T2,
+	VERTEX_P3_N3_C4,
+	VERTEX_P3_N3_C4_T2,
+
+	VERTEX_COUNT
+};
+
+// [0 - 2]		-> 8-bit
+// [3 - 11] 	-> 16-bit
+// [12 - 13]	-> 24-bit
+// [14 - 23]	-> 32-bit
+// [24 - 25]	-> 48-bit
+// [26 - 31]	-> 64-bit
+// [32 - 35]	-> 96-bit
+// [36 - 39]	-> 128-bit
+// 40			-> Unknown (0-bit)
+/// Enumerates pixel formats.
+enum PixelFormat
+{
+	PF_L_8 = 0,				///< Luminance only, 8-bit
+	PF_L_16 = 3,			///< Luminance only, 16-bit
+	PF_L_32 = 14,			///< Luminance only, 32-bit integer
+	PF_L_FLOAT_32 = 15,		///< Luminance only, 32-bit flaoting point
+
+	PF_LA_8 = 4,			///< Luminance and alpha, 8-bit each
+	PF_LA_16 = 16,			///< Luminance and alpha, 16-bit each
+	PF_LA_32 = 26,			///< Luminance and alpha, 32-bit integer each
+	PF_LA_FLOAT_32 = 27,	///< Luminance and alpha, 32-bit floating point each
+
+	PF_AL_8 = 5,			///< Luminance and alpha, 8-bit each
+	PF_AL_16 = 17,			///< Luminance and alpha, 16-bit each
+	PF_AL_32 = 28,			///< Luminance and alpha, 32-bit integer each
+	PF_AL_FLOAT_32 = 29,	///< Luminance and alpha, 32-bit floating point each
+
+	PF_RGB_8 = 12,			///< RGB values, 8-bit each
+	PF_RGB_16 = 24,			///< RGB values, 16-bit each
+	PF_RGB_32 = 32,			///< RGB values, 32-bit integer each
+	PF_RGB_FLOAT_32 = 33,	///< RGB values, 32-bit floating point each
+
+	PF_RGB_3_3_2 = 1,		///< Packed 8-bit RGB values
+	PF_RGB_5_6_5 = 6,		///< Packed 16-bit RGB values
+
+	PF_BGR_8 = 13,			///< BGR values, 8-bit each
+	PF_BGR_16 = 25,			///< BGR values, 16-bit each
+	PF_BGR_32 = 34,			///< BGR values, 32-bit integer each
+	PF_BGR_FLOAT_32 = 35,	///< BGR values, 32-bit floating point each
+
+	PF_BGR_2_3_3 = 2,		///< Packed 8-bit BGR values
+	PF_BGR_5_6_5 = 7,		///< Packed 16-bit BGR values
+
+	PF_RGBA_8 = 18,			///< RGBA values, 8-bit each
+	PF_RGBA_16 = 30,		///< RGBA values, 16-bit each
+	PF_RGBA_32 = 36,		///< RGBA values, 32-bit integer each
+	PF_RGBA_FLOAT_32 = 37,	///< RGBA values, 32-bit floating point each
+
+	PF_RGBA_4_4_4_4 = 8,	///< Packed 16-bit RGBA values
+	PF_RGBA_5_5_5_1 = 9,	///< Packed 16-bit RGBA values
+	PF_RGBA_8_8_8_8 = 19,	///< Packed 32-bit RGBA values
+	PF_RGBA_10_10_10_2 = 20,///< Packed 32-bit RGBA values
+
+	PF_ABGR_8 = 21,			///< ABGR values, 8-bit each
+	PF_ABGR_16 = 31,		///< ABGR values, 16-bit each
+	PF_ABGR_32 = 38,		///< ABGR values, 32-bit integer each
+	PF_ABGR_FLOAT_32 = 39,	///< ABGR values, 32-bit floating point each
+
+	PF_ABGR_4_4_4_4 = 10,	///< Packed 16-bit ABGR values
+	PF_ABGR_1_5_5_5 = 11,	///< Packed 16-bit ABGR values
+	PF_ABGR_8_8_8_8 = 22,	///< Packed 32-bit ABGR values
+	PF_ABGR_2_10_10_10 = 23,///< Packed 32-bit ABGR values
+
+	PF_UNKNOWN = 40
+};
+
+enum CommandType
+{
+	COMMAND_INIT_RENDERER,
+	COMMAND_SHUTDOWN_RENDERER,
+
+	COMMAND_CREATE_VERTEX_BUFFER,
+	COMMAND_UPDATE_VERTEX_BUFFER,
+	COMMAND_DESTROY_VERTEX_BUFFER,
+
+	COMMAND_CREATE_INDEX_BUFFER,
+	COMMAND_DESTROY_INDEX_BUFFER,
+
+	COMMAND_CREATE_TEXTURE,
+	COMMAND_UPDATE_TEXTURE,
+	COMMAND_DESTROY_TEXTURE,
+
+	COMMAND_CREATE_SHADER,
+	COMMAND_DESTROY_SHADER,
+
+	COMMAND_CREATE_GPU_PROGRAM,
+	COMMAND_DESTROY_GPU_PROGRAM,
+
+	COMMAND_CREATE_UNIFORM,
+	COMMAND_DESTROY_UNIFORM,
+
+	COMMAND_END
+};
+
+} // namespace crown

+ 2 - 31
engine/renderers/VertexFormat.h

@@ -26,39 +26,10 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-namespace crown
-{
+#include "RendererTypes.h"
 
-enum ShaderAttrib
-{
-	ATTRIB_POSITION			= 0,
-	ATTRIB_NORMAL			= 1,
-	ATTRIB_COLOR			= 2,
-	ATTRIB_TEX_COORD0		= 3,
-	ATTRIB_TEX_COORD1		= 4,
-	ATTRIB_TEX_COORD2		= 5,
-	ATTRIB_TEX_COORD3		= 6,
-	ATTRIB_COUNT
-};
-
-enum VertexFormat
+namespace crown
 {
-	VERTEX_P2 = 0,
-	VERTEX_P2_N3,
-	VERTEX_P2_C4,
-	VERTEX_P2_T2,
-	VERTEX_P2_N3_C4,
-	VERTEX_P2_N3_C4_T2,
-
-	VERTEX_P3,
-	VERTEX_P3_N3,
-	VERTEX_P3_C4,
-	VERTEX_P3_T2,
-	VERTEX_P3_N3_C4,
-	VERTEX_P3_N3_C4_T2,
-
-	VERTEX_COUNT
-};
 
 struct VertexFormatInfo
 {

+ 42 - 2
engine/renderers/gl/GLRenderer.cpp

@@ -82,6 +82,41 @@ const GLenum TEXTURE_WRAP_TABLE[] =
 	GL_REPEAT
 };
 
+// Keep in sync with ShaderAttrib
+const char* const SHADER_ATTRIB_NAMES[ATTRIB_COUNT] =
+{
+	"a_position",
+	"a_normal",
+	"a_color",
+	"a_tex_coord0",
+	"a_tex_coord1",
+	"a_tex_coord2",
+	"a_tex_coord3"
+};
+
+const char* const SHADER_UNIFORM_NAMES[] =
+{
+	"u_view",
+	"u_model",
+	"u_model_view",
+	"u_model_view_projection",
+	"u_time_since_start"
+};
+
+const size_t UNIFORM_SIZE_TABLE[UNIFORM_END] =
+{
+	sizeof(int32_t) * 1,
+	sizeof(int32_t) * 2,
+	sizeof(int32_t) * 3,
+	sizeof(int32_t) * 4,
+	sizeof(float) * 1,
+	sizeof(float) * 2,
+	sizeof(float) * 3,
+	sizeof(float) * 4,
+	sizeof(float) * 9,
+	sizeof(float) * 16
+};
+
 /// OpenGL renderer
 class RendererImplementation
 {
@@ -90,7 +125,7 @@ public:
 	//-----------------------------------------------------------------------------
 	RendererImplementation()
 		: m_max_texture_size(0), m_max_texture_units(0), m_max_vertex_indices(0), m_max_vertex_vertices(0),
-			m_max_anisotropy(0.0f)
+			m_max_anisotropy(0.0f), m_num_uniforms(0)
 	{
 		m_min_max_point_size[0] = 0.0f;
 		m_min_max_point_size[1] = 0.0f;
@@ -244,6 +279,8 @@ public:
 			{
 				const GPUProgram& gpu_program = m_gpu_programs[cur_state.program.index];
 				GL_CHECK(glUseProgram(gpu_program.m_id));
+				// Not necessarily here...
+				gpu_program.commit();
 
 				for (uint8_t uniform = 0; uniform < gpu_program.m_num_stock_uniforms; uniform++)
 				{
@@ -377,6 +414,7 @@ private:
 	Texture				m_textures[CROWN_MAX_TEXTURES];
 	Shader				m_shaders[CROWN_MAX_SHADERS];
 	GPUProgram			m_gpu_programs[CROWN_MAX_GPU_PROGRAMS];
+	uint32_t			m_num_uniforms;
 	Uniform				m_uniforms[CROWN_MAX_UNIFORMS];
 	RenderTarget		m_render_targets[CROWN_MAX_RENDER_TARGETS];
 
@@ -481,7 +519,7 @@ void Renderer::create_gpu_program_impl(GPUProgramId id, ShaderId vertex, ShaderI
 {
 	Shader& vs = m_impl->m_shaders[vertex.index];
 	Shader& ps = m_impl->m_shaders[pixel.index];
-	m_impl->m_gpu_programs[id.index].create(vs, ps);
+	m_impl->m_gpu_programs[id.index].create(vs, ps, m_impl->m_num_uniforms, m_impl->m_uniforms);
 }
 
 //-----------------------------------------------------------------------------
@@ -494,6 +532,7 @@ void Renderer::destroy_gpu_program_impl(GPUProgramId id)
 void Renderer::create_uniform_impl(UniformId id, const char* name, UniformType type, uint8_t num)
 {
 	m_impl->m_uniforms[id.index].create(name, type, num);
+	m_impl->m_num_uniforms++;
 }
 
 //-----------------------------------------------------------------------------
@@ -506,6 +545,7 @@ void Renderer::update_uniform_impl(UniformId id, size_t size, const void* data)
 void Renderer::destroy_uniform_impl(UniformId id)
 {
 	m_impl->m_uniforms[id.index].destroy();
+	m_impl->m_num_uniforms--;
 }
 
 // //-----------------------------------------------------------------------------

+ 96 - 55
engine/renderers/gl/GLRenderer.h

@@ -35,6 +35,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "GLContext.h"
 #include "HeapAllocator.h"
 #include "VertexFormat.h"
+#include "Allocator.h"
 
 namespace crown
 {
@@ -42,37 +43,9 @@ namespace crown
 extern const GLenum TEXTURE_MIN_FILTER_TABLE[];
 extern const GLenum TEXTURE_MAG_FILTER_TABLE[];
 extern const GLenum TEXTURE_WRAP_TABLE[];
-
-// Keep in sync with ShaderAttrib
-const char* const SHADER_ATTRIB_NAMES[ATTRIB_COUNT] =
-{
-	"a_position",
-	"a_normal",
-	"a_color",
-	"a_tex_coord0",
-	"a_tex_coord1",
-	"a_tex_coord2",
-	"a_tex_coord3"
-};
-
-enum ShaderUniform
-{
-	UNIFORM_VIEW					= 0,
-	UNIFORM_MODEL					= 1,
-	UNIFORM_MODEL_VIEW				= 2,
-	UNIFORM_MODEL_VIEW_PROJECTION	= 3,
-	UNIFORM_TIME_SINCE_START		= 4,
-	UNIFORM_COUNT
-};
-
-const char* const SHADER_UNIFORM_NAMES[] =
-{
-	"u_view",
-	"u_model",
-	"u_model_view",
-	"u_model_view_projection",
-	"u_time_since_start"
-};
+extern const char* const SHADER_ATTRIB_NAMES[ATTRIB_COUNT];
+extern const char* const SHADER_UNIFORM_NAMES[];
+extern const size_t UNIFORM_SIZE_TABLE[UNIFORM_END];
 
 static ShaderUniform name_to_stock_uniform(const char* uniform)
 {
@@ -177,6 +150,46 @@ public:
 	uint32_t	m_index_count;
 };
 
+//-----------------------------------------------------------------------------
+struct Uniform
+{
+	Uniform()
+	{
+		string::strncpy(m_name, "", CROWN_MAX_UNIFORM_NAME_LENGTH);
+	}
+
+	void create(const char* name, UniformType type, uint8_t num)
+	{
+		string::strncpy(m_name, name, CROWN_MAX_UNIFORM_NAME_LENGTH);
+		m_type = type;
+		m_num = num;
+
+		size_t size = UNIFORM_SIZE_TABLE[type] * num;
+		m_data = default_allocator().allocate(size);
+		memset(m_data, 0, size);
+
+		// Log::d("Uniform created, name = %s, type = %d, num = %d, size = %d", m_name, type, num, size);
+	}
+
+	void update(size_t size, const void* data)
+	{
+		// Log::d("Uniform updated, new size = %d, new ptr = %d", size, *((int32_t*)data));
+		memcpy(m_data, data, size);
+	}
+
+	void destroy()
+	{
+		default_allocator().deallocate(m_data);
+	}
+
+public:
+
+	char m_name[CROWN_MAX_UNIFORM_NAME_LENGTH];
+	UniformType m_type;
+	uint8_t m_num;
+	void* m_data;
+};
+
 //-----------------------------------------------------------------------------
 struct Shader
 {
@@ -282,7 +295,7 @@ public:
 struct GPUProgram
 {
 	//-----------------------------------------------------------------------------
-	void create(const Shader& vertex, const Shader& pixel)
+	void create(const Shader& vertex, const Shader& pixel, uint32_t num_uniforms, Uniform* uniforms)
 	{
 		m_id = GL_CHECK(glCreateProgram());
 
@@ -339,6 +352,8 @@ struct GPUProgram
 			}
 		}
 
+		m_num_stock_uniforms = 0;
+		m_num_uniforms = 0;
 		for (GLint uniform = 0; uniform < num_active_uniforms; uniform++)
 		{
 			GLint uniform_size;
@@ -354,6 +369,19 @@ struct GPUProgram
 				m_stock_uniform_locations[m_num_stock_uniforms] = uniform_location;
 				m_num_stock_uniforms++;
 			}
+			else
+			{
+				for (uint32_t i = 0; i < num_uniforms; i++)
+				{
+					if (string::strcmp(uniforms[i].m_name, uniform_name) == 0)
+					{
+						m_uniforms[m_num_uniforms] = uniforms[i].m_type;
+						m_uniform_info[m_num_uniforms].loc = uniform_location;
+						m_uniform_info[m_num_uniforms].data = uniforms[i].m_data;
+						m_num_uniforms++;
+					}
+				}
+			}
 
 			Log::d("Uniform %d: name = '%s' location = '%d' stock = %s", uniform, uniform_name, uniform_location,
 						(stock_uniform != UNIFORM_COUNT) ? "yes" : "no");
@@ -387,6 +415,32 @@ struct GPUProgram
 		}
 	}
 
+	//-----------------------------------------------------------------------------
+	void commit() const
+	{
+		for (uint8_t i = 0; i < m_num_uniforms; i++)
+		{
+			const UniformType type = m_uniforms[i];
+			const GLint loc = m_uniform_info[i].loc;
+			const void* data = m_uniform_info[i].data;
+
+			switch (type)
+			{
+				case UNIFORM_INTEGER_1:   GL_CHECK(glUniform1iv(loc, 1, (const GLint*)data)); break;
+				case UNIFORM_INTEGER_2:   GL_CHECK(glUniform2iv(loc, 2, (const GLint*)data)); break;
+				case UNIFORM_INTEGER_3:   GL_CHECK(glUniform3iv(loc, 3, (const GLint*)data)); break;				
+				case UNIFORM_INTEGER_4:   GL_CHECK(glUniform4iv(loc, 4, (const GLint*)data)); break;
+				case UNIFORM_FLOAT_1:     GL_CHECK(glUniform1fv(loc, 1, (const GLfloat*)data)); break;
+				case UNIFORM_FLOAT_2:     GL_CHECK(glUniform2fv(loc, 2, (const GLfloat*)data)); break;
+				case UNIFORM_FLOAT_3:     GL_CHECK(glUniform3fv(loc, 3, (const GLfloat*)data)); break;
+				case UNIFORM_FLOAT_4:     GL_CHECK(glUniform4fv(loc, 4, (const GLfloat*)data)); break;
+				case UNIFORM_FLOAT_3_X_3: GL_CHECK(glUniformMatrix3fv(loc, 9, GL_FALSE, (const GLfloat*)data)); break;
+				case UNIFORM_FLOAT_4_X_4: GL_CHECK(glUniformMatrix4fv(loc, 16, GL_FALSE, (const GLfloat*)data)); break;
+				default: CE_ASSERT(false, "Oops, unknown uniform type"); break;
+			}
+		}
+	}
+
 public:
 
 	GLuint				m_id;
@@ -398,6 +452,16 @@ public:
 	uint8_t				m_num_stock_uniforms;
 	ShaderUniform		m_stock_uniforms[UNIFORM_COUNT];
 	GLint				m_stock_uniform_locations[UNIFORM_COUNT];
+
+	struct LocAndData
+	{
+		GLint loc;
+		void* data;
+	};
+
+	uint8_t				m_num_uniforms;
+	UniformType			m_uniforms[16];
+	LocAndData			m_uniform_info[16];
 };
 
 //-----------------------------------------------------------------------------
@@ -478,27 +542,4 @@ struct RenderTarget
 	GLuint m_gl_rbo;
 };
 
-struct Uniform
-{
-	void create(const char* name, UniformType type, uint8_t num)
-	{
-		Log::d("Uniform created, name = %s, type = %d, num = %d", name, type, num);
-	}
-
-	void update(size_t size, const void* data)
-	{
-		Log::d("Uniform updated, new size = %d, new ptr = %d", size, *((int32_t*)data));
-	}
-
-	void destroy()
-	{
-		Log::d("Uniform destroyed");
-	}
-
-public:
-
-	UniformType m_type;
-	uint8_t m_num;
-};
-
 } // namespace crown