Daniele Bartolini 11 anni fa
parent
commit
978addb1cd

+ 10 - 3
engine/compilers/bundle_compiler.cpp

@@ -34,6 +34,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "path.h"
 #include "disk_filesystem.h"
 #include "temp_allocator.h"
+#include "compile_options.h"
 #include <inttypes.h>
 
 namespace crown
@@ -51,7 +52,8 @@ namespace sprite_resource { extern void compile(Filesystem&, const char*, File*)
 namespace material_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace font_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace level_resource { extern void compile(Filesystem&, const char*, File*); }
-namespace shader_resource { extern void compile(Filesystem&, const char*, File*); }
+namespace shader_resource { extern void compile(const char*, CompileOptions&); }
+namespace sprite_animation_resource { extern void compile(Filesystem&, const char*, File*); }
 
 //-----------------------------------------------------------------------------
 BundleCompiler::BundleCompiler()
@@ -59,7 +61,7 @@ BundleCompiler::BundleCompiler()
 }
 
 //-----------------------------------------------------------------------------
-bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, const char* resource)
+bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, const char* platform, const char* resource)
 {
 	Vector<DynamicString> files(default_allocator());
 
@@ -182,7 +184,12 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 			}
 			else if (name.type == SHADER_TYPE)
 			{
-				shader_resource::compile(root_fs, filename, out_file);
+				CompileOptions opts(root_fs, out_file, platform);
+				shader_resource::compile(filename, opts);
+			}
+			else if (name.type == SPRITE_ANIMATION_TYPE)
+			{
+				sprite_animation_resource::compile(root_fs, filename, out_file);
 			}
 			else
 			{

+ 1 - 1
engine/compilers/bundle_compiler.h

@@ -42,7 +42,7 @@ public:
 	/// Compiles all the resources found in @a source_dir and puts them in @a bundle_dir.
 	/// If @a resource is not NULL, only that particular resource is compiled.
 	/// Returns true on success, false otherwise.
-	bool compile(const char* bundle_dir, const char* source_dir, const char* resource = NULL);
+	bool compile(const char* bundle_dir, const char* source_dir, const char* platform, const char* resource = NULL);
 
 private:
 

+ 2 - 0
engine/device.cpp

@@ -57,6 +57,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "lua_system.h"
 #include "debug_line.h"
 #include "material_manager.h"
+#include "gui.h"
 
 #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_WINDOWS
 	#include "bundle_compiler.h"
@@ -164,6 +165,7 @@ void Device::init()
 	CE_LOGD("Creating renderer...");
 	graphics_system::init();
 	debug_line::init();
+	Gui::init();
 
 	CE_LOGD("Creating material manager...");
 	material_manager::init();

+ 66 - 0
engine/lua/lua_material.cpp

@@ -0,0 +1,66 @@
+/*
+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.
+*/
+
+#include "lua_stack.h"
+#include "lua_environment.h"
+#include "material.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+static int material_set_float(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.get_material(1)->set_float(stack.get_string(2), stack.get_float(3));
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int material_set_vector2(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.get_material(1)->set_vector2(stack.get_string(2), stack.get_vector2(3));
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+static int material_set_vector3(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.get_material(1)->set_vector3(stack.get_string(2), stack.get_vector3(3));
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+void load_material(LuaEnvironment& env)
+{
+	env.load_module_function("Material", "set_float", material_set_float);
+	env.load_module_function("Material", "set_vector2", material_set_vector2);
+	env.load_module_function("Material", "set_vector3", material_set_vector3);
+}
+
+} // namespace crown

+ 13 - 1
engine/lua/lua_stack.h

@@ -88,10 +88,10 @@ struct Sprite;
 struct Unit;
 struct DebugLine;
 struct Raycast;
+struct Material;
 
 typedef Id SoundInstanceId;
 typedef Id GuiId;
-typedef Id GuiComponentId;
 
 typedef int (*MetamethodFunction)(lua_State*);
 
@@ -364,6 +364,18 @@ public:
 		return (Sprite*) CHECKLIGHTDATA(m_L, index, always_true, "Sprite");
 	}
 
+	//-----------------------------------------------------------------------------
+	void push_material(Material* material)
+	{
+		lua_pushlightuserdata(m_L, material);
+	}
+
+	//-----------------------------------------------------------------------------
+	Material* get_material(int32_t index)
+	{
+		return (Material*) CHECKLIGHTDATA(m_L, index, always_true, "Material");
+	}
+
 	//-----------------------------------------------------------------------------
 	void push_actor(Actor* actor)
 	{

+ 2 - 0
engine/lua/lua_system.cpp

@@ -75,6 +75,7 @@ extern void load_vector3box(LuaEnvironment& env);
 extern void load_window(LuaEnvironment& env);
 extern void load_world(LuaEnvironment& env);
 extern void load_color4(LuaEnvironment& env);
+extern void load_material(LuaEnvironment& env);
 
 namespace lua_system
 {
@@ -342,6 +343,7 @@ namespace lua_system
 		load_window(env);
 		load_world(env);
 		load_color4(env);
+		load_material(env);
 
 		// Register custom loader
 		lua_getfield(s_L, LUA_GLOBALSINDEX, "package");

+ 18 - 0
engine/lua/lua_unit.cpp

@@ -219,6 +219,23 @@ static int unit_camera(lua_State* L)
 	return 1;
 }
 
+//-----------------------------------------------------------------------------
+static int unit_material(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+
+	if (stack.is_number(2))
+	{
+		stack.push_material(unit->material((uint32_t) stack.get_int(2)));
+		return 1;
+	}
+
+	stack.push_material(unit->material(stack.get_string(2)));
+	return 1;
+}
+
 //-----------------------------------------------------------------------------
 static int unit_mesh(lua_State* L)
 {
@@ -409,6 +426,7 @@ void load_unit(LuaEnvironment& env)
 	env.load_module_function("Unit", "unlink_node",				unit_unlink_node);
 
 	env.load_module_function("Unit", "camera",					unit_camera);
+	env.load_module_function("Unit", "material",				unit_material);
 	env.load_module_function("Unit", "mesh",					unit_mesh);
 	env.load_module_function("Unit", "sprite",					unit_sprite);
 	env.load_module_function("Unit", "actor",					unit_actor);

+ 1 - 1
engine/lua/lua_world.cpp

@@ -198,7 +198,7 @@ static int world_create_window_gui(lua_State* L)
 	LuaStack stack(L);
 
 	World* world = stack.get_world(1);
-	GuiId id = world->create_window_gui(stack.get_int(2), stack.get_int(3));
+	GuiId id = world->create_window_gui(stack.get_int(2), stack.get_int(3), stack.get_string(4));
 
 	stack.push_gui(world->get_gui(id));
 	return 1;

+ 15 - 1
engine/os/linux/main.cpp

@@ -143,6 +143,7 @@ public:
 		, m_compile(0)
 		, m_continue(0)
 		, m_wait_console(0)
+		, m_platform("linux")
 	{
 	}
 
@@ -159,7 +160,7 @@ public:
 			if (m_compile == 1)
 			{
 				m_bundle_compiler = CE_NEW(default_allocator(), BundleCompiler);
-				if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir))
+				if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir, m_platform))
 				{
 					CE_DELETE(default_allocator(), m_bundle_compiler);
 					CE_LOGE("Exiting.");
@@ -561,6 +562,11 @@ public:
 
 			"  --source-dir <path>        Use <path> as the source directory for resource compilation.\n"
 			"  --compile                  Do a full compile of the resources.\n"
+			"  --platform <platform>      Compile resources for the given <platform>.\n"
+			"      Possible values for <platform> are:\n"
+			"          linux\n"
+			"          android\n"
+			"          windows\n"
 			"  --continue                 Continue the execution after the resource compilation step.\n"
 			"  --file-server              Read resources from a remote engine instance.\n"
 			"  --console-port             Set the network port of the console server.\n"
@@ -572,6 +578,7 @@ public:
 			{ "source-dir",       AOA_REQUIRED_ARGUMENT, NULL,           's' },
 			{ "bundle-dir",       AOA_REQUIRED_ARGUMENT, NULL,           'b' },
 			{ "compile",          AOA_NO_ARGUMENT,       &m_compile,       1 },
+			{ "platform",         AOA_REQUIRED_ARGUMENT, NULL,           'r' },
 			{ "continue",         AOA_NO_ARGUMENT,       &m_continue,      1 },
 			{ "width",            AOA_REQUIRED_ARGUMENT, NULL,           'w' },
 			{ "height",           AOA_REQUIRED_ARGUMENT, NULL,           'h' },
@@ -630,6 +637,12 @@ public:
 					m_console_port = string::parse_uint(args.optarg());
 					break;
 				}
+				// Platform
+				case 'r':
+				{
+					m_platform = args.optarg();
+					break;
+				}
 				case 'i':
 				case '?':
 				default:
@@ -735,6 +748,7 @@ private:
 	int32_t m_compile;
 	int32_t m_continue;
 	int32_t m_wait_console;
+	const char* m_platform;
 
 	OsEventQueue m_queue;
 };

+ 104 - 109
engine/renderers/gui.cpp

@@ -24,20 +24,15 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "gui.h"
-#include "assert.h"
-#include "vector3.h"
-#include "vector2.h"
-#include "render_world.h"
-#include "vector3.h"
-#include "vector2.h"
 #include "color4.h"
 #include "font_resource.h"
-#include "device.h"
-#include "os_window.h"
-#include "resource_manager.h"
-#include "texture_resource.h"
+#include "gui.h"
 #include "material_resource.h"
+#include "material_manager.h"
+#include "vector2.h"
+#include "vector3.h"
+#include "matrix4x4.h"
+#include <bgfx.h>
 
 namespace crown
 {
@@ -97,14 +92,35 @@ static uint32_t utf8_decode(uint32_t* state, uint32_t* code_point, uint8_t chara
 	return *state;
 }
 
+bgfx::VertexDecl Gui::s_pos_col;
+bgfx::VertexDecl Gui::s_pos_col_tex;
+
+void Gui::init()
+{
+	Gui::s_pos_col
+		.begin()
+		.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
+		.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
+		.end();
+
+	Gui::s_pos_col_tex
+		.begin()
+		.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
+		.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, true)
+		.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
+		.end();
+}
+
 //-----------------------------------------------------------------------------
-Gui::Gui(RenderWorld& render_world, uint16_t width, uint16_t height)
-	: m_render_world(render_world)
-	, m_width(width)
+Gui::Gui(uint16_t width, uint16_t height, const char* material)
+	: m_width(width)
 	, m_height(height)
 	, m_pose(matrix4x4::IDENTITY)
 {
 	set_orthographic_rh(m_projection, 0, width, 0, height, -0.01f, 100.0f);
+
+	ResourceId id("material", material);
+	m_material = material_manager::get()->create_material(id.name);
 }
 
 //-----------------------------------------------------------------------------
@@ -141,47 +157,36 @@ Vector2 Gui::screen_to_gui(const Vector2& pos)
 //-----------------------------------------------------------------------------
 void Gui::draw_rectangle(const Vector3& pos, const Vector2& size, const Color4& color)
 {
-	// Renderer* r = device()->renderer();
-	// TransientVertexBuffer tvb;
-	// TransientIndexBuffer tib;
-
-	// r->reserve_transient_vertex_buffer(&tvb, 4, VertexFormat::P2);
-	// r->reserve_transient_index_buffer(&tib, 6);
-
-	// float* verts = (float*) tvb.data;
-	// verts[0] = pos.x;
-	// verts[1] = pos.y;
-
-	// verts[2] = pos.x + size.x;
-	// verts[3] = pos.y;
-
-	// verts[4] = pos.x + size.x;
-	// verts[5] = pos.y + size.y;
-
-	// verts[6] = pos.x;
-	// verts[7] = pos.y + size.y;
-
-	// uint16_t* inds = (uint16_t*) tib.data;
-	// inds[0] = 0;
-	// inds[1] = 1;
-	// inds[2] = 2;
-	// inds[3] = 0;
-	// inds[4] = 2;
-	// inds[5] = 3;
-
-	// r->set_layer_view(1, matrix4x4::IDENTITY);
-	// r->set_layer_projection(1, m_projection);
-	// r->set_layer_viewport(1, 0, 0, m_width, m_height);
-	// r->set_state(STATE_COLOR_WRITE
-	// 				| STATE_CULL_CW
-	// 				| STATE_BLEND_EQUATION_ADD 
-	// 				| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-	// r->set_pose(m_pose);
-	// r->set_program(render_world_globals::default_color_program());
-	// r->set_uniform(render_world_globals::default_color_uniform(), UniformType::FLOAT_4, color4::to_float_ptr(color), 1);
-	// r->set_vertex_buffer(tvb);
-	// r->set_index_buffer(tib);
-	// r->commit(1, (int32_t) pos.z);
+	bgfx::TransientVertexBuffer tvb;
+	bgfx::TransientIndexBuffer tib;
+	bgfx::allocTransientVertexBuffer(&tvb, 4, Gui::s_pos_col);
+	bgfx::allocTransientIndexBuffer(&tib, 6);
+
+	float* verts = (float*) tvb.data;
+	verts[0] = pos.x;
+	verts[1] = pos.y;
+	verts[2] = pos.x + size.x;
+	verts[3] = pos.y;
+	verts[4] = pos.x + size.x;
+	verts[5] = pos.y + size.y;
+	verts[6] = pos.x;
+	verts[7] = pos.y + size.y;
+
+	uint16_t* inds = (uint16_t*) tib.data;
+	inds[0] = 0;
+	inds[1] = 1;
+	inds[2] = 2;
+	inds[3] = 0;
+	inds[4] = 2;
+	inds[5] = 3;
+
+	material_manager::get()->lookup_material(m_material)->bind();
+	bgfx::setViewTransform(1, matrix4x4::to_float_ptr(matrix4x4::IDENTITY), matrix4x4::to_float_ptr(m_projection));
+	bgfx::setViewRect(1, 0, 0, m_width, m_height);
+	bgfx::setState(BGFX_STATE_DEFAULT);
+	bgfx::setVertexBuffer(&tvb);
+	bgfx::setIndexBuffer(&tib);
+	bgfx::submit(1, (int32_t) pos.z);
 }
 
 //-----------------------------------------------------------------------------
@@ -193,60 +198,50 @@ void Gui::draw_image(const char* material, const Vector3& pos, const Vector2& si
 //-----------------------------------------------------------------------------
 void Gui::draw_image_uv(const char* material, const Vector3& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, const Color4& color)
 {
-	// Renderer* r = device()->renderer();
-	// TransientVertexBuffer tvb;
-	// TransientIndexBuffer tib;
-
-	// r->reserve_transient_vertex_buffer(&tvb, 4, VertexFormat::P2_T2);
-	// r->reserve_transient_index_buffer(&tib, 6);
-
-	// float* verts = (float*) tvb.data;
-	// verts[0] = pos.x;
-	// verts[1] = pos.y;
-	// verts[2] = uv0.x;
-	// verts[3] = uv0.y;
-
-	// verts[4] = pos.x + size.x;
-	// verts[5] = pos.y;
-	// verts[6] = uv1.x;
-	// verts[7] = uv0.y;
-
-	// verts[8] = pos.x + size.x;
-	// verts[9] = pos.y + size.y;
-	// verts[10] = uv1.x;
-	// verts[11] = uv1.y;
-
-	// verts[12] = pos.x;
-	// verts[13] = pos.y + size.y;
-	// verts[14] = uv0.x;
-	// verts[15] = uv1.y;
-
-	// uint16_t* inds = (uint16_t*) tib.data;
-	// inds[0] = 0;
-	// inds[1] = 1;
-	// inds[2] = 2;
-	// inds[3] = 0;
-	// inds[4] = 2;
-	// inds[5] = 3;
-
-	// const MaterialResource* mr = (MaterialResource*) device()->resource_manager()->get("material", material);
-	// const TextureResource* tr = (TextureResource*) device()->resource_manager()->get(mr->get_texture_layer(0));
-
-	// r->set_layer_view(1, matrix4x4::IDENTITY);
-	// r->set_layer_projection(1, m_projection);
-	// r->set_layer_viewport(1, 0, 0, m_width, m_height);
-	// r->set_state(STATE_COLOR_WRITE
-	// 				| STATE_CULL_CW
-	// 				| STATE_BLEND_EQUATION_ADD 
-	// 				| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-	// r->set_pose(m_pose);
-	// r->set_program(render_world_globals::default_texture_program());
-	// r->set_texture(0, render_world_globals::default_albedo_uniform(), tr->texture(),
-	// 				TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_U_CLAMP_REPEAT | TEXTURE_WRAP_V_CLAMP_REPEAT);
-	// r->set_uniform(render_world_globals::default_color_uniform(), UniformType::FLOAT_4, color4::to_float_ptr(color), 1);
-	// r->set_vertex_buffer(tvb);
-	// r->set_index_buffer(tib);
-	// r->commit(1, (int32_t) pos.z);
+	bgfx::TransientVertexBuffer tvb;
+	bgfx::TransientIndexBuffer tib;
+	bgfx::allocTransientVertexBuffer(&tvb, 4, Gui::s_pos_col_tex);
+	bgfx::allocTransientIndexBuffer(&tib, 6);
+
+	float* verts = (float*) tvb.data;
+	verts[0] = pos.x;
+	verts[1] = pos.y;
+	verts[2] = uv0.x;
+	verts[3] = uv0.y;
+
+	verts[4] = pos.x + size.x;
+	verts[5] = pos.y;
+	verts[6] = uv1.x;
+	verts[7] = uv0.y;
+
+	verts[8] = pos.x + size.x;
+	verts[9] = pos.y + size.y;
+	verts[10] = uv1.x;
+	verts[11] = uv1.y;
+
+	verts[12] = pos.x;
+	verts[13] = pos.y + size.y;
+	verts[14] = uv0.x;
+	verts[15] = uv1.y;
+
+	uint16_t* inds = (uint16_t*) tib.data;
+	inds[0] = 0;
+	inds[1] = 1;
+	inds[2] = 2;
+	inds[3] = 0;
+	inds[4] = 2;
+	inds[5] = 3;
+
+/*	ResourceId res_id("material", material);
+	Material* mat = material_manager::get()->lookup_material(res_id.name);
+	mat->bind();*/
+
+	bgfx::setViewTransform(1, matrix4x4::to_float_ptr(matrix4x4::IDENTITY), matrix4x4::to_float_ptr(m_projection));
+	bgfx::setViewRect(1, 0, 0, m_width, m_height);
+	bgfx::setState(BGFX_STATE_DEFAULT);
+	bgfx::setVertexBuffer(&tvb);
+	bgfx::setIndexBuffer(&tib);
+	bgfx::submit(1, (int32_t) pos.z);
 }
 
 //-----------------------------------------------------------------------------

+ 12 - 4
engine/renderers/gui.h

@@ -29,6 +29,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "math_types.h"
 #include "color4.h"
 #include "render_world_types.h"
+#include "material.h"
+#include <bgfx.h>
 
 namespace crown
 {
@@ -40,7 +42,7 @@ class RenderWorld;
 /// @ingroup Graphics
 struct Gui
 {
-	Gui(RenderWorld& render_world, uint16_t width, uint16_t height);
+	Gui(uint16_t width, uint16_t height, const char* material);
 
 	const GuiId id() const;
 	void set_id(const GuiId id);
@@ -68,14 +70,20 @@ struct Gui
 
 public:
 
-	RenderWorld& m_render_world;
 	GuiId m_id;
-
 	uint16_t m_width;
 	uint16_t m_height;
-
+	typedef Id MaterialId;
+	MaterialId m_material;
 	Matrix4x4 m_projection;
 	Matrix4x4 m_pose;
+
+	static void init();
+
+private:
+
+	static bgfx::VertexDecl s_pos_col;
+	static bgfx::VertexDecl s_pos_col_tex;
 };
 
 } // namespace crown

+ 43 - 98
engine/renderers/material.cpp

@@ -31,95 +31,15 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "device.h"
 #include "resource_manager.h"
 #include "texture_resource.h"
+#include "material_manager.h"
+#include "log.h"
+#include "shader.h"
 #include <bgfx.h>
 
-static const uint8_t vs_h[358] =
-{
-	0x56, 0x53, 0x48, 0x02, 0x8c, 0xd4, 0x10, 0xbd, 0x01, 0x00, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, 0x64, // VSH........u_mod
-	0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x01, 0x00, 0x00, 0x01, 0x00, // elViewProj......
-	0x41, 0x01, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x65, // A...attribute me
-	0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, // diump vec2 a_pos
-	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, // ition;.attribute
-	0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, //  mediump vec2 a_
-	0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // texcoord0;.varyi
-	0x6e, 0x67, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, // ng mediump vec2 
-	0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, // v_texcoord0;.uni
-	0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x6d, 0x61, 0x74, // form mediump mat
-	0x34, 0x20, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, // 4 u_modelViewPro
-	0x6a, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, // j;.void main ().
-	0x7b, 0x0a, 0x20, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, // {.  mediump vec4
-	0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, //  tmpvar_1;.  tmp
-	0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, // var_1.zw = vec2(
-	0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, // 0.0, 1.0);.  tmp
-	0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, // var_1.xy = a_pos
-	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, // ition;.  gl_Posi
-	0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, // tion = (u_modelV
-	0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // iewProj * tmpvar
-	0x5f, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, // _1);.  v_texcoor
-	0x64, 0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, // d0 = a_texcoord0
-	0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00,                                                             // ;.}...
-};
-
-static const uint8_t fs_h[207] =
-{
-	0x46, 0x53, 0x48, 0x02, 0x8c, 0xd4, 0x10, 0xbd, 0x01, 0x00, 0x08, 0x75, 0x5f, 0x61, 0x6c, 0x62, // FSH........u_alb
-	0x65, 0x64, 0x6f, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x76, 0x61, 0x72, // edo..........var
-	0x79, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, // ying mediump vec
-	0x32, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, // 2 v_texcoord0;.u
-	0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, // niform sampler2D
-	0x20, 0x75, 0x5f, 0x61, 0x6c, 0x62, 0x65, 0x64, 0x6f, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, //  u_albedo;.void 
-	0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x70, // main ().{.  lowp
-	0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, //  vec4 tmpvar_1;.
-	0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, //   tmpvar_1 = tex
-	0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x20, 0x28, 0x75, 0x5f, 0x61, 0x6c, 0x62, 0x65, 0x64, 0x6f, // ture2D (u_albedo
-	0x2c, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x29, 0x3b, 0x0a, // , v_texcoord0);.
-	0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, //   gl_FragColor =
-	0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00,       //  tmpvar_1;.}...
-};
-
-static const uint8_t vsc_h[358] =
-{
-	0x56, 0x53, 0x48, 0x02, 0x8c, 0xd4, 0x10, 0xbd, 0x01, 0x00, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, 0x64, // VSH........u_mod
-	0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x01, 0x00, 0x00, 0x01, 0x00, // elViewProj......
-	0x41, 0x01, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x65, // A...attribute me
-	0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, // diump vec2 a_pos
-	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, // ition;.attribute
-	0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, //  mediump vec2 a_
-	0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // texcoord0;.varyi
-	0x6e, 0x67, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, // ng mediump vec2 
-	0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, // v_texcoord0;.uni
-	0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x6d, 0x61, 0x74, // form mediump mat
-	0x34, 0x20, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, // 4 u_modelViewPro
-	0x6a, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, // j;.void main ().
-	0x7b, 0x0a, 0x20, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, // {.  mediump vec4
-	0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, //  tmpvar_1;.  tmp
-	0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, // var_1.zw = vec2(
-	0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, // 0.0, 1.0);.  tmp
-	0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, // var_1.xy = a_pos
-	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, // ition;.  gl_Posi
-	0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, // tion = (u_modelV
-	0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // iewProj * tmpvar
-	0x5f, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, // _1);.  v_texcoor
-	0x64, 0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, // d0 = a_texcoord0
-	0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00,                                                             // ;.}...
-};
-
-static const uint8_t fsc_h[103] =
-{
-	0x46, 0x53, 0x48, 0x02, 0x8c, 0xd4, 0x10, 0xbd, 0x01, 0x00, 0x07, 0x75, 0x5f, 0x63, 0x6f, 0x6c, // FSH........u_col
-	0x6f, 0x72, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x69, 0x66, // or......J...unif
-	0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, // orm mediump vec4
-	0x20, 0x75, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, //  u_color;.void m
-	0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, // ain ().{.  gl_Fr
-	0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x75, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, // agColor = u_colo
-	0x72, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00,                                                       // r;.}...
-};
-
-
 namespace crown
 {
 
-void Material::create(const MaterialResource* mr)
+void Material::create(const MaterialResource* mr, MaterialManager& mm)
 {
 	uint32_t size = mr->dynamic_data_size();
 	uint32_t offt = mr->dynamic_data_offset();
@@ -128,10 +48,6 @@ void Material::create(const MaterialResource* mr)
 	data = (char*) default_allocator().allocate(size);
 	memcpy(data, base, size);
 
-	bgfx::ShaderHandle vs = bgfx::createShader(bgfx::makeRef(vs_h, sizeof(vs_h)));
-	bgfx::ShaderHandle fs = bgfx::createShader(bgfx::makeRef(fs_h, sizeof(fs_h)));
-	program = bgfx::createProgram(vs, fs, true);
-
 	for (uint32_t i = 0; i < mr->num_textures(); i++)
 	{
 		TextureData* ud = mr->get_texture_data(i);
@@ -142,9 +58,8 @@ void Material::create(const MaterialResource* mr)
 		ResourceId texid;
 		texid.type = TEXTURE_TYPE;
 		texid.name = ud->id;
-		TextureResource* tex = (TextureResource*) device()->resource_manager()->get(texid);
-
-		th->texture_handle = bgfx::createTexture(bgfx::copy(tex->data(), tex->size())).idx;
+		TextureImage* teximg = (TextureImage*) device()->resource_manager()->get(texid);
+		th->texture_handle = teximg->handle.idx;
 	}
 
 	for (uint32_t i = 0; i < mr->num_uniforms(); i++)
@@ -158,10 +73,20 @@ void Material::create(const MaterialResource* mr)
 	resource = mr;
 }
 
-void Material::destroy() const
+void Material::clone(const Material& m)
 {
-	bgfx::destroyProgram(program);
+	const MaterialResource* mr = m.resource;
+	uint32_t size = mr->dynamic_data_size();
+	char* base = m.data;
 
+	data = (char*) default_allocator().allocate(size);
+	memcpy(data, base, size);
+
+	resource = mr;
+}
+
+void Material::destroy() const
+{
 	for (uint32_t i = 0; i < resource->num_textures(); i++)
 	{
 		TextureHandle* th = resource->get_texture_handle(i, data);
@@ -169,10 +94,6 @@ void Material::destroy() const
 		bgfx::UniformHandle sh;
 		sh.idx = th->sampler_handle;
 		bgfx::destroyUniform(sh);
-
-		bgfx::TextureHandle bgfx_th;
-		bgfx_th.idx = th->texture_handle;
-		bgfx::destroyTexture(bgfx_th);
 	}
 
 	for (uint32_t i = 0; i < resource->num_uniforms(); i++)
@@ -189,7 +110,12 @@ void Material::destroy() const
 
 void Material::bind() const
 {
-	bgfx::setProgram(program);
+	// bgfx::setProgram(program);
+	ResourceId shader_id;
+	shader_id.type = SHADER_TYPE;
+	shader_id.name = resource->shader();
+	Shader* shader = (Shader*) device()->resource_manager()->get(shader_id);
+	bgfx::setProgram(shader->program);
 
 	// Set samplers
 	for (uint32_t i = 0; i < resource->num_textures(); i++)
@@ -215,4 +141,23 @@ void Material::bind() const
 	}
 }
 
+void Material::set_float(const char* name, float val)
+{
+	char* p = (char*) resource->get_uniform_handle_by_string(name, data);
+	*((float*)(p + sizeof(uint32_t))) = val;
+
+}
+
+void Material::set_vector2(const char* name, const Vector2& val)
+{
+	char* p = (char*) resource->get_uniform_handle_by_string(name, data);
+	*((Vector2*)(p + sizeof(uint32_t))) = val;
+}
+
+void Material::set_vector3(const char* name, const Vector3& val)
+{
+	char* p = (char*) resource->get_uniform_handle_by_string(name, data);
+	*((Vector3*)(p + sizeof(uint32_t))) = val;
+}
+
 } // namespace crown

+ 8 - 3
engine/renderers/material.h

@@ -26,23 +26,28 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
+#include "math_types.h"
 #include <bgfx.h>
 
 namespace crown
 {
 
+struct MaterialManager;
 struct MaterialResource;
 
 struct Material
 {
-	void create(const MaterialResource* mr);
+	void create(const MaterialResource* mr, MaterialManager& mm);
+	void clone(const Material& m);
 	void destroy() const;
 	void bind() const;
 
+	void set_float(const char* name, float val);
+	void set_vector2(const char* name, const Vector2& val);
+	void set_vector3(const char* name, const Vector3& val);
+
 	const MaterialResource* resource;
 	char* data;
-
-	bgfx::ProgramHandle program;
 };
 
 } // namespace crown

+ 37 - 10
engine/renderers/material_manager.cpp

@@ -62,25 +62,52 @@ void MaterialManager::load(StringId64 id, ResourceManager& rm)
 	res_id.type = MATERIAL_TYPE;
 	res_id.name = id;
 
-	Material mat;
-	mat.create((MaterialResource*) rm.get(res_id));
+	MaterialId mat_id = id_table::create(_materials_ids);
+	_materials[mat_id.index].create((MaterialResource*) rm.get(res_id), *this);
 
-	sort_map::set(m_materials, id, mat);
+	sort_map::set(m_materials, id, mat_id);
 	sort_map::sort(m_materials);
 }
 
 void MaterialManager::unload(StringId64 id, ResourceManager& /*rm*/)
 {
-	Material deff;
-	deff.program.idx = BGFX_INVALID_HANDLE;
-	sort_map::get(m_materials, id, deff).destroy();
+	MaterialId deff_id;
+	deff_id.id = INVALID_ID;
+	deff_id.index = 0;
+
+	MaterialId mat_id = sort_map::get(m_materials, id, deff_id);
+	CE_ASSERT(mat_id.id != INVALID_ID, "Material not loaded");
+
+	_materials[mat_id.index].destroy();
+	id_table::destroy(_materials_ids, mat_id);
+
+	sort_map::remove(m_materials, id);
+	sort_map::sort(m_materials);
+}
+
+MaterialId MaterialManager::create_material(StringId64 id)
+{
+	MaterialId deff_id;
+	deff_id.id = INVALID_ID;
+	deff_id.index = 0;
+
+	MaterialId idd = sort_map::get(m_materials, id, deff_id);
+	CE_ASSERT(idd.id != INVALID_ID, "Material not loaded");
+
+	MaterialId new_id = id_table::create(_materials_ids);
+	_materials[new_id.index].clone(_materials[idd.index]);
+
+	return new_id;
+}
+
+void MaterialManager::destroy_material(MaterialId id)
+{
+	id_table::destroy(_materials_ids, id);
 }
 
-const Material& MaterialManager::get(StringId64 id)
+Material* MaterialManager::lookup_material(MaterialId id)
 {
-	Material deff;
-	deff.program.idx = BGFX_INVALID_HANDLE;
-	return sort_map::get(m_materials, id, deff);
+	return &_materials[id.index];
 }
 
 } // namespace crown

+ 9 - 2
engine/renderers/material_manager.h

@@ -30,11 +30,13 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "container_types.h"
 #include "material.h"
 #include "resource_manager.h"
+#include "id_table.h"
 #include <bgfx.h>
 
 namespace crown
 {
 
+typedef Id MaterialId;
 struct MaterialResource;
 
 struct MaterialManager
@@ -43,11 +45,16 @@ struct MaterialManager
 
 	void load(StringId64 id, ResourceManager& rm);
 	void unload(StringId64 id, ResourceManager& rm);
-	const Material& get(StringId64 id);
+
+	MaterialId create_material(StringId64 id);
+	void destroy_material(MaterialId id);
+	Material* lookup_material(MaterialId id);
 
 private:
 
-	SortMap<StringId64, Material> m_materials;
+	SortMap<StringId64, MaterialId> m_materials;
+	IdTable<512> _materials_ids;
+	Material _materials[512];
 };
 
 namespace material_manager

+ 2 - 8
engine/renderers/render_world.cpp

@@ -111,9 +111,9 @@ Sprite*	RenderWorld::get_sprite(SpriteId id)
 }
 
 //-----------------------------------------------------------------------------
-GuiId RenderWorld::create_gui(uint16_t width, uint16_t height)
+GuiId RenderWorld::create_gui(uint16_t width, uint16_t height, const char* material)
 {
-	Gui* gui = CE_NEW(m_gui_pool, Gui)(*this, width, height);
+	Gui* gui = CE_NEW(m_gui_pool, Gui)(width, height, material);
 	GuiId id = id_array::create(m_guis, gui);
 	gui->set_id(id);
 	return id;
@@ -163,12 +163,6 @@ void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uin
 	bgfx::dbgTextClear();
 	bgfx::dbgTextPrintf(0, 2, 0x6f, "dt = %4.7f", dt);
 
-	// Update all sprites
-	for (uint32_t s = 0; s < id_array::size(m_sprite); s++)
-	{
-		m_sprite[s]->update(dt);
-	}	
-
 	// Draw all sprites
 	for (uint32_t s = 0; s < id_array::size(m_sprite); s++)
 	{

+ 1 - 1
engine/renderers/render_world.h

@@ -94,7 +94,7 @@ public:
 	/// Creates the sprite @a id.
 	Sprite* get_sprite(SpriteId id);
 
-	GuiId create_gui(uint16_t width, uint16_t height);
+	GuiId create_gui(uint16_t width, uint16_t height, const char* material);
 	void destroy_gui(GuiId id);
 	Gui* get_gui(GuiId id);
 

+ 5 - 70
engine/renderers/sprite.cpp

@@ -45,27 +45,7 @@ Sprite::Sprite(RenderWorld& render_world, SceneGraph& sg, int32_t node, const Sp
 	, m_scene_graph(sg)
 	, m_node(node)
 	, m_resource(sr)
-	, m_material(0)
 	, m_frame(0)
-	, m_animation(NULL)
-	, m_time(0)
-	, m_loop(false)
-{
-	Blob vmem = sr->get_vertices();
-	Blob imem = sr->get_indices();
-
-	bgfx::VertexDecl decl;
-	decl.begin()
-		.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
-		.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, true)
-		.end();
-
-	m_vb = bgfx::createVertexBuffer(bgfx::makeRef((void*) vmem.m_data, vmem.m_size), decl);
-	m_ib = bgfx::createIndexBuffer(bgfx::makeRef((void*) imem.m_data, imem.m_size));
-}
-
-//-----------------------------------------------------------------------------
-Sprite::~Sprite()
 {
 }
 
@@ -123,7 +103,7 @@ void Sprite::set_local_pose(Unit* unit, const Matrix4x4& pose)
 	unit->set_local_pose(m_node, pose);
 }
 
-void Sprite::set_material(StringId64 id)
+void Sprite::set_material(MaterialId id)
 {
 	m_material = id;
 }
@@ -134,60 +114,15 @@ void Sprite::set_frame(uint32_t i)
 	m_frame = i;
 }
 
-//-----------------------------------------------------------------------------
-void Sprite::play_animation(const char* name, bool loop)
-{
-	if (m_animation)
-		return;
-
-	m_animation = m_resource->get_animation(name);
-	m_time = 0;
-	m_loop = loop;
-	m_frame = m_resource->get_animation_frame(m_animation, m_animation->start_frame);
-}
-
-//-----------------------------------------------------------------------------
-void Sprite::stop_animation()
-{
-	m_animation = NULL;
-	m_time = 0;
-	m_frame = 0;
-}
-
-//-----------------------------------------------------------------------------
-void Sprite::update(float dt)
-{
-	if (!m_animation)
-		return;
-
-	m_time += dt;
-
-	if (m_time >= m_animation->time)
-	{
-		if (m_loop)
-		{
-			m_time = 0;
-		}
-		else
-		{
-			stop_animation();
-			return;
-		}
-	}
-
-	uint32_t frame = (uint32_t) m_animation->num_frames * (m_time / m_animation->time);
-	m_frame = m_resource->get_animation_frame(m_animation, frame);
-}
-
 //-----------------------------------------------------------------------------
 void Sprite::render()
 {
-	if (m_material)
-		material_manager::get()->get(m_material).bind();
+	if (m_material.id != INVALID_ID)
+		material_manager::get()->lookup_material(m_material)->bind();
 
 	bgfx::setState(BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA);
-	bgfx::setVertexBuffer(m_vb);
-	bgfx::setIndexBuffer(m_ib, m_frame * 6, 6);
+	bgfx::setVertexBuffer(m_resource->vb);
+	bgfx::setIndexBuffer(m_resource->ib, m_frame * 6, 6);
 	bgfx::setTransform(matrix4x4::to_float_ptr(world_pose()));
 	bgfx::submit(0);
 }

+ 5 - 16
engine/renderers/sprite.h

@@ -31,6 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "matrix4x4.h"
 #include "quaternion.h"
 #include "sprite_resource.h"
+#include "material.h"
 #include <bgfx.h>
 
 namespace crown
@@ -40,12 +41,12 @@ class Renderer;
 class RenderWorld;
 struct SceneGraph;
 struct Unit;
+typedef Id MaterialId;
 
 //-----------------------------------------------------------------------------
 struct Sprite
 {
 	Sprite(RenderWorld& render_world, SceneGraph& sg, int32_t node, const SpriteResource* sr);
-	~Sprite();
 
 	Vector3 local_position() const;
 	Quaternion local_rotation() const;
@@ -59,15 +60,11 @@ struct Sprite
 	void set_local_rotation(Unit* unit, const Quaternion& rot);
 	void set_local_pose(Unit* unit, const Matrix4x4& pose);
 
-	void set_material(StringId64 id);
+	void set_material(MaterialId id);
 
-	void render();
 	void set_frame(uint32_t i);
 
-	void play_animation(const char* name, bool loop);
-	void stop_animation();
-
-	void update(float dt);
+	void render();
 
 public:
 
@@ -75,16 +72,8 @@ public:
 	SceneGraph& m_scene_graph;
 	int32_t m_node;
 	const SpriteResource* m_resource;
-	StringId64 m_material;
-
-	bgfx::VertexBufferHandle m_vb;
-	bgfx::IndexBufferHandle m_ib;
-
+	MaterialId m_material;
 	uint32_t m_frame;
-
-	const SpriteAnimation* m_animation;
-	float m_time;
-	bool m_loop;
 };
 
 } // namespace crown

+ 4 - 8
engine/resource/material_resource.cpp

@@ -93,9 +93,8 @@ struct UniformTypeInfo
 
 static const UniformTypeInfo s_uniform_type_info[UniformType::COUNT] =
 {
-	{ "integer", UniformType::INTEGER,  4 },
 	{ "float",   UniformType::FLOAT,    4 },
-	{ "vector2", UniformType::VECTOR3,  8 },
+	{ "vector2", UniformType::VECTOR2,  8 },
 	{ "vector3", UniformType::VECTOR3, 12 },
 	{ "vector4", UniformType::VECTOR4, 16 }
 };
@@ -109,6 +108,7 @@ static UniformType::Enum string_to_uniform_type(const char* str)
 	}
 
 	CE_FATAL("Unknown uniform type");
+	return UniformType::COUNT;
 }
 
 static void parse_uniforms(JSONElement root, Array<UniformData>& uniforms, Array<char>& dynamic)
@@ -134,12 +134,6 @@ static void parse_uniforms(JSONElement root, Array<UniformData>& uniforms, Array
 
 		switch (ud.type)
 		{
-			case UniformType::INTEGER:
-			{
-				int32_t data = root.key("uniforms").key(keys[i].c_str()).key("value").to_int();
-				reserve_dynamic_data(data, dynamic);
-				break;
-			}
 			case UniformType::FLOAT:
 			{
 				float data = root.key("uniforms").key(keys[i].c_str()).key("value").to_int();
@@ -184,11 +178,13 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	Array<UniformData> unidata(default_allocator());
 	Array<char> dynblob(default_allocator());
 
+	ResourceId shader = root.key("shader").to_resource_id("shader");
 	parse_textures(root, texdata, dynblob);
 	parse_uniforms(root, unidata, dynblob);
 
 	MaterialHeader mh;
 	mh.version = MATERIAL_VERSION;
+	mh.shader = shader.name;
 	mh.num_textures = array::size(texdata);
 	mh.texture_data_offset = sizeof(mh);
 	mh.num_uniforms = array::size(unidata);

+ 31 - 2
engine/resource/material_resource.h

@@ -43,10 +43,10 @@ namespace crown
 
 const uint32_t MATERIAL_VERSION = 1;
 
-
 struct MaterialHeader
 {
 	uint32_t version;
+	StringId64 shader;
 	uint32_t num_textures;
 	uint32_t texture_data_offset;
 	uint32_t num_uniforms;
@@ -72,7 +72,6 @@ struct UniformType
 {
 	enum Enum
 	{
-		INTEGER,
 		FLOAT,
 		VECTOR2,
 		VECTOR3,
@@ -142,6 +141,12 @@ public:
 		return mh->dynamic_data_offset;
 	}
 
+	StringId64 shader() const
+	{
+		MaterialHeader* mh = (MaterialHeader*) this;
+		return mh->shader;		
+	}
+
 	uint32_t num_textures() const
 	{
 		MaterialHeader* mh = (MaterialHeader*) this;
@@ -161,6 +166,24 @@ public:
 		return &base[i];
 	}
 
+	UniformData* get_uniform_data_by_string(const char* str) const
+	{
+		MaterialHeader* mh = (MaterialHeader*) this;
+		UniformData* base = (UniformData*) ((char*) mh + mh->uniform_data_offset);
+
+		uint32_t num = num_uniforms();
+		for (uint32_t i = 0; i < num; i++)
+		{
+			if (string::strncmp(base->name, str, 256) == 0)
+				return base;
+
+			base++;
+		}
+
+		CE_FATAL("Oops, bad uniform name");
+		return NULL;
+	}
+
 	TextureData* get_texture_data(uint32_t i) const
 	{
 		MaterialHeader* mh = (MaterialHeader*) this;
@@ -174,6 +197,12 @@ public:
 		return (UniformHandle*) (dynamic + ud->data_offset);
 	}
 
+	UniformHandle* get_uniform_handle_by_string(const char* str, char* dynamic) const
+	{
+		UniformData* ud = get_uniform_data_by_string(str);
+		return (UniformHandle*) (dynamic + ud->data_offset);
+	}	
+
 	TextureHandle* get_texture_handle(uint32_t i, char* dynamic) const
 	{
 		TextureData* td = get_texture_data(i);

+ 16 - 0
engine/resource/package_resource.cpp

@@ -57,6 +57,8 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	const uint32_t num_fonts     = root.key("font").size();
 	const uint32_t num_levels    = root.key("level").size();
 	const uint32_t num_phyconfs  = root.key("physics_config").size();
+	const uint32_t num_shaders   = root.key("shader").size();
+	const uint32_t num_sprite_animations = root.key("sprite_animation").size();
 
 	// Write header
 	bw.write(num_textures);
@@ -103,6 +105,14 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	offt += sizeof(ResourceId) * num_levels;
 	bw.write(offt);
 
+	bw.write(num_shaders);
+	offt += sizeof(ResourceId) * num_phyconfs;
+	bw.write(offt);
+
+	bw.write(num_sprite_animations);
+	offt += sizeof(ResourceId) * num_shaders;
+	bw.write(offt);
+
 	// Write resource ids
 	for (uint32_t i = 0; i < num_textures; i++)
 		bw.write(root.key("texture")[i].to_resource_id("texture"));
@@ -136,6 +146,12 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 	for (uint32_t i = 0; i < num_phyconfs; i++)
 		bw.write(root.key("physics_config")[i].to_resource_id("physics_config"));
+
+	for (uint32_t i = 0; i < num_shaders; i++)
+		bw.write(root.key("shader")[i].to_resource_id("shader"));
+
+	for (uint32_t i = 0; i < num_sprite_animations; i++)
+		bw.write(root.key("sprite_animation")[i].to_resource_id("sprite_animation"));
 }
 
 } // namespace package_resource

+ 34 - 0
engine/resource/package_resource.h

@@ -60,6 +60,10 @@ struct PackageHeader
 	uint32_t levels_offset;
 	uint32_t num_physics_configs;
 	uint32_t physics_configs_offset;
+	uint32_t num_shaders;
+	uint32_t shaders_offset;
+	uint32_t num_sprite_animations;
+	uint32_t sprite_animations_offset;
 };
 
 struct PackageResource
@@ -159,6 +163,18 @@ struct PackageResource
 		return ((PackageHeader*) this)->num_physics_configs;
 	}
 
+	//-----------------------------------------------------------------------------
+	uint32_t num_shaders() const
+	{
+		return ((PackageHeader*) this)->num_shaders;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_sprite_animations() const
+	{
+		return ((PackageHeader*) this)->num_sprite_animations;
+	}
+
 	//-----------------------------------------------------------------------------
 	ResourceId get_texture_id(uint32_t i) const
 	{
@@ -258,6 +274,24 @@ struct PackageResource
 		return begin[i];
 	}
 
+	//-----------------------------------------------------------------------------
+	ResourceId get_shader_id(uint32_t i) const
+	{
+		CE_ASSERT(i < num_shaders(), "Index out of bounds");
+
+		ResourceId* begin = (ResourceId*) ((char*) this + ((PackageHeader*) this)->shaders_offset);
+		return begin[i];
+	}
+
+	//-----------------------------------------------------------------------------
+	ResourceId get_sprite_animation_id(uint32_t i) const
+	{
+		CE_ASSERT(i < num_sprite_animations(), "Index out of bounds");
+
+		ResourceId* begin = (ResourceId*) ((char*) this + ((PackageHeader*) this)->sprite_animations_offset);
+		return begin[i];
+	}
+
 private:
 
 	// Disable construction

+ 4 - 2
engine/resource/resource.h

@@ -43,11 +43,12 @@ namespace crown
 #define PACKAGE_EXTENSION			"package"
 #define PHYSICS_CONFIG_EXTENSION	"physics_config"
 #define PHYSICS_EXTENSION			"physics"
+#define SHADER_EXTENSION			"shader"
 #define SOUND_EXTENSION				"sound"
+#define SPRITE_ANIMATION_EXTENSION	"sprite_animation"
 #define SPRITE_EXTENSION			"sprite"
 #define TEXTURE_EXTENSION			"texture"
 #define UNIT_EXTENSION				"unit"
-#define SHADER_EXTENSION			"shader"
 
 #define CONFIG_TYPE					uint64_t(0x82645835e6b73232)
 #define FONT_TYPE					uint64_t(0x9efe0a916aae7880)
@@ -58,11 +59,12 @@ namespace crown
 #define PACKAGE_TYPE				uint64_t(0xad9c6d9ed1e5e77a)
 #define PHYSICS_CONFIG_TYPE			uint64_t(0x72e3cc03787a11a1)
 #define PHYSICS_TYPE				uint64_t(0x5f7203c8f280dab8)
+#define SHADER_TYPE					uint64_t(0xcce8d5b5f5ae333f)
 #define SOUND_TYPE					uint64_t(0x90641b51c98b7aac)
+#define SPRITE_ANIMATION_TYPE		uint64_t(0x487e78e3f87f238d)
 #define SPRITE_TYPE					uint64_t(0x8d5871f9ebdb651c)
 #define TEXTURE_TYPE				uint64_t(0xcd4238c6a0c69e32)
 #define UNIT_TYPE					uint64_t(0xe0a48d0be9a7453f)
-#define SHADER_TYPE					uint64_t(0xcce8d5b5f5ae333f)
 
 struct ResourceId
 {

+ 20 - 0
engine/resource/resource_package.h

@@ -117,11 +117,31 @@ public:
 		{
 			m_resource_manager->load(m_package->get_physics_config_id(i));
 		}
+
+		for (uint32_t i = 0; i < m_package->num_shaders(); i++)
+		{
+			m_resource_manager->load(m_package->get_shader_id(i));
+		}
+
+		for (uint32_t i = 0; i < m_package->num_sprite_animations(); i++)
+		{
+			m_resource_manager->load(m_package->get_sprite_animation_id(i));
+		}
 	}
 
 	/// Unloads all the resources in the package.
 	void unload()
 	{
+		for (uint32_t i = 0; i < m_package->num_sprite_animations(); i++)
+		{
+			m_resource_manager->unload(m_package->get_sprite_animation_id(i));
+		}
+
+		for (uint32_t i = 0; i < m_package->num_shaders(); i++)
+		{
+			m_resource_manager->unload(m_package->get_shader_id(i));
+		}
+
 		for (uint32_t i = 0; i < m_package->num_physics_configs(); i++)
 		{
 			m_resource_manager->unload(m_package->get_physics_config_id(i));

+ 4 - 1
engine/resource/resource_registry.cpp

@@ -36,6 +36,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "material_resource.h"
 #include "font_resource.h"
 #include "level_resource.h"
+#include "shader.h"
 
 namespace crown
 {
@@ -47,13 +48,15 @@ static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 	{ MESH_TYPE, MeshResource::load, MeshResource::unload, MeshResource::online, MeshResource::offline },
 	{ SOUND_TYPE, SoundResource::load, SoundResource::unload, SoundResource::online, SoundResource::offline },
 	{ UNIT_TYPE, UnitResource::load, UnitResource::unload, UnitResource::online, UnitResource::offline },
-	{ SPRITE_TYPE, SpriteResource::load, SpriteResource::unload, SpriteResource::online, SpriteResource::offline},
+	{ SPRITE_TYPE, sprite_resource::load, sprite_resource::unload, sprite_resource::online, sprite_resource::offline},
 	{ PACKAGE_TYPE, PackageResource::load, PackageResource::unload, PackageResource::online, PackageResource::offline },
 	{ PHYSICS_TYPE, PhysicsResource::load, PhysicsResource::unload, PhysicsResource::online, PhysicsResource::offline },
 	{ MATERIAL_TYPE, MaterialResource::load, MaterialResource::unload, MaterialResource::online, MaterialResource::offline },
 	{ PHYSICS_CONFIG_TYPE, PhysicsConfigResource::load, PhysicsConfigResource::unload, PhysicsConfigResource::online, PhysicsConfigResource::offline },
 	{ FONT_TYPE, FontResource::load, FontResource::unload, FontResource::online, FontResource::offline },
 	{ LEVEL_TYPE, LevelResource::load, LevelResource::unload, LevelResource::online, LevelResource::offline },
+	{ SHADER_TYPE, shader_resource::load, shader_resource::unload, shader_resource::online, shader_resource::offline },
+	{ SPRITE_ANIMATION_TYPE, sprite_animation_resource::load, sprite_animation_resource::unload, sprite_animation_resource::online, sprite_animation_resource::offline },
 	{ 0, NULL, NULL, NULL, NULL }
 };
 

+ 219 - 106
engine/resource/sprite_resource.cpp

@@ -41,142 +41,255 @@ namespace crown
 {
 namespace sprite_resource
 {
+	struct SpriteFrame
+	{
+		StringId32 name;
+		Vector4 region;		// [x0, y0, x1, y1]
+		Vector2 scale;		// [Sx, Sy]
+		Vector2 offset;		// [Ox, Oy]
+	};
 
-struct SpriteFrame
-{
-	StringId32 name;
-	Vector4 region;		// [x0, y0, x1, y1]
-	Vector2 scale;		// [Sx, Sy]
-	Vector2 offset;		// [Ox, Oy]
-};
-
-//-----------------------------------------------------------------------------
-void parse_frame(JSONElement e, SpriteFrame& frame)
-{
-	frame.name   = e.key("name"  ).to_string_id();
-	frame.region = e.key("region").to_vector4();
-	frame.offset = e.key("offset").to_vector2();
-	frame.scale  = e.key("scale" ).to_vector2();
-}
-
-//-----------------------------------------------------------------------------
-void parse_animation(JSONElement e, SpriteAnimation& anim)
-{
-	anim.name = e.key("name").to_string_id();
-	anim.time = e.key("time").to_float();
-	anim.num_frames = 0;
-	anim.start_frame = 0;
-}
-
-//-----------------------------------------------------------------------------
-void compile(Filesystem& fs, const char* resource_path, File* out_file)
-{
-	File* file = fs.open(resource_path, FOM_READ);
-	JSONParser json(*file);
-	fs.close(file);
+	void parse_frame(JSONElement e, SpriteFrame& frame)
+	{
+		frame.name   = e.key("name"  ).to_string_id();
+		frame.region = e.key("region").to_vector4();
+		frame.offset = e.key("offset").to_vector2();
+		frame.scale  = e.key("scale" ).to_vector2();
+	}
 
-	JSONElement root = json.root();
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
 
-	// Read width/height
-	const float width  = root.key("width" ).to_float();
-	const float height = root.key("height").to_float();
-	const uint32_t num_frames = root.key("frames").size();
-	const uint32_t num_animations = root.key("animations").size();
+		JSONElement root = json.root();
 
-	BinaryWriter bw(*out_file);
+		// Read width/height
+		const float width  = root.key("width" ).to_float();
+		const float height = root.key("height").to_float();
+		const uint32_t num_frames = root.key("frames").size();
 
-	Array<float> vertices(default_allocator());
-	Array<uint16_t> indices(default_allocator());
-	uint32_t num_idx = 0;
-	for (uint32_t i = 0; i < num_frames; i++)
-	{
-		JSONElement e(root.key("frames")[i]);
 
-		SpriteFrame frame;
-		parse_frame(e, frame);
+		BinaryWriter bw(*out_file);
 
-		const SpriteFrame& fd = frame;
+		Array<float> vertices(default_allocator());
+		Array<uint16_t> indices(default_allocator());
+		uint32_t num_idx = 0;
+		for (uint32_t i = 0; i < num_frames; i++)
+		{
+			JSONElement e(root.key("frames")[i]);
 
-		// Compute uv coords
-		const float u0 = fd.region.x / width;
-		const float v0 = fd.region.y / height;
-		const float u1 = (fd.region.x + fd.region.z) / width;
-		const float v1 = (fd.region.y + fd.region.w) / height;
+			SpriteFrame frame;
+			parse_frame(e, frame);
 
-		// Compute positions
-		const float w = fd.region.z / CE_PIXELS_PER_METER;
-		const float h = fd.region.w / CE_PIXELS_PER_METER;
+			const SpriteFrame& fd = frame;
 
-		const float x0 = fd.scale.x * (-w * 0.5f) + fd.offset.x;
-		const float y0 = fd.scale.y * (-h * 0.5f) + fd.offset.y;
-		const float x1 = fd.scale.x * ( w * 0.5f) + fd.offset.x;
-		const float y1 = fd.scale.y * ( h * 0.5f) + fd.offset.y;
+			// Compute uv coords
+			const float u0 = fd.region.x / width;
+			const float v0 = fd.region.y / height;
+			const float u1 = (fd.region.x + fd.region.z) / width;
+			const float v1 = (fd.region.y + fd.region.w) / height;
 
-		array::push_back(vertices, x0); array::push_back(vertices, y0); // position
-		array::push_back(vertices, u0); array::push_back(vertices, v0); // uv
+			// Compute positions
+			const float w = fd.region.z / CE_PIXELS_PER_METER;
+			const float h = fd.region.w / CE_PIXELS_PER_METER;
 
-		array::push_back(vertices, x1); array::push_back(vertices, y0); // position
-		array::push_back(vertices, u1); array::push_back(vertices, v0); // uv
+			const float x0 = fd.scale.x * (-w * 0.5f) + fd.offset.x;
+			const float y0 = fd.scale.y * (-h * 0.5f) + fd.offset.y;
+			const float x1 = fd.scale.x * ( w * 0.5f) + fd.offset.x;
+			const float y1 = fd.scale.y * ( h * 0.5f) + fd.offset.y;
 
-		array::push_back(vertices, x1); array::push_back(vertices, y1); // position
-		array::push_back(vertices, u1); array::push_back(vertices, v1); // uv
+			array::push_back(vertices, x0); array::push_back(vertices, y0); // position
+			array::push_back(vertices, u0); array::push_back(vertices, v0); // uv
 
-		array::push_back(vertices, x0); array::push_back(vertices, y1); // position
-		array::push_back(vertices, u0); array::push_back(vertices, v1); // uv
+			array::push_back(vertices, x1); array::push_back(vertices, y0); // position
+			array::push_back(vertices, u1); array::push_back(vertices, v0); // uv
 
-		array::push_back(indices, uint16_t(num_idx)); array::push_back(indices, uint16_t(num_idx + 1)); array::push_back(indices, uint16_t(num_idx + 2));
-		array::push_back(indices, uint16_t(num_idx)); array::push_back(indices, uint16_t(num_idx + 2)); array::push_back(indices, uint16_t(num_idx + 3));
-		num_idx += 4;
-	}
+			array::push_back(vertices, x1); array::push_back(vertices, y1); // position
+			array::push_back(vertices, u1); array::push_back(vertices, v1); // uv
 
-	const uint32_t num_vertices = array::size(vertices) / 4; // 4 components per vertex
-	const uint32_t num_indices = array::size(indices);
+			array::push_back(vertices, x0); array::push_back(vertices, y1); // position
+			array::push_back(vertices, u0); array::push_back(vertices, v1); // uv
 
-	// Write animations
-	Array<SpriteAnimation> animations(default_allocator());
-	Array<uint32_t> frames(default_allocator());
+			array::push_back(indices, uint16_t(num_idx)); array::push_back(indices, uint16_t(num_idx + 1)); array::push_back(indices, uint16_t(num_idx + 2));
+			array::push_back(indices, uint16_t(num_idx)); array::push_back(indices, uint16_t(num_idx + 2)); array::push_back(indices, uint16_t(num_idx + 3));
+			num_idx += 4;
+		}
+
+		const uint32_t num_vertices = array::size(vertices) / 4; // 4 components per vertex
+		const uint32_t num_indices = array::size(indices);
+
+		// Write header
+		bw.write(SPRITE_VERSION);
+		bw.write(num_vertices);
+		if (array::size(vertices))
+			bw.write(array::begin(vertices), sizeof(float) * array::size(vertices));
+		bw.write(num_indices);
+		if (array::size(indices))
+			bw.write(array::begin(indices), sizeof(uint16_t) * array::size(indices));
+	}
 
-	for (uint32_t i = 0; i < num_animations; i++)
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
-		JSONElement e(root.key("animations")[i]);
+		File* file = bundle.open(id);
+		BinaryReader br(*file);
 
-		SpriteAnimation anim;
-		parse_animation(e, anim);
+		uint32_t version;
+		br.read(version);
 
-		// Read frames
-		const uint32_t num_frames = e.key("frames").size();
+		uint32_t num_verts;
+		br.read(num_verts);
+		const bgfx::Memory* vbmem = bgfx::alloc(num_verts * sizeof(float) * 4);
+		br.read(vbmem->data, num_verts * sizeof(float) * 4);
 
-		anim.num_frames = num_frames;
-		anim.start_frame = array::size(frames); // Relative offset
+		uint32_t num_inds;
+		br.read(num_inds);
+		const bgfx::Memory* ibmem = bgfx::alloc(num_inds * sizeof(uint16_t));
+		br.read(ibmem->data, num_inds * sizeof(uint16_t));
 
-		for (uint32_t ff = 0; ff < num_frames; ff++)
-			array::push_back(frames, (uint32_t) e.key("frames")[ff].to_int());
+		bundle.close(file);
 
-		array::push_back(animations, anim);
+		SpriteResource* so = (SpriteResource*) default_allocator().allocate(sizeof(SpriteResource));
+		so->vbmem = vbmem;
+		so->ibmem = ibmem;
+
+		return so;
 	}
 
-	// Write header
-	bw.write(uint32_t(0)); // vb
-	bw.write(uint32_t(0)); // ib
-	bw.write(num_animations); uint32_t offt = sizeof(SpriteHeader);
-	bw.write(offt);
-	bw.write(num_vertices); offt += sizeof(SpriteAnimation) * array::size(animations) + sizeof(uint32_t) * array::size(frames);
-	bw.write(offt);
-	bw.write(num_indices); offt += sizeof(float) * array::size(vertices);
-	bw.write(offt);
+	void online(StringId64 id, ResourceManager& rm)
+	{
+		ResourceId res_id;
+		res_id.type = SPRITE_TYPE;
+		res_id.name = id;
+
+		SpriteResource* so = (SpriteResource*) rm.get(res_id);
 
-	if (array::size(animations))
-		bw.write(array::begin(animations), sizeof(SpriteAnimation) * array::size(animations));
+		bgfx::VertexDecl decl;
+		decl.begin()
+			.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
+			.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, false)
+			.end();
 
-	if (array::size(frames))
-		bw.write(array::begin(frames), sizeof(uint32_t) * array::size(frames));
+		so->vb = bgfx::createVertexBuffer(so->vbmem, decl);
+		so->ib = bgfx::createIndexBuffer(so->ibmem);
+	}
+
+	void offline(StringId64 id, ResourceManager& rm)
+	{
+		ResourceId res_id;
+		res_id.type = SPRITE_TYPE;
+		res_id.name = id;
 
-	if (array::size(vertices))
-		bw.write(array::begin(vertices), sizeof(float) * array::size(vertices));
+		SpriteResource* so = (SpriteResource*) rm.get(res_id);
 
-	if (array::size(indices))
-		bw.write(array::begin(indices), sizeof(uint16_t) * array::size(indices));
-}
+		bgfx::destroyVertexBuffer(so->vb);
+		bgfx::destroyIndexBuffer(so->ib);
+	}
 
+	void unload(Allocator& a, void* resource)
+	{
+		a.deallocate(resource);
+	}
 } // namespace sprite_resource
+
+namespace sprite_animation_resource
+{
+	void parse_animations(JSONElement e, Array<SpriteAnimationName>& names, Array<SpriteAnimationData>& anim_data, Array<uint32_t>& frames)
+	{
+		const uint32_t num = e.key("animations").size();
+		for (uint32_t i = 0; i < num; i++)
+		{
+			JSONElement anim(e.key("animations")[i]);
+
+			SpriteAnimationName san;
+			san.id = anim.key("name").to_string_id();
+
+			const uint32_t num_frames = anim.key("frames").size();
+			SpriteAnimationData sad;
+			sad.num_frames = num_frames;
+			sad.first_frame = array::size(frames);
+			sad.time = anim.key("time").to_float();
+
+			// Read frames
+			for (uint32_t ff = 0; ff < num_frames; ff++)
+				array::push_back(frames, (uint32_t) anim.key("frames")[ff].to_int());
+
+			array::push_back(names, san);
+			array::push_back(anim_data, sad);
+		}
+	}
+
+	void compile(Filesystem& fs, const char* resource_path, File* out_file)
+	{
+		File* file = fs.open(resource_path, FOM_READ);
+		JSONParser json(*file);
+		fs.close(file);
+
+		Array<SpriteAnimationName> anim_names(default_allocator());
+		Array<SpriteAnimationData> anim_data(default_allocator());
+		Array<uint32_t> anim_frames(default_allocator());
+
+		parse_animations(json.root(), anim_names, anim_data, anim_frames);
+
+		BinaryWriter bw(*out_file);
+		bw.write(uint32_t(1)); // version
+		bw.write(uint32_t(array::size(anim_names)));
+		bw.write(uint32_t(array::size(anim_frames)));
+		bw.write(uint32_t(
+			sizeof(SpriteAnimationResource) +
+			sizeof(SpriteAnimationName) * array::size(anim_names) +
+			sizeof(SpriteAnimationData) * array::size(anim_data)));
+
+		if (array::size(anim_names));
+			bw.write(array::begin(anim_names), sizeof(SpriteAnimationName) * array::size(anim_names));
+		if (array::size(anim_data))
+			bw.write(array::begin(anim_data), sizeof(SpriteAnimationData) * array::size(anim_data));
+		if (array::size(anim_frames))
+			bw.write(array::begin(anim_frames), sizeof(uint32_t) * array::size(anim_frames));
+	}
+
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+		const size_t file_size = file->size();
+		void* res = allocator.allocate(file_size);
+		file->read(res, file_size);
+		bundle.close(file);
+		return res;
+	}
+
+	void online(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
+	{
+	}
+
+	void unload(Allocator& a, void* resource)
+	{
+		a.deallocate(resource);
+	}
+
+	const SpriteAnimationData* get_animation(const SpriteAnimationResource* sar, StringId32 name)
+	{
+		const uint32_t num = sar->num_animations;
+		const SpriteAnimationName* begin = (SpriteAnimationName*) ((char*) sar + sizeof(*sar));
+		const SpriteAnimationData* data = (SpriteAnimationData*) ((char*) sar + sizeof(*sar) + sizeof(SpriteAnimationName) * num);
+
+		for (uint32_t i = 0; i < num; i++)
+		{
+			if (begin[i].id == name)
+				return &data[i];
+		}
+
+		return NULL;
+	}
+
+	const uint32_t* get_animation_frames(const SpriteAnimationResource* sar)
+	{
+		return (uint32_t*) ((char*) sar + sar->frames_offset);
+	}
+} // namespace sprite_animation_resource
 } // namespace crown

+ 55 - 95
engine/resource/sprite_resource.h

@@ -26,17 +26,16 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #pragma once
 
-#include "types.h"
 #include "allocator.h"
-#include "file.h"
-#include "os.h"
-#include "string_utils.h"
-#include "container_types.h"
 #include "bundle.h"
+#include "container_types.h"
 #include "device.h"
+#include "file.h"
+#include "os.h"
+#include "reader_writer.h"
 #include "resource_manager.h"
-#include "texture_resource.h"
-#include "blob.h"
+#include "string_utils.h"
+#include "types.h"
 #include <cstring>
 #include <inttypes.h>
 #include <bgfx.h>
@@ -48,101 +47,62 @@ const uint32_t SPRITE_VERSION = 1;
 
 struct SpriteHeader
 {
-	uint32_t		dummy[2];
-	uint32_t		num_animations;
-	uint32_t		animations_offset;
-	uint32_t		num_vertices;
-	uint32_t		vertices_offset;
-	uint32_t		num_indices;
-	uint32_t		indices_offset;
+	uint32_t version;
 };
 
-struct SpriteAnimation
+// header
+// num_verts
+// verts[num_verts]
+// num_inds
+// inds[num_inds]
+
+struct SpriteResource
 {
-	StringId32 name;
-	float time;
-	uint32_t num_frames;
-	uint32_t start_frame;
+	const bgfx::Memory* vbmem;
+	const bgfx::Memory* ibmem;
+	bgfx::VertexBufferHandle vb;
+	bgfx::IndexBufferHandle ib;
 };
 
 //-----------------------------------------------------------------------------
-struct SpriteResource
+namespace sprite_resource
+{
+	void compile(crown::Filesystem&, char const*, crown::File*);
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 id, ResourceManager& rm);
+	void offline(StringId64 id, ResourceManager& rm);
+	void unload(Allocator& a, void* resource);
+} // namespace sprite_resource
+
+struct SpriteAnimationResource
 {
-	//-----------------------------------------------------------------------------
-	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
-	{
-		File* file = bundle.open(id);
-		const size_t file_size = file->size();
-
-		void* res = allocator.allocate(file_size);
-		file->read(res, file_size);
-
-		bundle.close(file);
-
-		return res;
-	}
-
-	//-----------------------------------------------------------------------------
-	static void online(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-
-	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
-	//-----------------------------------------------------------------------------
-	const SpriteAnimation* get_animation(const char* name) const
-	{
-		SpriteHeader* h = (SpriteHeader*) this;
-		SpriteAnimation* begin = (SpriteAnimation*) (((char*) this) + h->animations_offset);
-
-		const StringId32 name_hash = string::murmur2_32(name, string::strlen(name));
-		const uint32_t num = h->num_animations;
-		for (uint32_t i = 0; i < num; i++)
-		{
-			if (begin[i].name == name_hash)
-				return &begin[i];
-		}
-
-		return NULL;
-	}
-
-	uint32_t get_animation_frame(const SpriteAnimation* a, uint32_t frame) const
-	{
-		SpriteHeader* h = (SpriteHeader*) this;
-		uint32_t* begin = (uint32_t*) (((char*) this) + h->animations_offset + sizeof(SpriteAnimation) * h->num_animations);
-		return begin[a->start_frame + frame];
-	}
-
-	Blob get_vertices() const
-	{
-		SpriteHeader* h = (SpriteHeader*) this;
-		Blob b;
-		b.m_size = ((SpriteHeader*) this)->num_vertices * 16;
-		b.m_data = (uintptr_t) (((char*) this) + h->vertices_offset);
-		return b;
-	}
-
-	Blob get_indices() const
-	{
-		SpriteHeader* h = (SpriteHeader*) this;
-		Blob b;
-		b.m_size = ((SpriteHeader*) this)->num_indices * 2;
-		b.m_data = (uintptr_t) (((char*) this) + h->indices_offset);
-		return b;
-	}
-
-private:
-
-	// Disable construction
-	SpriteResource();
+	uint32_t version;
+	uint32_t num_animations;
+	uint32_t num_frames;
+	uint32_t frames_offset;
 };
 
+struct SpriteAnimationName
+{
+	StringId32 id;
+};
+
+struct SpriteAnimationData
+{
+	uint32_t num_frames;
+	uint32_t first_frame;
+	float time;
+};
+
+namespace sprite_animation_resource
+{
+	void compile(crown::Filesystem&, char const*, crown::File*);
+	void* load(Allocator& allocator, Bundle& bundle, ResourceId id);
+	void online(StringId64 id, ResourceManager& rm);
+	void offline(StringId64 id, ResourceManager& rm);
+	void unload(Allocator& a, void* resource);
+	const SpriteAnimationData* get_animation(const SpriteAnimationResource* sar, StringId32 name);
+	const uint32_t* get_animation_frames(const SpriteAnimationResource* sar);
+}
+
 } // namespace crown

+ 89 - 0
engine/resource/texture_resource.cpp

@@ -35,6 +35,95 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
+#define FOURCC(a, b, c, d)			uint32_t(a | (b << 8) | (c << 16) | (d << 24))
+
+#define DDSD_MAGIC 					FOURCC('D', 'D', 'S', ' ')
+#define DDSD_HEADERSIZE				uint32_t(124)
+#define DDSD_UNUSED					uint32_t(0x00000000)
+#define DDSD_CAPS					uint32_t(0x00000001) // Required in every .dds file.
+#define DDSD_HEIGHT					uint32_t(0x00000002) // Required in every .dds file.
+#define DDSD_WIDTH					uint32_t(0x00000004) // Required in every .dds file.
+#define DDSD_PITCH					uint32_t(0x00000008) // Required when pitch is provided for an uncompressed texture.
+#define DDSD_PIXELFORMAT			uint32_t(0x00001000) // Required in every .dds file.
+#define DDSD_MIPMAPCOUNT			uint32_t(0x00020000) // Required in a mipmapped texture.
+#define DDSD_LINEARSIZE				uint32_t(0x00080000) // Required when pitch is provided for a compressed texture.
+#define DDSD_DEPTH					uint32_t(0x00800000) // Required in a depth texture.
+
+#define DDS_HEADER_FLAGS_TEXTURE	uint32_t(DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT)
+#define DDS_HEADER_FLAGS_MIPMAP		uint32_t(DDSD_MIPMAPCOUNT)
+#define DDS_HEADER_FLAGS_VOLUME		uint32_t(DDSD_DEPTH)
+#define DDS_HEADER_FLAGS_PITCH		uint32_t(DDSD_PITCH)
+#define DDS_HEADER_FLAGS_LINEARSIZE	uint32_t(DDSD_LINEARSIZE)
+
+#define DDSCAPS_COMPLEX				uint32_t(0x00000008) // Optional; must be used on any file that contains more than one surface (a mipmap, a cubic environment map, or mipmapped volume texture).
+#define DDSCAPS_MIPMAP				uint32_t(0x00400000) // Optional; should be used for a mipmap.
+#define DDSCAPS_TEXTURE				uint32_t(0x00001000) // Required
+
+#define DDSCAPS2_CUBEMAP			uint32_t(0x00000200) // Required for a cube map.
+#define DDSCAPS2_CUBEMAP_POSITIVEX	uint32_t(0x00000400) // Required when these surfaces are stored in a cube map.
+#define DDSCAPS2_CUBEMAP_NEGATIVEX	uint32_t(0x00000800) // Required when these surfaces are stored in a cube map.
+#define DDSCAPS2_CUBEMAP_POSITIVEY	uint32_t(0x00001000) // Required when these surfaces are stored in a cube map.
+#define DDSCAPS2_CUBEMAP_NEGATIVEY	uint32_t(0x00002000) // Required when these surfaces are stored in a cube map.
+#define DDSCAPS2_CUBEMAP_POSITIVEZ	uint32_t(0x00004000) // Required when these surfaces are stored in a cube map.
+#define DDSCAPS2_CUBEMAP_NEGATIVEZ	uint32_t(0x00008000) // Required when these surfaces are stored in a cube map.
+#define DDSCAPS2_VOLUME				uint32_t(0x00200000) // Required for a volume texture.
+
+#define DDPF_HEADERSIZE				uint32_t(32)
+#define DDPF_ALPHAPIXELS			uint32_t(0x00000001) // Texture contains alpha data; dwRGBAlphaBitMask contains valid data.
+#define DDPF_ALPHA					uint32_t(0x00000002) // Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data)
+#define DDPF_FOURCC					uint32_t(0x00000004) // Texture contains compressed RGB data; dwFourCC contains valid data.
+#define DDPF_RGB					uint32_t(0x00000040) // Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwGBitMask, dwBBitMask) contain valid data.
+#define DDPF_YUV					uint32_t(0x00000200) // Used in some older DDS files for YUV uncompressed data (dwRGBBitCount contains the YUV bit count; dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask)
+#define DDPF_LUMINANCE				uint32_t(0x00020000) // Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count; dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file.
+
+#define DDS_FOURCC					uint32_t(DDPF_FOURCC)
+#define DDS_RGB						uint32_t(DDPF_RGB)
+#define DDS_RGBA					uint32_t(DDPF_RGB | DDPF_ALPHAPIXELS)
+#define DDS_LUMINANCE				uint32_t(DDPF_LUMINANCE)
+#define DDS_LUMINANCEA				uint32_t(DDPF_LUMINANCE | DDPF_ALPHAPIXELS)
+#define DDS_ALPHA					uint32_t(DDPF_ALPHA)
+
+#define DDPF_FOURCC_DXT1			FOURCC('D', 'X', 'T', '1')
+#define DDPF_FOURCC_DXT2			FOURCC('D', 'X', 'T', '2')
+#define DDPF_FOURCC_DXT3			FOURCC('D', 'X', 'T', '3')
+#define DDPF_FOURCC_DXT4			FOURCC('D', 'X', 'T', '4')
+#define DDPF_FOURCC_DXT5			FOURCC('D', 'X', 'T', '5')
+#define DDPF_FOURCC_DX10			FOURCC('D', 'X', '1', '0')
+
+#define DDS_HEADER_OFFSET			uint32_t(sizeof(TextureHeader))
+#define DDS_DATA_OFFSET				uint32_t(DDS_HEADER_OFFSET + DDSD_HEADERSIZE)
+
+struct DdsPixelFormat
+{
+	uint32_t size;
+	uint32_t flags;
+	uint32_t fourcc;
+	uint32_t bitcount;
+	uint32_t rmask;
+	uint32_t gmask;
+	uint32_t bmask;
+	uint32_t amask;
+};
+
+struct DdsHeader
+{
+	uint32_t		magic;
+	uint32_t        size;
+	uint32_t        flags;
+	uint32_t        height;
+	uint32_t        width;
+	uint32_t        pitch_or_linear_size;
+	uint32_t        depth;
+	uint32_t        num_mips;
+	uint32_t        reserved[11];
+	DdsPixelFormat  ddspf;
+	uint32_t        caps;
+	uint32_t        caps2;
+	uint32_t        caps3;
+	uint32_t        caps4;
+	uint32_t        reserved2;
+};
+
 struct PixelFormat
 {
 	enum Enum

+ 29 - 125
engine/resource/texture_resource.h

@@ -31,105 +31,24 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "bundle.h"
 #include "allocator.h"
 #include "file.h"
+#include "resource_manager.h"
+#include "memory.h"
 #include <bgfx.h>
 
 namespace crown
 {
 
-#define FOURCC(a, b, c, d)			uint32_t(a | (b << 8) | (c << 16) | (d << 24))
-
-#define DDSD_MAGIC 					FOURCC('D', 'D', 'S', ' ')
-#define DDSD_HEADERSIZE				uint32_t(124)
-#define DDSD_UNUSED					uint32_t(0x00000000)
-#define DDSD_CAPS					uint32_t(0x00000001) // Required in every .dds file.
-#define DDSD_HEIGHT					uint32_t(0x00000002) // Required in every .dds file.
-#define DDSD_WIDTH					uint32_t(0x00000004) // Required in every .dds file.
-#define DDSD_PITCH					uint32_t(0x00000008) // Required when pitch is provided for an uncompressed texture.
-#define DDSD_PIXELFORMAT			uint32_t(0x00001000) // Required in every .dds file.
-#define DDSD_MIPMAPCOUNT			uint32_t(0x00020000) // Required in a mipmapped texture.
-#define DDSD_LINEARSIZE				uint32_t(0x00080000) // Required when pitch is provided for a compressed texture.
-#define DDSD_DEPTH					uint32_t(0x00800000) // Required in a depth texture.
-
-#define DDS_HEADER_FLAGS_TEXTURE	uint32_t(DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT)
-#define DDS_HEADER_FLAGS_MIPMAP		uint32_t(DDSD_MIPMAPCOUNT)
-#define DDS_HEADER_FLAGS_VOLUME		uint32_t(DDSD_DEPTH)
-#define DDS_HEADER_FLAGS_PITCH		uint32_t(DDSD_PITCH)
-#define DDS_HEADER_FLAGS_LINEARSIZE	uint32_t(DDSD_LINEARSIZE)
-
-#define DDSCAPS_COMPLEX				uint32_t(0x00000008) // Optional; must be used on any file that contains more than one surface (a mipmap, a cubic environment map, or mipmapped volume texture).
-#define DDSCAPS_MIPMAP				uint32_t(0x00400000) // Optional; should be used for a mipmap.
-#define DDSCAPS_TEXTURE				uint32_t(0x00001000) // Required
-
-#define DDSCAPS2_CUBEMAP			uint32_t(0x00000200) // Required for a cube map.
-#define DDSCAPS2_CUBEMAP_POSITIVEX	uint32_t(0x00000400) // Required when these surfaces are stored in a cube map.
-#define DDSCAPS2_CUBEMAP_NEGATIVEX	uint32_t(0x00000800) // Required when these surfaces are stored in a cube map.
-#define DDSCAPS2_CUBEMAP_POSITIVEY	uint32_t(0x00001000) // Required when these surfaces are stored in a cube map.
-#define DDSCAPS2_CUBEMAP_NEGATIVEY	uint32_t(0x00002000) // Required when these surfaces are stored in a cube map.
-#define DDSCAPS2_CUBEMAP_POSITIVEZ	uint32_t(0x00004000) // Required when these surfaces are stored in a cube map.
-#define DDSCAPS2_CUBEMAP_NEGATIVEZ	uint32_t(0x00008000) // Required when these surfaces are stored in a cube map.
-#define DDSCAPS2_VOLUME				uint32_t(0x00200000) // Required for a volume texture.
-
-#define DDPF_HEADERSIZE				uint32_t(32)
-#define DDPF_ALPHAPIXELS			uint32_t(0x00000001) // Texture contains alpha data; dwRGBAlphaBitMask contains valid data.
-#define DDPF_ALPHA					uint32_t(0x00000002) // Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data)
-#define DDPF_FOURCC					uint32_t(0x00000004) // Texture contains compressed RGB data; dwFourCC contains valid data.
-#define DDPF_RGB					uint32_t(0x00000040) // Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwGBitMask, dwBBitMask) contain valid data.
-#define DDPF_YUV					uint32_t(0x00000200) // Used in some older DDS files for YUV uncompressed data (dwRGBBitCount contains the YUV bit count; dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask)
-#define DDPF_LUMINANCE				uint32_t(0x00020000) // Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count; dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file.
-
-#define DDS_FOURCC					uint32_t(DDPF_FOURCC)
-#define DDS_RGB						uint32_t(DDPF_RGB)
-#define DDS_RGBA					uint32_t(DDPF_RGB | DDPF_ALPHAPIXELS)
-#define DDS_LUMINANCE				uint32_t(DDPF_LUMINANCE)
-#define DDS_LUMINANCEA				uint32_t(DDPF_LUMINANCE | DDPF_ALPHAPIXELS)
-#define DDS_ALPHA					uint32_t(DDPF_ALPHA)
-
-#define DDPF_FOURCC_DXT1			FOURCC('D', 'X', 'T', '1')
-#define DDPF_FOURCC_DXT2			FOURCC('D', 'X', 'T', '2')
-#define DDPF_FOURCC_DXT3			FOURCC('D', 'X', 'T', '3')
-#define DDPF_FOURCC_DXT4			FOURCC('D', 'X', 'T', '4')
-#define DDPF_FOURCC_DXT5			FOURCC('D', 'X', 'T', '5')
-#define DDPF_FOURCC_DX10			FOURCC('D', 'X', '1', '0')
-
-struct DdsPixelFormat
-{
-	uint32_t size;
-	uint32_t flags;
-	uint32_t fourcc;
-	uint32_t bitcount;
-	uint32_t rmask;
-	uint32_t gmask;
-	uint32_t bmask;
-	uint32_t amask;
-};
-
-struct DdsHeader
-{
-	uint32_t		magic;
-	uint32_t        size;
-	uint32_t        flags;
-	uint32_t        height;
-	uint32_t        width;
-	uint32_t        pitch_or_linear_size;
-	uint32_t        depth;
-	uint32_t        num_mips;
-	uint32_t        reserved[11];
-	DdsPixelFormat  ddspf;
-	uint32_t        caps;
-	uint32_t        caps2;
-	uint32_t        caps3;
-	uint32_t        caps4;
-	uint32_t        reserved2;
-};
-
 struct TextureHeader
 {
 	uint32_t version;
 	uint32_t size;
 };
 
-#define DDS_HEADER_OFFSET	uint32_t(sizeof(TextureHeader))
-#define DDS_DATA_OFFSET		uint32_t(DDS_HEADER_OFFSET + DDSD_HEADERSIZE)
+struct TextureImage
+{
+	const bgfx::Memory* mem; // BGFX will take care of deallocation
+	bgfx::TextureHandle handle;
+};
 
 struct TextureResource
 {
@@ -138,57 +57,42 @@ struct TextureResource
 	{
 		File* file = bundle.open(id);
 		const size_t file_size = file->size();
-
-		void* res = allocator.allocate(file_size);
-		file->read(res, file_size);
-
+		file->skip(sizeof(TextureHeader));
+		const bgfx::Memory* mem = bgfx::alloc(file_size);
+		file->read(mem->data, file_size - sizeof(TextureHeader));
 		bundle.close(file);
 
-		// HACK HACK HACK
-		TextureHeader* th = (TextureHeader*) res;
-		th->size = file_size;
+		TextureImage* teximg = (TextureImage*) default_allocator().allocate(sizeof(TextureImage));
+		teximg->mem = mem;
+		teximg->handle.idx = bgfx::invalidHandle;
 
-		return res;
-	}
-
-	//-----------------------------------------------------------------------------
-	static void online(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
+		return teximg;
 	}
 
-	static void offline(StringId64 /*id*/, ResourceManager& /*rm*/)
-	{
-	}
-	
 	//-----------------------------------------------------------------------------
-	static void unload(Allocator& allocator, void* resource)
-	{
-		allocator.deallocate(resource);
-	}
-
-	uint32_t width() const
+	static void online(StringId64 id, ResourceManager& rm)
 	{
-		return ((DdsHeader*) (((char*) this) + DDS_HEADER_OFFSET))->width;
-	}
+		ResourceId res_id;
+		res_id.type = TEXTURE_TYPE;
+		res_id.name = id;
 
-	uint32_t height() const
-	{
-		return ((DdsHeader*) (((char*) this) + DDS_HEADER_OFFSET))->height;
+		TextureImage* teximg = (TextureImage*) rm.get(res_id);
+		teximg->handle = bgfx::createTexture(teximg->mem);
 	}
 
-	uint8_t num_mipmaps() const
+	static void offline(StringId64 id, ResourceManager& rm)
 	{
-		return (uint8_t) ((DdsHeader*) (((char*) this) + DDS_HEADER_OFFSET))->num_mips;
-	}
+		ResourceId res_id;
+		res_id.type = TEXTURE_TYPE;
+		res_id.name = id;
 
-	uint32_t size() const
-	{
-		return ((TextureHeader*) this)->size;
+		TextureImage* teximg = (TextureImage*) rm.get(res_id);
+		bgfx::destroyTexture(teximg->handle);
 	}
-
-	const char* data() const
+	
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& /*a*/, void* /*resource*/)
 	{
-		return (char*) this + DDS_HEADER_OFFSET;
 	}
 
 private:

+ 7 - 0
engine/resource/unit_resource.cpp

@@ -363,8 +363,15 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 		m_physics_resource = ResourceId();
 	}
 
+	ResourceId sprite_anim;
+	sprite_anim.type = 0;
+	sprite_anim.name = 0;
+	if (root.has_key("sprite_animation"))
+		sprite_anim = root.key("sprite_animation").to_resource_id("sprite_animation");
+
 	UnitHeader h;
 	h.physics_resource = m_physics_resource;
+	h.sprite_animation = sprite_anim.name;
 	h.num_renderables = array::size(m_renderables);
 	h.num_materials = array::size(m_materials);
 	h.num_cameras = array::size(m_cameras);

+ 9 - 0
engine/resource/unit_resource.h

@@ -42,6 +42,7 @@ namespace crown
 struct UnitHeader
 {
 	ResourceId physics_resource;
+	StringId64 sprite_animation;
 	uint32_t num_renderables;
 	uint32_t renderables_offset;
 	uint32_t num_materials;
@@ -137,6 +138,14 @@ struct UnitResource
 		allocator.deallocate(resource);
 	}
 
+	ResourceId sprite_animation() const
+	{
+		ResourceId id;
+		id.type = SPRITE_ANIMATION_TYPE;
+		id.name = ((UnitHeader*) this)->sprite_animation;
+		return id;
+	}
+
 	//-----------------------------------------------------------------------------
 	ResourceId physics_resource() const
 	{

+ 45 - 15
engine/world/unit.cpp

@@ -36,6 +36,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "device.h"
 #include "resource_manager.h"
 #include "sprite.h"
+#include "sprite_animation_player.h"
 
 namespace crown
 {
@@ -44,6 +45,7 @@ namespace crown
 Unit::Unit(World& w, UnitId unit_id, const ResourceId id, const UnitResource* ur, const Matrix4x4& pose)
 	: m_world(w)
 	, m_scene_graph(*w.scene_graph_manager()->create_scene_graph())
+	, m_sprite_animation(NULL)
 	, m_resource_id(id)
 	, m_resource(ur)
 	, m_id(unit_id)
@@ -51,6 +53,7 @@ Unit::Unit(World& w, UnitId unit_id, const ResourceId id, const UnitResource* ur
 	, m_num_meshes(0)
 	, m_num_sprites(0)
 	, m_num_actors(0)
+	, m_num_materials(0)
 	, m_values(NULL)
 {
 	m_controller.component.id = INVALID_ID;
@@ -96,6 +99,12 @@ void Unit::create_objects(const Matrix4x4& pose)
 
 	m_values = (char*) default_allocator().allocate(m_resource->values_size());
 	memcpy(m_values, m_resource->values(), m_resource->values_size());
+
+	ResourceId anim_id = m_resource->sprite_animation();
+	if (anim_id.name != 0)
+	{
+		m_sprite_animation = m_world.sprite_animation_player()->create_sprite_animation((SpriteAnimationResource*) device()->resource_manager()->get(anim_id));
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -138,6 +147,13 @@ void Unit::destroy_objects()
 		m_controller.component.id = INVALID_ID;
 	}
 
+	// Destroy materials
+	for (uint32_t i = 0; i < m_num_materials; i++)
+	{
+		material_manager::get()->destroy_material(m_materials[i].component);
+	}
+	m_num_materials = 0;
+
 	// Destroy scene graph
 	m_scene_graph.destroy();
 }
@@ -178,6 +194,12 @@ void Unit::create_renderable_objects()
 			CE_FATAL("Oops, bad renderable type");
 		}
 	}
+
+	for (uint32_t i = 0; i < m_resource->num_materials(); i++)
+	{
+		const UnitMaterial material = m_resource->get_material(i);
+		add_material(string::murmur2_32("default", string::strlen("default"), 0), material_manager::get()->create_material(material.id));
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -218,12 +240,12 @@ void Unit::create_physics_objects()
 //-----------------------------------------------------------------------------
 void Unit::set_default_material()
 {
-	if (m_resource->num_materials() == 0) return;
+	if (m_num_materials == 0) return;
 
 	for (uint32_t i = 0; i < m_num_sprites; i++)
 	{
 		Sprite* s = m_world.render_world()->get_sprite(m_sprites[i].component);
-		s->set_material(m_resource->get_material(0).id);
+		s->set_material(m_materials[0].component);
 	}
 }
 
@@ -314,6 +336,10 @@ void Unit::unlink_node(int32_t child)
 //-----------------------------------------------------------------------------
 void Unit::update()
 {
+	if (m_sprite_animation)
+	{
+		sprite(0u)->set_frame(m_sprite_animation->m_cur_frame);
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -406,6 +432,14 @@ void Unit::add_actor(StringId32 name, ActorId actor)
 	add_component(name, actor, m_num_actors, m_actors);
 }
 
+//-----------------------------------------------------------------------------
+void Unit::add_material(StringId32 name, MaterialId material)
+{
+	CE_ASSERT(m_num_materials < CE_MAX_MATERIAL_COMPONENTS, "Max material number reached");
+
+	add_component(name, material, m_num_materials, m_materials);
+}
+
 //-----------------------------------------------------------------------------
 void Unit::set_controller(StringId32 name, ControllerId controller)
 {
@@ -517,23 +551,17 @@ Controller* Unit::controller()
 //-----------------------------------------------------------------------------
 Material* Unit::material(const char* name)
 {
-/*	MaterialId material = find_component(name, m_num_materials, m_materials);
-
+	MaterialId material = find_component(name, m_num_materials, m_materials);
 	CE_ASSERT(material.id != INVALID_ID, "Unit does not have material with name '%s'", name);
-
-	return m_world.render_world()->get_material(material);*/
-	return NULL;
+	return material_manager::get()->lookup_material(material);
 }
 
 //-----------------------------------------------------------------------------
 Material* Unit::material(uint32_t i)
 {
-/*	MaterialId material = find_component_by_index(i, m_num_materials, m_materials);
-
+	MaterialId material = find_component_by_index(i, m_num_materials, m_materials);
 	CE_ASSERT(material.id != INVALID_ID, "Unit does not have material with name '%d'", i);
-
-	return m_world.render_world()->get_material(material);*/
-	return NULL;
+	return material_manager::get()->lookup_material(material);
 }
 
 //-----------------------------------------------------------------------------
@@ -545,13 +573,15 @@ bool Unit::is_a(const char* name)
 //-----------------------------------------------------------------------------
 void Unit::play_sprite_animation(const char* name, bool loop)
 {
-	sprite(0u)->play_animation(name, loop);
+	if (m_sprite_animation)
+		m_sprite_animation->play(string::murmur2_32(name, string::strlen(name), 0), loop);
 }
 
 //-----------------------------------------------------------------------------
 void Unit::stop_sprite_animation()
 {
-	sprite(0u)->stop_animation();
+	if (m_sprite_animation)
+		m_sprite_animation->stop();
 }
 
 //-----------------------------------------------------------------------------
@@ -636,4 +666,4 @@ void Unit::set_key(const char* k, const Vector3& v)
 	*(Vector3*)(m_values + key.offset) = v;
 }
 
-} // namespace crown
+} // namespace crown

+ 8 - 0
engine/world/unit.h

@@ -35,6 +35,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "world_types.h"
 #include "render_world_types.h"
 #include "config.h"
+#include "sprite_animation.h"
 
 namespace crown
 {
@@ -53,6 +54,7 @@ struct ComponentType
 };
 
 typedef	Id ComponentId;
+typedef Id MaterialId;
 
 struct Component
 {
@@ -116,6 +118,7 @@ struct Unit
 	void add_sprite(StringId32 name, SpriteId sprite);
 	void add_actor(StringId32 name, ActorId actor);
 	void set_controller(StringId32 name, ControllerId controller);
+	void add_material(StringId32 name, MaterialId material);
 
 	Camera* camera(const char* name);
 	Camera* camera(uint32_t i);
@@ -164,6 +167,7 @@ public:
 
 	World& m_world;
 	SceneGraph& m_scene_graph;
+	SpriteAnimation* m_sprite_animation;
 	const ResourceId m_resource_id;
 	const UnitResource*	m_resource;
 	UnitId m_id;
@@ -180,7 +184,11 @@ public:
 	uint32_t m_num_actors;
 	Component m_actors[CE_MAX_ACTOR_COMPONENTS];
 
+	uint32_t m_num_materials;
+	Component m_materials[CE_MAX_MATERIAL_COMPONENTS];
+
 	Component m_controller;
+
 	char* m_values;
 };