فهرست منبع

Merge branch 'world' of https://github.com/taylor001/crown into world

Conflicts:
	engine/CMakeLists.txt
	engine/Unit.h
	engine/compilers/package/PackageCompiler.cpp
	engine/compilers/package/PackageCompiler.h
	engine/resource/PackageResource.h
	engine/resource/ResourcePackage.h
	engine/resource/ResourceRegistry.cpp
Daniele Bartolini 12 سال پیش
والد
کامیت
e9ee051764

+ 8 - 0
engine/CMakeLists.txt

@@ -69,6 +69,7 @@ set (CROWN_INCLUDES
 	${CMAKE_SOURCE_DIR}/engine/compilers/mesh
 	${CMAKE_SOURCE_DIR}/engine/compilers/package
 	${CMAKE_SOURCE_DIR}/engine/compilers/unit
+	${CMAKE_SOURCE_DIR}/engine/compilers/sprite
 )
 
 set (SRC
@@ -79,6 +80,7 @@ set (SRC
 	SceneGraph.cpp
 	RenderWorld.cpp
 	Mesh.cpp
+	Sprite.cpp
 )
 
 set (HEADERS
@@ -91,6 +93,8 @@ set (HEADERS
 	SceneGraph.h
 	RenderWorld.h
 	Mesh.h
+	Sprite.h
+	SpriteAnimator.h
 )
 
 set (CORE_SRC
@@ -302,6 +306,7 @@ set (RESOURCE_HEADERS
 	resource/PackageResource.h
 	resource/UnitResource.h
 	resource/ResourcePackage.h
+	resource/SpriteResource.h
 )
 
 set (RPC_SRC
@@ -345,6 +350,7 @@ set (LUA_SRC
 	lua/LuaUnit.cpp
 	lua/LuaCamera.cpp
 	lua/LuaMesh.cpp
+	lua/LuaSprite.cpp
 )
 
 set (LUA_HEADERS
@@ -368,6 +374,7 @@ set (COMPILER_SRC
 	compilers/sound/SoundCompiler.cpp
 	compilers/package/PackageCompiler.cpp
 	compilers/unit/UnitCompiler.cpp
+	compilers/sprite/SpriteCompiler.cpp
 )
 
 set (COMPILER_HEADER
@@ -379,6 +386,7 @@ set (COMPILER_HEADER
 	compilers/sound/SoundCompiler.h
 	compilers/package/PackageCompiler.h
 	compilers/unit/UnitCompiler.h
+	compilers/sprite/SpriteCompiler.h
 )
 
 set (CROWN_LIBRARIES)

+ 87 - 27
engine/RenderWorld.cpp

@@ -30,6 +30,10 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Renderer.h"
 #include "Allocator.h"
 #include "Camera.h"
+#include "Resource.h"
+#include "Log.h"
+#include "SpriteResource.h"
+#include "SpriteAnimator.h"
 
 namespace crown
 {
@@ -86,7 +90,10 @@ static const char* texture_fragment =
 
 //-----------------------------------------------------------------------------
 RenderWorld::RenderWorld()
-	: m_mesh(default_allocator())
+	: m_mesh_pool(default_allocator(), MAX_MESHES, sizeof(Mesh))
+	, m_mesh(default_allocator())
+	, m_transform(default_allocator())
+	, m_sprite(default_allocator())
 {
 	Renderer* r = device()->renderer();
 
@@ -118,13 +125,18 @@ RenderWorld::~RenderWorld()
 }
 
 //-----------------------------------------------------------------------------
-MeshId RenderWorld::create_mesh(const char* name, int32_t node, const Vector3& pos, const Quaternion& rot)
+MeshId RenderWorld::create_mesh(ResourceId id, int32_t node, const Vector3& pos, const Quaternion& rot)
 {
-	MeshResource* mr = (MeshResource*) device()->resource_manager()->lookup("mesh", name);
+	MeshResource* mr = (MeshResource*) device()->resource_manager()->data(id);
 
-	MeshId mesh = allocate_mesh(mr, node, pos, rot);
+	// Allocate memory for mesh
+	Mesh* mesh = (Mesh*) m_mesh_pool.allocate(sizeof(Mesh));
 
-	return mesh;
+	// Create mesh id
+	const MeshId mesh_id = m_mesh.create(mesh);
+	mesh->create(mr, node, pos, rot);
+
+	return mesh_id;
 }
 
 //-----------------------------------------------------------------------------
@@ -135,61 +147,109 @@ void RenderWorld::destroy_mesh(MeshId /*id*/)
 //-----------------------------------------------------------------------------
 Mesh* RenderWorld::lookup_mesh(MeshId mesh)
 {
-	CE_ASSERT(m_mesh_table.has(mesh), "Mesh does not exits");
+	CE_ASSERT(m_mesh.has(mesh), "Mesh does not exits");
+
+	return m_mesh.lookup(mesh);
+}
+
+//-----------------------------------------------------------------------------
+SpriteId RenderWorld::create_sprite(const char* name, int32_t node, const Vector3& pos, const Quaternion& rot)
+{
+	SpriteResource* sr = (SpriteResource*) device()->resource_manager()->lookup(SPRITE_EXTENSION, name);
+
+	SpriteId sprite = allocate_sprite(sr, node, pos, rot);
+
+	return sprite;
+}
+
+//-----------------------------------------------------------------------------
+void RenderWorld::destroy_sprite(SpriteId /*id*/)
+{
+	// Stub
+}
 
-	return &m_mesh[m_sparse_to_packed[mesh.index]];
+//-----------------------------------------------------------------------------
+Sprite*	RenderWorld::lookup_sprite(SpriteId id)
+{
+	return &m_sprite[m_sprite_sparse_to_packed[id.index]];
 }
 
 //-----------------------------------------------------------------------------
-void RenderWorld::update(Camera& camera, float /*dt*/)
+void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float /*dt*/)
 {
+	static uint64_t frames = 0;
+
 	Renderer* r = device()->renderer();
 
-	Matrix4x4 camera_view = camera.world_pose();
-	camera_view.invert();
+	Matrix4x4 inv_view = view;
+	inv_view.invert();
 
-	r->set_layer_view(0, camera_view);
-	r->set_layer_projection(0, camera.m_projection);
-	r->set_layer_viewport(0, 0, 0, 1000, 625);
+	r->set_layer_view(0, inv_view);
+	r->set_layer_projection(0, projection);
+	r->set_layer_viewport(0, x, y, width, height);
 	r->set_layer_clear(0, CLEAR_COLOR | CLEAR_DEPTH, Color4::LIGHTBLUE, 1.0f);
 
 	r->set_state(STATE_DEPTH_WRITE | STATE_COLOR_WRITE | STATE_CULL_CCW);
 	r->commit(0);
 
 	// Draw all meshes
-	for (uint32_t m = 0; m < m_mesh.size(); m++)
+	const List<Mesh*>& meshes = m_mesh.m_objects;
+
+	for (uint32_t m = 0; m < meshes.size(); m++)
 	{
-		const Mesh& mesh = m_mesh[m];
+		const Mesh* mesh = meshes[m];
 
 		r->set_state(STATE_DEPTH_WRITE | STATE_COLOR_WRITE | STATE_ALPHA_WRITE | STATE_CULL_CW);
-		r->set_vertex_buffer(mesh.m_vbuffer);
-		r->set_index_buffer(mesh.m_ibuffer);
+		r->set_vertex_buffer(mesh->m_vbuffer);
+		r->set_index_buffer(mesh->m_ibuffer);
 		r->set_program(default_program);
-/*		r->set_texture(0, u_albedo_0, grass_texture, TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_CLAMP_EDGE);
+		/*r->set_texture(0, u_albedo_0, grass_texture, TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_CLAMP_EDGE);
 		r->set_uniform(u_brightness, UNIFORM_FLOAT_1, &brightness, 1);*/
 
-		r->set_pose(mesh.m_local_pose);
+		r->set_pose(mesh->m_local_pose);
+		r->commit(0);
+	}
+
+	for (uint32_t s = 0; s < m_sprite.size(); s++)
+	{
+		Sprite& sprite = m_sprite[s];
+
+		if (frames % sprite.m_animator->m_frame_rate == 0)
+		{
+			sprite.m_animator->play_frame();
+		}
+
+		r->set_state(STATE_DEPTH_WRITE | STATE_COLOR_WRITE | STATE_ALPHA_WRITE | STATE_CULL_CW);
+		r->set_vertex_buffer(sprite.m_vb);
+		r->set_index_buffer(sprite.m_ib);
+		r->set_program(sprite.m_program);
+		r->set_texture(0, sprite.m_uniform, sprite.m_texture, TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_CLAMP_EDGE);
+
+		r->set_pose(sprite.m_local_pose);
 		r->commit(0);
 	}
+
+	frames++;
 }
 
 //-----------------------------------------------------------------------------
-MeshId RenderWorld::allocate_mesh(MeshResource* mr, int32_t node, const Vector3& pos, const Quaternion& rot)
+SpriteId RenderWorld::allocate_sprite(SpriteResource* sr, int32_t node, const Vector3& pos, const Quaternion& rot)
 {
-	MeshId mesh_id = m_mesh_table.create();
+	SpriteId id = m_sprite_table.create();
 
-	Mesh mesh;
-	mesh.create(mr, node, pos, rot);
+	Sprite sprite;
+	sprite.create(sr, node, pos, rot);
 
-	uint32_t index = m_mesh.push_back(mesh);
-	m_sparse_to_packed[mesh_id.index] = index;
+	uint32_t index = m_sprite.push_back(sprite);
+	m_sprite_sparse_to_packed[id.index] = index;
 
-	return mesh_id;
+	return id;
 }
 
 //-----------------------------------------------------------------------------
-void RenderWorld::deallocate_mesh(MeshId /*id*/)
+void RenderWorld::deallocate_sprite(SpriteId /*id*/)
 {
+	// Stub
 }
 
 } // namespace crown

+ 28 - 9
engine/RenderWorld.h

@@ -27,17 +27,24 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "IdTable.h"
+#include "IdArray.h"
 #include "Mesh.h"
+#include "Sprite.h"
 #include "List.h"
 #include "Vector3.h"
 #include "Quaternion.h"
+#include "PoolAllocator.h"
+#include "Resource.h"
 
 #define MAX_MESHES 100
+#define MAX_SPRITES 256
 
 namespace crown
 {
 
 typedef Id MeshId;
+typedef Id SpriteId;
+
 struct Camera;
 
 class RenderWorld
@@ -47,21 +54,33 @@ public:
 	RenderWorld();
 	~RenderWorld();
 
-	MeshId create_mesh(const char* mesh, int32_t node = -1, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
-	void destroy_mesh(MeshId id);
+	MeshId		create_mesh(ResourceId id, int32_t node = -1, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
+	void 		destroy_mesh(MeshId id);
+	Mesh* 		lookup_mesh(MeshId mesh);
+
+	SpriteId	create_sprite(const char* name, int32_t node = -1, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
+	void		destroy_sprite(SpriteId id);
+	Sprite*		lookup_sprite(SpriteId id);
 
-	Mesh* lookup_mesh(MeshId mesh);
+	MeshId 		allocate_mesh(MeshResource* mr, int32_t node, const Vector3& pos, const Quaternion& rot);
+	void 		deallocate_mesh(MeshId id);
 
-	void update(Camera& camera, float dt);
+	SpriteId	allocate_sprite(SpriteResource* sr, int32_t node, const Vector3& pos, const Quaternion& rot);
+	void 		deallocate_sprite(SpriteId id);
 
-	MeshId allocate_mesh(MeshResource* mr, int32_t node, const Vector3& pos, const Quaternion& rot);
-	void deallocate_mesh(MeshId id);
+	void		update(const Matrix4x4& view, const Matrix4x4& projection, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float dt);
 
 private:
 
-	IdTable<MAX_MESHES>		m_mesh_table;
-	uint32_t				m_sparse_to_packed[MAX_MESHES];
-	List<Mesh>				m_mesh;
+	PoolAllocator					m_mesh_pool;
+	IdArray<MAX_MESHES, Mesh*>		m_mesh;
+
+	// Mesh transforms
+	IdArray<MAX_MESHES, Matrix4x4>	m_transform;
+
+	IdTable<MAX_SPRITES>	m_sprite_table;
+	uint32_t				m_sprite_sparse_to_packed[MAX_SPRITES];
+	List<Sprite>			m_sprite;
 };
 
 } // namespace crown

+ 132 - 0
engine/Sprite.cpp

@@ -0,0 +1,132 @@
+/*
+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 "Sprite.h"
+#include "Vector3.h"
+#include "Quaternion.h"
+#include "SpriteResource.h"
+#include "Allocator.h"
+#include "SpriteAnimator.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+void Sprite::create(SpriteResource* sr, int32_t node, const Vector3& pos, const Quaternion& rot)
+{
+	m_vb = sr->m_vb;
+	m_ib = sr->m_ib;
+	m_texture = sr->m_texture;
+	m_vertex = sr->m_vertex;
+	m_fragment = sr->m_fragment;
+	m_program = sr->m_program;
+	m_uniform = sr->m_uniform;
+
+	set_local_position(pos);
+	set_local_rotation(rot);
+
+	m_node = node;
+
+	m_animator = CE_NEW(default_allocator(), SpriteAnimator)(sr);
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::destroy()
+{
+	if (m_animator)
+	{
+		CE_DELETE(default_allocator(), m_animator);
+	}
+}
+
+//-----------------------------------------------------------------------------
+Vector3 Sprite::local_position() const
+{
+	Vector3 tmp = m_local_pose.translation();
+
+	return tmp;
+}
+
+//-----------------------------------------------------------------------------
+Quaternion Sprite::local_rotation() const
+{
+	Quaternion tmp = m_local_pose.to_quat();
+
+	return tmp;
+}
+
+//-----------------------------------------------------------------------------
+Matrix4x4 Sprite::local_pose() const
+{
+	return m_local_pose;
+}
+
+//-----------------------------------------------------------------------------
+Vector3 Sprite::world_position() const
+{
+	Vector3 tmp = m_world_pose.translation();
+
+	return tmp;
+}
+
+//-----------------------------------------------------------------------------
+Quaternion Sprite::world_rotation() const
+{
+	Quaternion tmp = m_world_pose.to_quat();
+
+	return tmp;
+}
+
+//-----------------------------------------------------------------------------
+Matrix4x4 Sprite::world_pose() const
+{
+	return m_world_pose;	
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::set_local_position(const Vector3& pos)
+{
+	m_local_pose.set_translation(pos);
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::set_local_rotation(const Quaternion& rot)
+{
+	Matrix4x4& local_pose = m_local_pose;
+
+	Vector3 local_translation = local_pose.translation();
+	local_pose = rot.to_mat4();
+	local_pose.set_translation(local_translation);	
+}
+
+//-----------------------------------------------------------------------------
+void Sprite::set_local_pose(const Matrix4x4& pose)
+{
+	m_local_pose = pose;
+}
+
+
+} // namespace crown

+ 76 - 0
engine/Sprite.h

@@ -0,0 +1,76 @@
+/*
+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 "RendererTypes.h"
+#include "Matrix4x4.h"
+
+namespace crown
+{
+
+class SpriteResource;
+class SpriteAnimator;
+class Vector3;
+class Quaternion;
+
+//-----------------------------------------------------------------------------
+struct Sprite
+{
+	void				create(SpriteResource* sr, int32_t node, const Vector3& pos, const Quaternion& rot);
+	void				destroy();
+
+	Vector3				local_position() const;
+	Quaternion			local_rotation() const;
+	Matrix4x4			local_pose() const;
+
+	Vector3				world_position() const;
+	Quaternion			world_rotation() const;
+	Matrix4x4			world_pose() const;
+
+	void				set_local_position(const Vector3& pos);
+	void				set_local_rotation(const Quaternion& rot);
+	void				set_local_pose(const Matrix4x4& pose);
+
+public:
+	
+	int32_t				m_node;
+
+	Matrix4x4			m_local_pose;
+	Matrix4x4			m_world_pose;
+
+	VertexBufferId		m_vb;
+	IndexBufferId		m_ib;
+	TextureId			m_texture;
+	ShaderId			m_vertex;
+	ShaderId			m_fragment;
+	GPUProgramId		m_program;
+	UniformId			m_uniform;
+
+	SpriteAnimator*		m_animator;
+};
+
+} // namespace crown

+ 118 - 0
engine/SpriteAnimator.h

@@ -0,0 +1,118 @@
+/*
+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 <cstring>
+
+#include "Assert.h"
+#include "SpriteResource.h"
+#include "Device.h"
+#include "RendererTypes.h"
+#include "Renderer.h"
+#include "Random.h"
+#include "OS.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+class SpriteAnimator
+{
+public:
+	//-----------------------------------------------------------------------------
+	enum Enum
+	{
+		UNKNOWN = 0,
+		SEQUENTIAL_ONCE,
+		SEQUENTIAL_LOOP,
+		RANDOM_LOOP
+	};
+
+public:
+	//-----------------------------------------------------------------------------	
+	SpriteAnimator(SpriteResource* sr)
+		: m_vb(sr->m_vb)
+		, m_anim_length(sr->length())
+		, m_frame_rate(sr->frame_rate())
+		, m_playback_mode((Enum)sr->playback_mode())
+		, m_cur_frame(0)
+		, m_random(os::microseconds())
+	{
+		memcpy(m_vertices, sr->animation(), sizeof(float) * 16 * m_anim_length);
+	}
+
+	//-----------------------------------------------------------------------------
+	void play_frame()
+	{
+		CE_ASSERT(m_playback_mode != UNKNOWN, "Playback mode must be != UNKNOWN (%d)", m_playback_mode);
+
+		update_frame();
+
+		device()->renderer()->update_vertex_buffer(m_vb, 0, 4, m_vertices + 16 * m_cur_frame);
+	}
+
+	//-----------------------------------------------------------------------------
+	void update_frame()
+	{
+		switch (m_playback_mode)
+		{
+			case SEQUENTIAL_ONCE:
+			{
+				m_cur_frame = ++m_cur_frame < m_anim_length ? m_cur_frame : m_anim_length - 1;
+				break;
+			}
+			case SEQUENTIAL_LOOP:
+			{
+				m_cur_frame = ++m_cur_frame < m_anim_length ? m_cur_frame : 0;
+				break;
+			}
+			case RANDOM_LOOP:
+			{
+				m_cur_frame = m_random.integer(m_anim_length);
+				break;
+			}
+			default:
+			{
+				CE_ASSERT(false, "Ops! Wrong playback mode!");
+			}
+		}
+	}
+
+public:
+
+	VertexBufferId	m_vb;
+	float			m_vertices[MAX_SPRITE_ANIM_FRAMES*SPRITE_VERTEX_FRAME_SIZE];
+
+	uint32_t		m_anim_length;
+	uint32_t		m_frame_rate;
+	Enum			m_playback_mode;
+	uint32_t		m_cur_frame;
+
+	Random 			m_random;
+};
+
+} // namespace crown 

+ 63 - 5
engine/Unit.cpp

@@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "World.h"
 #include "Allocator.h"
 #include "Log.h"
+#include "UnitResource.h"
 
 namespace crown
 {
@@ -43,10 +44,39 @@ Unit::Unit()
 }
 
 //-----------------------------------------------------------------------------
-void Unit::create(World& world, UnitId id, const Vector3& pos, const Quaternion& rot)
+void Unit::create(World& world, UnitResource* ur, UnitId id, const Vector3& pos, const Quaternion& rot)
 {
 	m_root_node = m_scene_graph.create_node(-1, pos, rot);
+
+	// Create renderables
+	for (uint32_t i = 0; i < ur->num_renderables(); i++)
+	{
+		int32_t node = m_scene_graph.create_node(m_root_node, Vector3::ZERO, Quaternion::IDENTITY);
+
+		UnitRenderable renderable = ur->get_renderable(i);
+		MeshId mesh = world.create_mesh(renderable.resource, node, Vector3::ZERO, Quaternion::IDENTITY);
+
+		add_mesh(renderable.name, mesh);
+	}
+
+	// Create cameras
+	for (uint32_t i = 0; i < ur->num_cameras(); i++)
+	{
+		int32_t cam_node = m_scene_graph.create_node(m_root_node, Vector3::ZERO, Quaternion::IDENTITY);
+
+		UnitCamera camera = ur->get_camera(i);
+		CameraId cam = world.create_camera(cam_node, Vector3::ZERO, Quaternion::IDENTITY);
+		
+		world.link_camera(cam, id, m_root_node);
+		add_camera(camera.name, cam);
+	}
+
+	// FIXME FIXME FIXME - TEST CODE - FIXME FIXME FIXME
+	SpriteId sprite = world.create_sprite("sprites/loading", m_root_node, Vector3::ZERO, Quaternion::IDENTITY);
+	add_sprite(hash::murmur2_32("sprite", 6, 0), sprite);
+
 	m_world = &world;
+	m_resource = ur;
 	m_id = id;
 }
 
@@ -122,10 +152,10 @@ void Unit::unlink_node(int32_t child)
 }
 
 //-----------------------------------------------------------------------------
-void Unit::add_component(const char* name, Id component, uint32_t& size, Component* array)
+void Unit::add_component(uint32_t name, Id component, uint32_t& size, Component* array)
 {
 	Component comp;
-	comp.name = hash::murmur2_32(name, string::strlen(name), 0);
+	comp.name = name;
 	comp.component = component;
 
 	array[size] = comp;
@@ -166,7 +196,7 @@ Id Unit::find_component(uint32_t index, uint32_t size, Component* array)
 }
 
 //-----------------------------------------------------------------------------
-void Unit::add_camera(const char* name, CameraId camera)
+void Unit::add_camera(uint32_t name, CameraId camera)
 {
 	CE_ASSERT(m_num_cameras < MAX_CAMERA_COMPONENTS, "Max camera number reached");
 
@@ -174,13 +204,21 @@ void Unit::add_camera(const char* name, CameraId camera)
 }
 
 //-----------------------------------------------------------------------------
-void Unit::add_mesh(const char* name, MeshId mesh)
+void Unit::add_mesh(uint32_t name, MeshId mesh)
 {
 	CE_ASSERT(m_num_meshes < MAX_MESH_COMPONENTS, "Max mesh number reached");
 
 	add_component(name, mesh, m_num_meshes, m_meshes);
 }
 
+//-----------------------------------------------------------------------------
+void Unit::add_sprite(uint32_t name, SpriteId sprite)
+{
+	CE_ASSERT(m_num_sprites < MAX_SPRITE_COMPONENTS, "Max sprite number reached");
+
+	add_component(name, sprite, m_num_sprites, m_sprites);
+}
+
 //-----------------------------------------------------------------------------
 Camera* Unit::camera(const char* name)
 {
@@ -221,4 +259,24 @@ Mesh* Unit::mesh(uint32_t i)
 	return m_world->lookup_mesh(mesh);
 }
 
+//-----------------------------------------------------------------------------
+Sprite*	Unit::sprite(const char* name)
+{
+	SpriteId sprite = find_component(name, m_num_sprites, m_sprites);
+
+	CE_ASSERT(sprite.id != INVALID_ID, "Unit does not have sprite with name '%s'", name);
+
+	return m_world->lookup_sprite(sprite);
+}
+
+//-----------------------------------------------------------------------------
+Sprite*	Unit::sprite(uint32_t i)
+{
+	SpriteId sprite = find_component(i, m_num_sprites, m_sprites);
+
+	CE_ASSERT(sprite.id != INVALID_ID, "Unit does not have sprite with index '%d'", i);
+
+	return m_world->lookup_sprite(sprite);
+}
+
 } // namespace crown

+ 31 - 4
engine/Unit.h

@@ -38,6 +38,21 @@ namespace crown
 {
 
 typedef Id CameraId;
+typedef	Id ComponentId;
+typedef Id UnitId;
+
+//-----------------------------------------------------------------------------
+struct ComponentType
+{
+	enum Enum
+	{
+		UNKNOWN,
+		CAMERA,
+		MESH,
+		SPRITE,
+		SOUND
+	};
+};
 
 struct Component
 {
@@ -47,18 +62,22 @@ struct Component
 
 typedef Id UnitId;
 typedef Id MeshId;
+typedef Id SpriteId;
 
 class Camera;
 class Mesh;
+class Sprite;
 class World;
+struct UnitResource;
 
 #define MAX_CAMERA_COMPONENTS 8
 #define MAX_MESH_COMPONENTS 8
+#define MAX_SPRITE_COMPONENTS 8
 
 struct Unit
 {
 					Unit();
-	void			create(World& world, UnitId id, const Vector3& pos, const Quaternion& rot);
+	void			create(World& world, UnitResource* ur, UnitId id, const Vector3& pos, const Quaternion& rot);
 	void			destroy();
 
 	Vector3			local_position(int32_t node = 0) const;
@@ -76,12 +95,13 @@ struct Unit
 	void			link_node(int32_t child, int32_t parent);
 	void			unlink_node(int32_t child);
 
-	void			add_component(const char* name, Id component, uint32_t& size, Component* array);
+	void			add_component(uint32_t name, Id component, uint32_t& size, Component* array);
 	Id				find_component(const char* name, uint32_t size, Component* array);
 	Id				find_component(uint32_t index, uint32_t size, Component* array);
 
-	void			add_camera(const char* name, CameraId camera);
-	void			add_mesh(const char* name, MeshId mesh);
+	void			add_camera(uint32_t name, CameraId camera);
+	void			add_mesh(uint32_t name, MeshId mesh);
+	void			add_sprite(uint32_t name, SpriteId sprite);
 
 	Camera*			camera(const char* name);
 	Camera*			camera(uint32_t i);
@@ -89,9 +109,13 @@ struct Unit
 	Mesh*			mesh(const char* name);
 	Mesh*			mesh(uint32_t i);
 
+	Sprite*			sprite(const char* name);
+	Sprite*			sprite(uint32_t i);
+
 public:
 
 	World*			m_world;
+	UnitResource*	m_resource;
 	UnitId			m_id;
 
 	int32_t			m_root_node;
@@ -102,6 +126,9 @@ public:
 
 	uint32_t		m_num_meshes;
 	Component		m_meshes[MAX_MESH_COMPONENTS];
+
+	uint32_t		m_num_sprites;
+	Component		m_sprites[MAX_SPRITE_COMPONENTS];
 };
 
 } // namespace crown

+ 169 - 83
engine/World.cpp

@@ -37,80 +37,109 @@ namespace crown
 
 //-----------------------------------------------------------------------------
 World::World()
-	: m_allocator(default_allocator(), 1024 * 1024)
-	, m_is_init(false)
+	: m_unit_pool(default_allocator(), MAX_UNITS, sizeof(Unit))
 	, m_units(default_allocator())
 	, m_camera(default_allocator())
+	, m_sounds(default_allocator())
+	, m_unit_to_camera(default_allocator())
+	, m_unit_to_sound_instance(default_allocator())
 {
 }
 
 //-----------------------------------------------------------------------------
-void World::init()
+UnitId World::spawn_unit(const char* name, const Vector3& pos, const Quaternion& rot)
 {
+	// Allocate memory for unit
+	Unit* unit = CE_NEW(m_unit_pool, Unit)();
+
+	// Fetch resource
+	UnitResource* ur = (UnitResource*) device()->resource_manager()->lookup(UNIT_EXTENSION, name);
+
+	// Create Id for the unit
+	const UnitId unit_id = m_units.create(unit);
+	unit->create(*this, ur, unit_id, pos, rot);
+
+	return unit_id;
 }
 
 //-----------------------------------------------------------------------------
-void World::shutdown()
+void World::destroy_unit(UnitId unit)
 {
+	CE_ASSERT(m_units.has(unit), "Unit does not exist");
 }
 
 //-----------------------------------------------------------------------------
-UnitId World::spawn_unit(const char* /*name*/, const Vector3& pos, const Quaternion& rot)
+void World::destroy_unit(Unit* unit)
 {
-	const UnitId unit_id = m_unit_table.create();
-
-	Unit unit;
-	unit.create(*this, m_scene_graph[unit_id.index], m_component[unit_id.index], unit_id, pos, rot);
-
-	// Test stuff
-	int32_t cam_node = unit.m_scene_graph->create_node(unit.m_root_node, pos, rot);
-	CameraId camera = create_camera(unit_id, cam_node);
-
-	MeshId mesh = m_render_world.create_mesh("monkey");
+	CE_ASSERT_NOT_NULL(unit);
+	CE_DELETE(m_unit_pool, unit);
+}
 
-	unit.m_component->add_component("camera", ComponentType::CAMERA, camera);
-	unit.m_component->add_component("mesh", ComponentType::MESH, mesh);
+//-----------------------------------------------------------------------------
+void World::link_unit(UnitId child, UnitId parent, int32_t node)
+{
+	CE_ASSERT(m_units.has(child), "Child unit does not exist");
+	CE_ASSERT(m_units.has(parent), "Parent unit does not exist");
 
-	m_units.push_back(unit);
+	Unit* child_unit = lookup_unit(child);
+	Unit* parent_unit = lookup_unit(parent);
 
-	return unit_id;
+	parent_unit->link_node(child_unit->m_root_node, node);
 }
 
 //-----------------------------------------------------------------------------
-void World::kill_unit(UnitId unit)
+void World::unlink_unit(UnitId child)
 {
-	CE_ASSERT(m_unit_table.has(unit), "Unit does not exist");
-	(void)unit;
+	CE_ASSERT(m_units.has(child), "Child unit does not exist");
 }
 
 //-----------------------------------------------------------------------------
-void World::link_unit(UnitId child, UnitId parent)
+void World::link_camera(CameraId camera, UnitId unit, int32_t node)
 {
-	CE_ASSERT(m_unit_table.has(child), "Child unit does not exist");
-	CE_ASSERT(m_unit_table.has(parent), "Parent unit does not exist");
+	UnitToCamera* utc = NULL;
+
+	for (uint32_t i = 0; i < m_unit_to_camera.size(); i++)
+	{
+		if (utc->camera == camera && utc->unit == unit)
+		{
+			utc = &m_unit_to_camera[i];
+		}
+	}
+
+	if (utc != NULL)
+	{
+		utc->node = node;
+	}
+	else
+	{
+		UnitToCamera new_utc;
+		new_utc.camera = camera;
+		new_utc.unit = unit;
+		new_utc.node = node;
+		m_unit_to_camera.push_back(new_utc);
+	}
 }
 
 //-----------------------------------------------------------------------------
-void World::unlink_unit(UnitId child, UnitId parent)
+void World::unlink_camera(CameraId camera)
 {
-	CE_ASSERT(m_unit_table.has(child), "Child unit does not exist");
-	CE_ASSERT(m_unit_table.has(parent), "Parent unit does not exist");
+	(void)camera;
 }
 
 //-----------------------------------------------------------------------------
 Unit* World::lookup_unit(UnitId unit)
 {
-	CE_ASSERT(m_unit_table.has(unit), "Unit does not exist");
+	CE_ASSERT(m_units.has(unit), "Unit does not exist");
 
-	return &m_units[unit.index];
+	return m_units.lookup(unit);
 }
 
 //-----------------------------------------------------------------------------
 Camera* World::lookup_camera(CameraId camera)
 {
-	CE_ASSERT(m_camera_table.has(camera), "Camera does not exist");
+	CE_ASSERT(m_camera.has(camera), "Camera does not exist");
 
-	return &m_camera[camera.index];
+	return &m_camera.lookup(camera);
 }
 
 //-----------------------------------------------------------------------------
@@ -119,39 +148,68 @@ Mesh* World::lookup_mesh(MeshId mesh)
 	return m_render_world.lookup_mesh(mesh);
 }
 
+//-----------------------------------------------------------------------------
+Sprite* World::lookup_sprite(SpriteId sprite)
+{
+	return m_render_world.lookup_sprite(sprite);
+}
+
 //-----------------------------------------------------------------------------
 void World::update(Camera& camera, float dt)
 {
-	// Feed the scene graph with camera local pose
-	for (uint cc = 0; cc < m_camera.size(); cc++)
+	// Update all the units
+	for (uint32_t uu = 0; uu < m_units.m_objects.size(); uu++)
 	{
-		Camera& cam = m_camera[cc];
-		SceneGraph& graph = m_scene_graph[cam.m_unit.index];
+		Unit& unit = *m_units.m_objects[uu];
+		SceneGraph& graph = unit.m_scene_graph;
 
-		graph.set_local_pose(cam.m_node, cam.m_local_pose);
+		// Update unit's scene graph
+		graph.update();
 	}
 
-	// Update all the units
-	for (uint32_t uu = 0; uu < m_units.size(); uu++)
+	// Update camera poses
+	for (uint32_t i = 0; i < m_unit_to_camera.size(); i++)
 	{
-		Unit& unit = m_units[uu];
-		SceneGraph& graph = m_scene_graph[unit.m_id.index];
+		const UnitToCamera& utc = m_unit_to_camera[i];
 
-		// Update unit's scene graph
-		graph.update();
+		Camera& cam = m_camera.lookup(utc.camera);
+		Unit* unit = m_units.lookup(utc.unit);
+
+		cam.m_world_pose = unit->m_scene_graph.world_pose(utc.node);
 	}
 
-	// Fetch the camera world poses from scene graph
-	for (uint32_t cc = 0; cc < m_camera.size(); cc++)
+	// Updates sound poses
+	for (uint32_t i = 0; i < m_unit_to_sound_instance.size(); i++)
 	{
-		Camera& cam = m_camera[cc];
-		SceneGraph& graph = m_scene_graph[cam.m_unit.index];
+		const UnitToSoundInstance& uts = m_unit_to_sound_instance[i];
 
-		cam.m_world_pose = graph.world_pose(cam.m_node);
+		SoundInstance& sound = m_sounds.lookup(uts.sound);
+		Unit* unit = m_units.lookup(uts.unit);
+
+		sound.world = unit->m_scene_graph.world_pose(uts.node);
 	}
 
 	// Update render world
-	m_render_world.update(camera, dt);
+	m_render_world.update(camera.m_world_pose, camera.m_projection, camera.m_view_x, camera.m_view_y,
+							camera.m_view_width, camera.m_view_height, dt);
+
+	// Update sounds
+	List<SoundInstance>& sounds = m_sounds.m_objects; 
+	for (uint32_t i = 0; i < sounds.size(); i++)
+	{
+		SoundInstance& sound = sounds[i];
+
+		device()->sound_renderer()->set_sound_loop(sound.sound, sound.loop);
+		device()->sound_renderer()->set_sound_gain(sound.sound, sound.volume);
+		device()->sound_renderer()->set_sound_max_distance(sound.sound, sound.range);
+		device()->sound_renderer()->set_sound_position(sound.sound, sound.world.translation());
+
+		if (!sound.playing)
+		{
+			device()->sound_renderer()->play_sound(sound.sound);
+			sound.playing = true;
+		}
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -161,59 +219,84 @@ RenderWorld& World::render_world()
 }
 
 //-----------------------------------------------------------------------------
-CameraId World::create_camera(UnitId unit, int32_t node, const Vector3& pos, const Quaternion& rot)
+CameraId World::create_camera(int32_t node, const Vector3& pos, const Quaternion& rot)
 {
-	CameraId camera_id = m_camera_table.create();
-
 	Camera camera;
-	camera.create(unit, node, pos, rot);
+	camera.create(node, pos, rot);
 
-	m_camera.push_back(camera);
-
-	return camera_id;
+	return m_camera.create(camera);
 }
 
 //-----------------------------------------------------------------------------
 void World::destroy_camera(CameraId camera)
 {
-	m_camera_table.destroy(camera);
+	m_camera.destroy(camera);
 }
 
 //-----------------------------------------------------------------------------
-SoundInstanceId World::play_sound(const char* name, const bool loop, const float volume, const Vector3& pos, const float range)
+MeshId World::create_mesh(ResourceId id, int32_t node, const Vector3& pos, const Quaternion& rot)
 {
-	SoundInstanceId id = m_sound_table.create();
+	return m_render_world.create_mesh(id, node, pos, rot);
+}
 
-	SoundResource* sound = (SoundResource*)device()->resource_manager()->lookup(SOUND_EXTENSION, name);
+//-----------------------------------------------------------------------------
+void World::destroy_mesh(MeshId id)
+{
+	m_render_world.destroy_mesh(id);
+}
 
-	m_sound[id.index].m_sound = sound->m_id;
+//-----------------------------------------------------------------------------
+SpriteId World::create_sprite(const char* name, int32_t node, const Vector3& pos, const Quaternion& rot)
+{
+	return m_render_world.create_sprite(name, node, pos, rot);
+}
+
+//-----------------------------------------------------------------------------
+void World::destroy_sprite(SpriteId id)
+{
+	m_render_world.destroy_sprite(id);
+}
 
-	device()->sound_renderer()->set_sound_loop(m_sound[id.index].m_sound, loop);
-	device()->sound_renderer()->set_sound_gain(m_sound[id.index].m_sound, volume);
-	device()->sound_renderer()->set_sound_position(m_sound[id.index].m_sound, pos);
-	device()->sound_renderer()->set_sound_max_distance(m_sound[id.index].m_sound, range);
 
-	device()->sound_renderer()->play_sound(m_sound[id.index].m_sound);
+//-----------------------------------------------------------------------------
+SoundInstanceId World::play_sound(const char* name, const bool loop, const float volume, const Vector3& pos, const float range)
+{
+	SoundResource* sound = (SoundResource*)device()->resource_manager()->lookup(SOUND_EXTENSION, name);
+
+	SoundInstance s;
+	s.sound = sound->m_id;
+	s.world = Matrix4x4(Quaternion::IDENTITY, pos);
+	s.volume = volume;
+	s.range = range;
+	s.loop = loop;
+	s.playing = false;
+
+	SoundInstanceId id = m_sounds.create(s);
 
 	return id;
 }
 
 //-----------------------------------------------------------------------------
-void World::pause_sound(SoundInstanceId sound)
+void World::pause_sound(SoundInstanceId id)
 {
-	CE_ASSERT(m_sound_table.has(sound), "SoundInstance does not exists");
+	CE_ASSERT(m_sounds.has(id), "SoundInstance does not exists");
 
-	device()->sound_renderer()->pause_sound(m_sound[sound.index].m_sound);
+	const SoundInstance& sound = m_sounds.lookup(id);
+	device()->sound_renderer()->pause_sound(sound.sound);
 }
 
 //-----------------------------------------------------------------------------
-void World::link_sound(SoundInstanceId sound, UnitId unit)
+void World::link_sound(SoundInstanceId id, Unit* unit, int32_t node)
 {
-	CE_ASSERT(m_unit_table.has(unit), "Unit does not exists");
-	CE_ASSERT(m_sound_table.has(sound), "SoundInstance does not exists");
+	//CE_ASSERT(m_units.has(unit), "Unit does not exists");
+	CE_ASSERT(m_sounds.has(id), "SoundInstance does not exists");
+
+	UnitToSoundInstance uts;
+	uts.sound = id;
+	uts.unit = unit->m_id;
+	uts.node = node;
 
-	Vector3 pos = m_units[unit.index].world_position();
-	device()->sound_renderer()->set_sound_position(m_sound[sound.index].m_sound, pos);
+	m_unit_to_sound_instance.push_back(uts);
 }
 
 //-----------------------------------------------------------------------------
@@ -223,27 +306,30 @@ void World::set_listener(const Vector3& pos, const Vector3& vel, const Vector3&
 }
 
 //-----------------------------------------------------------------------------
-void World::set_sound_position(SoundInstanceId sound, const Vector3& pos)
+void World::set_sound_position(SoundInstanceId id, const Vector3& pos)
 {
-	CE_ASSERT(m_sound_table.has(sound), "SoundInstance does not exists");
+	CE_ASSERT(m_sounds.has(id), "SoundInstance does not exists");
 
-	device()->sound_renderer()->set_sound_position(m_sound[sound.index].m_sound, pos);
+	SoundInstance& sound = m_sounds.lookup(id);
+	sound.world = Matrix4x4(Quaternion::IDENTITY, pos);
 }
 
 //-----------------------------------------------------------------------------
-void World::set_sound_range(SoundInstanceId sound, const float range)
+void World::set_sound_range(SoundInstanceId id, const float range)
 {
-	CE_ASSERT(m_sound_table.has(sound), "SoundInstance does not exists");
+	CE_ASSERT(m_sounds.has(id), "SoundInstance does not exists");
 
-	device()->sound_renderer()->set_sound_max_distance(m_sound[sound.index].m_sound, range);
+	SoundInstance& sound = m_sounds.lookup(id);
+	sound.range = range;
 }
 
 //-----------------------------------------------------------------------------
-void World::set_sound_volume(SoundInstanceId sound, const float vol)
+void World::set_sound_volume(SoundInstanceId id, const float vol)
 {
-	CE_ASSERT(m_sound_table.has(sound), "SoundInstance does not exists");
+	CE_ASSERT(m_sounds.has(id), "SoundInstance does not exists");
 
-	device()->sound_renderer()->set_sound_gain(m_sound[sound.index].m_sound, vol);
+	SoundInstance& sound = m_sounds.lookup(id);
+	sound.volume = vol;
 }
 
 } // namespace crown

+ 48 - 23
engine/World.h

@@ -28,6 +28,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "HeapAllocator.h"
 #include "IdTable.h"
+#include "IdArray.h"
 #include "LinearAllocator.h"
 #include "Unit.h"
 #include "Camera.h"
@@ -35,6 +36,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "LinearAllocator.h"
 #include "RenderWorld.h"
 #include "SoundRenderer.h"
+#include "PoolAllocator.h"
 
 namespace crown
 {
@@ -50,10 +52,30 @@ typedef Id SoundInstanceId;
 
 struct SoundInstance
 {
-	SoundId m_sound;
+	SoundId sound;
+	Matrix4x4 world;
+	float volume;
+	float range;
+	bool loop : 1;
+	bool playing : 1;
+};
+
+struct UnitToCamera
+{
+	UnitId unit;
+	int32_t node;
+	CameraId camera;
+};
+
+struct UnitToSoundInstance
+{
+	UnitId unit;
+	SoundInstanceId sound;
+	int32_t node;
 };
 
 class Mesh;
+class Sprite;
 class Vector3;
 class Quaternion;
 
@@ -62,51 +84,54 @@ class World
 public:
 							World();
 
-	void					init();
-	void					shutdown();
-
 	UnitId					spawn_unit(const char* name, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion(Vector3(0, 1, 0), 0.0f));
-	void					kill_unit(UnitId unit);
+	void					destroy_unit(UnitId unit);
+	void					destroy_unit(Unit* unit);
 
-	void					link_unit(UnitId child, UnitId parent);
-	void					unlink_unit(UnitId child, UnitId parent);
+	void					link_unit(UnitId child, UnitId parent, int32_t node);
+	void					unlink_unit(UnitId unit);
+
+	void					link_camera(CameraId camera, UnitId unit, int32_t node);
+	void					unlink_camera(CameraId camera);
 
 	Unit*					lookup_unit(UnitId unit);
 	Camera*					lookup_camera(CameraId camera);
 	Mesh*					lookup_mesh(MeshId mesh);
+	Sprite*					lookup_sprite(SpriteId sprite);
 
 	RenderWorld&			render_world();
 	void					update(Camera& camera, float dt);
 
-	CameraId				create_camera(UnitId unit, int32_t node, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
+	CameraId				create_camera(int32_t node, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
 	void					destroy_camera(CameraId camera);
 
+	MeshId					create_mesh(ResourceId id, int32_t node, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
+	void					destroy_mesh(MeshId id);
+
+	SpriteId				create_sprite(const char* name, int32_t node = -1, const Vector3& pos = Vector3::ZERO, const Quaternion& rot = Quaternion::IDENTITY);
+	void					destroy_sprite(SpriteId id);
+
 	SoundInstanceId			play_sound(const char* name, const bool loop = false, const float volume = 1.0f, const Vector3& pos = Vector3::ZERO, const float range = 50.0f);
 	void					pause_sound(SoundInstanceId sound);
-	void 					link_sound(SoundInstanceId sound, UnitId unit);
+	void 					link_sound(SoundInstanceId sound, Unit* unit, int32_t node);
 	void					set_listener(const Vector3& pos, const Vector3& vel, const Vector3& or_up, const Vector3& or_at);
 	void					set_sound_position(SoundInstanceId sound, const Vector3& pos);
 	void					set_sound_range(SoundInstanceId sound, const float range);
 	void					set_sound_volume(SoundInstanceId sound, const float vol);
-	
-private:
-
-	LinearAllocator			m_allocator;
-	bool					m_is_init : 1;
 
-	SceneGraph				m_scene_graph[MAX_UNITS];
-	ComponentList			m_component[MAX_UNITS];
+private:
 
-	IdTable<MAX_UNITS> 		m_unit_table;
-	List<Unit>				m_units;
+	PoolAllocator						m_unit_pool;
 
-	IdTable<MAX_CAMERAS>	m_camera_table;
-	List<Camera>			m_camera;
+	IdArray<MAX_UNITS, Unit*>			m_units;
+	IdArray<MAX_CAMERAS, Camera>		m_camera;
+	IdArray<MAX_SOUNDS, SoundInstance> 	m_sounds;
 
-	IdTable<MAX_SOUNDS> 	m_sound_table;
-	SoundInstance			m_sound[MAX_SOUNDS];
+	// Connections
+	List<UnitToCamera>					m_unit_to_camera;
+	List<UnitToSoundInstance>			m_unit_to_sound_instance;
 
-	RenderWorld				m_render_world;
+	RenderWorld							m_render_world;
 };
 
 } // namespace crown

+ 4 - 0
engine/compilers/BundleCompiler.cpp

@@ -124,6 +124,10 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 		{
 			result = m_sound.compile(source_dir, bundle_dir, filename, out_name);
 		}
+		else if(resource_type_hash == SPRITE_TYPE)
+		{
+			result = m_sprite.compile(source_dir, bundle_dir, filename, out_name);
+		}
 		else if (resource_type_hash == PACKAGE_TYPE)
 		{
 			result = m_package.compile(source_dir, bundle_dir, filename, out_name);

+ 2 - 0
engine/compilers/BundleCompiler.h

@@ -30,6 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "TextureCompiler.h"
 #include "LuaCompiler.h"
 #include "SoundCompiler.h"
+#include "SpriteCompiler.h"
 #include "PackageCompiler.h"
 #include "DynamicString.h"
 #include "Vector.h"
@@ -60,6 +61,7 @@ private:
 	TextureCompiler	m_texture;
 	LuaCompiler 	m_lua;
 	SoundCompiler	m_sound;
+	SpriteCompiler	m_sprite;
 	PackageCompiler m_package;
 	UnitCompiler	m_unit;
 };

+ 35 - 7
engine/compilers/package/PackageCompiler.cpp

@@ -39,15 +39,12 @@ namespace crown
 
 //-----------------------------------------------------------------------------
 PackageCompiler::PackageCompiler()
-	: m_has_texture(false)
-	, m_has_lua(false)
-	, m_has_sound(false)
-	, m_has_unit(false)
-	, m_texture(default_allocator())
+	: m_texture(default_allocator())
 	, m_script(default_allocator())
 	, m_sound(default_allocator())
 	, m_mesh(default_allocator())
 	, m_unit(default_allocator())
+	, m_sprite(default_allocator())
 {
 }
 
@@ -180,7 +177,6 @@ size_t PackageCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 			if (!fs.is_file(unit_name.c_str()))
 			{
 				Log::e("Unit '%s' does not exist.", unit_name.c_str());
-				return 0;
 			}
 
 			ResourceId id;
@@ -189,13 +185,38 @@ size_t PackageCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 		}
 	}
 
+	// Check for meshes
+	if (root.has_key("sprite"))
+	{
+		JSONElement sprite_array = root.key("sprite");
+		uint32_t sprite_array_size = sprite_array.size();
+
+		for (uint32_t i = 0; i < sprite_array_size; i++)
+		{
+			TempAllocator256 alloc;
+			DynamicString sprite_name(alloc);
+			sprite_name += sprite_array[i].string_value();
+			sprite_name += ".sprite";
+
+			if (!fs.is_file(sprite_name.c_str()))
+			{
+				Log::e("Sprite '%s' does not exist.", sprite_name.c_str());
+				return 0;
+			}
+
+			ResourceId id;
+			id.id = hash::murmur2_64(sprite_name.c_str(), string::strlen(sprite_name.c_str()), 0);
+			m_sprite.push_back(id);
+		}
+	}
 
 	return sizeof(PackageHeader) +
 			m_texture.size() * sizeof(ResourceId) +
 			m_script.size() * sizeof(ResourceId) +
 			m_sound.size() * sizeof(ResourceId) +
 			m_mesh.size() * sizeof(ResourceId) +
-			m_unit.size() * sizeof(ResourceId);
+			m_unit.size() * sizeof(ResourceId) +
+			m_sprite.size() * sizeof(ResourceId);
 }
 
 //-----------------------------------------------------------------------------
@@ -207,12 +228,14 @@ void PackageCompiler::write_impl(File* out_file)
 	header.num_sounds = m_sound.size();
 	header.num_meshes = m_mesh.size();
 	header.num_units = m_unit.size();
+	header.num_sprites = m_sprite.size();
 
 	header.textures_offset = sizeof(PackageHeader);
 	header.scripts_offset  = header.textures_offset + sizeof(ResourceId) * header.num_textures;
 	header.sounds_offset = header.scripts_offset + sizeof(ResourceId) * header.num_scripts;
 	header.meshes_offset = header.sounds_offset + sizeof(ResourceId) * header.num_sounds;
 	header.units_offset = header.meshes_offset + sizeof(ResourceId) * header.num_meshes;
+	header.sprites_offset = header.units_offset + sizeof(ResourceId) * header.num_units;
 
 	out_file->write((char*) &header, sizeof(PackageHeader));
 
@@ -236,6 +259,10 @@ void PackageCompiler::write_impl(File* out_file)
 	{
 		out_file->write((char*) m_unit.begin(), sizeof(ResourceId) * header.num_units);	
 	}
+	if (m_sprite.size() > 0)
+	{
+		out_file->write((char*) m_sprite.begin(), sizeof(ResourceId) * header.num_sprites);
+	}
 
 	// Cleanup
 	m_texture.clear();
@@ -243,6 +270,7 @@ void PackageCompiler::write_impl(File* out_file)
 	m_sound.clear();
 	m_mesh.clear();
 	m_unit.clear();
+	m_sprite.clear();
 }
 
 } // namespace crown

+ 1 - 6
engine/compilers/package/PackageCompiler.h

@@ -44,17 +44,12 @@ public:
 
 private:
 
-	bool m_has_texture;
-	bool m_has_lua;
-	bool m_has_sound;
-	bool m_has_mesh;
-	bool m_has_unit;
-
 	List<ResourceId> m_texture;
 	List<ResourceId> m_script;
 	List<ResourceId> m_sound;
 	List<ResourceId> m_mesh;
 	List<ResourceId> m_unit;
+	List<ResourceId> m_sprite;
 };
 
 } // namespace crown

+ 116 - 0
engine/compilers/sprite/SpriteCompiler.cpp

@@ -0,0 +1,116 @@
+/*
+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 <cstring>
+
+#include "Allocator.h"
+#include "Filesystem.h"
+#include "StringUtils.h"
+#include "SpriteCompiler.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+SpriteCompiler::SpriteCompiler()
+	: m_anim_data(default_allocator())
+{
+}
+
+//-----------------------------------------------------------------------------
+SpriteCompiler::~SpriteCompiler()
+{
+}
+
+//-----------------------------------------------------------------------------
+size_t SpriteCompiler::compile_impl(Filesystem& fs, const char* resource_path)
+{
+	File* file = fs.open(resource_path, FOM_READ);
+	char* buf = (char*)default_allocator().allocate(file->size());
+	file->read(buf, file->size());
+
+	JSONParser json(buf);
+	JSONElement root = json.root();
+
+	JSONElement anim_name = root.key("name");
+	string::strncpy(m_anim_header.name, anim_name.string_value(), string::strlen(anim_name.string_value()) + 1);
+
+	JSONElement anim_texture = root.key("texture");
+	string::strncpy(m_anim_header.texture, anim_texture.string_value(), string::strlen(anim_texture.string_value()) + 1);
+
+	JSONElement anim_length = root.key("length");
+	m_anim_header.length = anim_length.int_value();
+
+	JSONElement anim_frame_rate = root.key("frame_rate");
+	m_anim_header.frame_rate = anim_frame_rate.int_value();
+
+	JSONElement anim_playback_mode = root.key("playback_mode");
+	m_anim_header.playback_mode = anim_playback_mode.int_value();
+
+	Log::i("Playback mode: %d", m_anim_header.playback_mode);
+
+	List<float> t_positions(default_allocator());
+	JSONElement anim_vertices = root.key("positions");
+	anim_vertices.array_value(t_positions);
+
+	List<float> t_texcoords(default_allocator());
+	JSONElement anim_texcoords = root.key("texcoords");
+	anim_texcoords.array_value(t_texcoords);
+
+	for (uint32_t i = 0; i < t_texcoords.size(); i+=8)
+	{
+		for (uint32_t j = 0; j < t_positions.size(); j+=2)
+		{
+			SpriteAnimationData t_animation_data;
+
+			t_animation_data.position.x = t_positions[j];
+			t_animation_data.position.y = t_positions[j+1];
+
+			t_animation_data.texcoords.x = t_texcoords[j+i];
+			t_animation_data.texcoords.y = t_texcoords[j+i+1];
+
+			m_anim_data.push_back(t_animation_data);
+		}
+	}
+
+	fs.close(file);
+
+	return sizeof(SpriteHeader) + sizeof(SpriteAnimationData) * m_anim_data.size();
+}
+
+//-----------------------------------------------------------------------------
+void SpriteCompiler::write_impl(File* out_file)
+{
+	out_file->write((char*)&m_anim_header, sizeof(SpriteHeader));
+
+	for (uint32_t j = 0; j < m_anim_data.size(); j++)
+	{
+		out_file->write((char*)&m_anim_data[j], sizeof(SpriteAnimationData));
+	}
+}
+
+
+} // namespace crown

+ 75 - 0
engine/compilers/sprite/SpriteCompiler.h

@@ -0,0 +1,75 @@
+/*
+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 "Types.h"
+#include "List.h"
+#include "SpriteResource.h"
+#include "Compiler.h"
+#include "OS.h"
+#include "Vector2.h"
+
+
+namespace crown
+{
+
+class Filesystem;
+
+//-----------------------------------------------------------------------------
+struct SpriteHeader
+{
+	char name[128];
+	char texture[128];
+	uint32_t length;
+	uint32_t frame_rate;
+	uint32_t playback_mode;
+};
+
+//-----------------------------------------------------------------------------
+struct SpriteAnimationData
+{
+	Vector2 position;
+	Vector2 texcoords;
+};
+
+//-----------------------------------------------------------------------------
+class SpriteCompiler : public Compiler
+{
+public:
+							SpriteCompiler();
+							~SpriteCompiler();
+
+	size_t					compile_impl(Filesystem& fs, const char* resource_path);
+	void					write_impl(File* out_file);
+
+private:
+
+	SpriteHeader				m_anim_header;
+	List<SpriteAnimationData> 	m_anim_data;
+};
+
+} // namespace crown

+ 29 - 3
engine/compilers/unit/UnitCompiler.cpp

@@ -39,6 +39,7 @@ namespace crown
 //-----------------------------------------------------------------------------
 UnitCompiler::UnitCompiler()
 	: m_renderable(default_allocator())
+	, m_camera(default_allocator())
 {
 }
 
@@ -57,8 +58,6 @@ size_t UnitCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 	// Check for renderable
 	if (root.has_key("renderable"))
 	{
-		Log::d("Reading renderables");
-
 		JSONElement renderable_array = root.key("renderable");
 		uint32_t renderable_array_size = renderable_array.size();
 
@@ -80,7 +79,26 @@ size_t UnitCompiler::compile_impl(Filesystem& fs, const char* resource_path)
 		}
 	}
 
-	return sizeof(UnitHeader) + m_renderable.size() * sizeof(UnitRenderable);
+	// Check for cameras
+	if (root.has_key("camera"))
+	{
+		JSONElement camera = root.key("camera");
+		uint32_t num_cameras = camera.size();
+
+		for (uint32_t i = 0; i < num_cameras; i++)
+		{
+			JSONElement camera_name = camera[i].key("name");
+
+			UnitCamera uc;
+			uc.name = hash::murmur2_32(camera_name.string_value(), camera_name.size(), 0);
+
+			m_camera.push_back(uc);
+		}
+	}
+
+	return sizeof(UnitHeader) +
+			m_renderable.size() * sizeof(UnitRenderable) +
+			m_camera.size() * sizeof(UnitCamera);
 }
 
 //-----------------------------------------------------------------------------
@@ -88,8 +106,10 @@ void UnitCompiler::write_impl(File* out_file)
 {
 	UnitHeader header;
 	header.num_renderables = m_renderable.size();
+	header.num_cameras = m_camera.size();
 
 	header.renderables_offset = sizeof(UnitHeader);
+	header.cameras_offset = sizeof(UnitHeader) + sizeof(UnitRenderable) * header.num_renderables;
 
 	out_file->write((char*) &header, sizeof(UnitHeader));
 
@@ -98,8 +118,14 @@ void UnitCompiler::write_impl(File* out_file)
 		out_file->write((char*) m_renderable.begin(), sizeof(UnitRenderable) * header.num_renderables);
 	}
 
+	if (m_camera.size() > 0)
+	{
+		out_file->write((char*) m_camera.begin(), sizeof(UnitCamera) * header.num_cameras);
+	}
+
 	// Cleanup
 	m_renderable.clear();
+	m_camera.clear();
 }
 
 } // namespace crown

+ 1 - 5
engine/compilers/unit/UnitCompiler.h

@@ -34,11 +34,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 namespace crown
 {
 
-struct UnitCamera
-{
-
-};
-
 class CE_EXPORT UnitCompiler : public Compiler
 {
 public:
@@ -51,6 +46,7 @@ public:
 private:
 
 	List<UnitRenderable> m_renderable;
+	List<UnitCamera> m_camera;
 };
 
 } // namespace crown

+ 189 - 0
engine/core/containers/IdArray.h

@@ -0,0 +1,189 @@
+/*
+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 "Assert.h"
+#include "Allocator.h"
+#include "Types.h"
+#include "IdTable.h"
+#include "List.h"
+
+namespace crown
+{
+
+/// Table of Ids.
+template <uint32_t MAX_NUM_ID, typename T>
+class IdArray
+{
+public:
+
+	/// Creates the table for tracking exactly @a MAX_NUM_ID - 1 unique Ids.
+					IdArray(Allocator& a);
+
+	/// Random access by Id
+	T&				operator[](const Id& id);
+	const T&		operator[](const Id& id) const;
+
+	/// Returns a new Id.
+	Id				create(const T& object);
+
+	/// Destroys the specified @a id.
+	void			destroy(Id id);
+
+	/// Returns whether the table has the specified @a id
+	bool			has(Id id) const;
+
+	T&				lookup(const Id& id);
+
+private:
+
+	// Returns the next available unique id.
+	uint16_t		next_id();
+
+public:
+
+	// The index of the first unused id
+	uint16_t		m_freelist;
+
+	// The index of the last id in the id table
+	uint16_t		m_last_index;
+
+	// Next available unique id
+	uint16_t		m_next_id;
+
+
+	// The last valid id is reserved and cannot be used to
+	// refer to Ids from the outside
+	Id				m_sparse[MAX_NUM_ID];
+	uint16_t		m_sparse_to_dense[MAX_NUM_ID];
+	uint16_t		m_dense_to_sparse[MAX_NUM_ID];
+	List<T>			m_objects;
+};
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline IdArray<MAX_NUM_ID, T>::IdArray(Allocator& a)
+	: m_freelist(MAX_NUM_ID)
+	, m_last_index(0)
+	, m_next_id(0)
+	, m_objects(a)
+{
+	for (uint32_t i = 0; i < MAX_NUM_ID; i++)
+	{
+		m_sparse[i].id = INVALID_ID;
+	}
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline T& IdArray<MAX_NUM_ID, T>::operator[](const Id& id)
+{
+	return lookup(id);
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline const T& IdArray<MAX_NUM_ID, T>::operator[](const Id& id) const
+{
+	return lookup(id);
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline Id IdArray<MAX_NUM_ID, T>::create(const T& object)
+{
+	// Obtain a new id
+	Id id;
+	id.id = next_id();
+
+	uint16_t dense_index;
+
+	// Recycle slot if there are any
+	if (m_freelist != MAX_NUM_ID)
+	{
+		id.index = m_freelist;
+		m_freelist = m_sparse[m_freelist].id;
+		m_objects[id.index] = object;
+		dense_index = id.index;
+	}
+	else
+	{
+		id.index = m_last_index++;
+		dense_index = m_objects.push_back(object);
+	}
+
+	m_sparse[id.index] = id;
+	m_sparse_to_dense[id.index] = dense_index;
+	m_dense_to_sparse[dense_index] = id.index;
+
+	return id;
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline void IdArray<MAX_NUM_ID, T>::destroy(Id id)
+{
+	CE_ASSERT(has(id), "IdArray does not have ID: %d,%d", id.id, id.index);
+
+	m_sparse[id.index].id = INVALID_ID;
+	m_sparse[id.index].index = m_freelist;
+	m_freelist = id.index;
+
+	// Swap with last element
+	m_objects[m_sparse_to_dense[id.index]] = m_objects.back();
+	m_objects.pop_back();
+
+	// Update conversion tables
+	//m_sparse_to_dense[m_dense_to_sparse[m_dense.size() - 1]] = id.index;
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline T& IdArray<MAX_NUM_ID, T>::lookup(const Id& id)
+{
+	CE_ASSERT(has(id), "IdArray does not have ID: %d,%d", id.id, id.index);
+
+	return m_objects[m_sparse_to_dense[id.index]];
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline bool IdArray<MAX_NUM_ID, T>::has(Id id) const
+{
+	return id.index < MAX_NUM_ID && m_sparse[id.index].id == id.id;
+}
+
+//-----------------------------------------------------------------------------
+template <uint32_t MAX_NUM_ID, typename T>
+inline uint16_t IdArray<MAX_NUM_ID, T>::next_id()
+{
+	CE_ASSERT(m_next_id < MAX_NUM_ID, "Maximum number of IDs reached");
+
+	return m_next_id++;
+}
+
+} // namespace crown

+ 10 - 0
engine/core/containers/IdTable.h

@@ -50,6 +50,16 @@ struct Id
 	{
 		return (uint32_t(id) << 16) | uint32_t(index);
 	}
+
+	bool operator==(const Id& other)
+	{
+		return id == other.id && index == other.index;
+	}
+
+	bool operator!=(const Id& other)
+	{
+		return id != other.id || index != other.index;
+	}
 };
 
 /// Table of Ids.

+ 1 - 0
engine/lua/LuaEnvironment.cpp

@@ -62,6 +62,7 @@ CE_EXPORT int luaopen_libcrown(lua_State* /*L*/)
 	load_camera(*env);
 	load_world(*env);
 	load_mesh(*env);
+	load_sprite(*env);
 
 	return 1;
 }

+ 1 - 0
engine/lua/LuaEnvironment.h

@@ -112,6 +112,7 @@ void load_unit(LuaEnvironment& env);
 void load_camera(LuaEnvironment& env);
 void load_world(LuaEnvironment& env);
 void load_mesh(LuaEnvironment& env);
+void load_sprite(LuaEnvironment& env);
 
 CE_EXPORT int32_t luaopen_libcrown(lua_State* L);
 

+ 121 - 0
engine/lua/LuaSprite.cpp

@@ -0,0 +1,121 @@
+/*
+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 "Sprite.h"
+#include "Quaternion.h"
+#include "LuaStack.h"
+#include "LuaEnvironment.h"
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int sprite_local_position(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+
+	stack.push_vector3(sprite->local_position());
+
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int sprite_local_rotation(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+
+	stack.push_quaternion(sprite->local_rotation());
+
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int sprite_local_pose(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+
+	stack.push_matrix4x4(sprite->local_pose());
+
+	return 1;
+}
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int sprite_set_local_position(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+	Vector3 pos = stack.get_vector3(2);
+
+	sprite->set_local_position(pos);
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int sprite_set_local_rotation(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+	Quaternion rot = stack.get_quaternion(2);
+
+	sprite->set_local_rotation(rot);
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+CE_EXPORT int sprite_set_local_pose(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Sprite* sprite = stack.get_sprite(1);
+	Matrix4x4 pose = stack.get_matrix4x4(2);
+
+	sprite->set_local_pose(pose);
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+void load_sprite(LuaEnvironment& env)
+{
+	env.load_module_function("Sprite", "local_position", 		sprite_local_position);
+	env.load_module_function("Sprite", "local_rotation", 		sprite_local_rotation);
+	env.load_module_function("Sprite", "local_pose", 			sprite_local_pose);
+	env.load_module_function("Sprite", "set_local_position", 	sprite_set_local_position);
+	env.load_module_function("Sprite", "set_local_rotation", 	sprite_set_local_rotation);
+	env.load_module_function("Sprite", "set_local_pose", 		sprite_set_local_pose);
+}
+
+} // namespace crown

+ 13 - 0
engine/lua/LuaStack.h

@@ -40,6 +40,7 @@ class Unit;
 class Camera;
 class World;
 class Mesh;
+class Sprite;
 
 void clear_lua_temporaries();
 
@@ -199,6 +200,18 @@ public:
 		return (Mesh*) lua_touserdata(m_state, index);
 	}
 
+	//-----------------------------------------------------------------------------
+	void push_sprite(Sprite* sprite)
+	{
+		lua_pushlightuserdata(m_state, sprite);
+	}
+
+	//-----------------------------------------------------------------------------
+	Sprite* get_sprite(int32_t index)
+	{
+		return (Sprite*) lua_touserdata(m_state, index);
+	}
+
 	Vector2& get_vector2(int32_t index);
 	Vector3& get_vector3(int32_t index);
 	Matrix4x4& get_matrix4x4(int32_t index);

+ 13 - 0
engine/lua/LuaUnit.cpp

@@ -157,6 +157,18 @@ CE_EXPORT int unit_mesh(lua_State* L)
 	return 1;
 }
 
+//-----------------------------------------------------------------------------
+CE_EXPORT int unit_sprite(lua_State* L)
+{
+	LuaStack stack(L);
+
+	Unit* unit = stack.get_unit(1);
+	const char* sprite_name = stack.get_string(2);
+
+	stack.push_sprite(unit->sprite(sprite_name));
+	return 1;
+}
+
 //-----------------------------------------------------------------------------
 void load_unit(LuaEnvironment& env)
 {
@@ -172,6 +184,7 @@ void load_unit(LuaEnvironment& env)
 
 	env.load_module_function("Unit", "camera",					unit_camera);
 	env.load_module_function("Unit", "mesh",					unit_mesh);	
+	env.load_module_function("Unit", "sprite",					unit_sprite);
 }
 
 } // namespace crown

+ 1 - 1
engine/renderers/Renderer.h

@@ -138,7 +138,7 @@ public:
 	/// @note
 	/// @a count and @a offset together do not have to exceed the number of elements
 	/// originally specified to Renderer::create_vertex_buffer() (or Renderer::create_dynamic_vertex_buffer())
-	inline void update_vertex_buffer(VertexBufferId id, size_t offset, size_t count, const uint16_t* vertices)
+	inline void update_vertex_buffer(VertexBufferId id, size_t offset, size_t count, const void* vertices)
 	{
 		m_submit->m_commands.write(CommandType::UPDATE_VERTEX_BUFFER);
 		m_submit->m_commands.write(id);

+ 19 - 0
engine/resource/PackageResource.h

@@ -48,6 +48,8 @@ struct PackageHeader
 	uint32_t meshes_offset;
 	uint32_t num_units;
 	uint32_t units_offset;
+	uint32_t num_sprites;
+	uint32_t sprites_offset;
 };
 
 class PackageResource
@@ -130,6 +132,14 @@ public:
 		return ((PackageHeader*)m_data)->num_units;
 	}
 
+	//-----------------------------------------------------------------------------
+	uint32_t num_sprites() const
+	{
+		CE_ASSERT_NOT_NULL(m_data);
+
+		return ((PackageHeader*)m_data)->num_sprites;
+	}
+
 	//-----------------------------------------------------------------------------
 	ResourceId get_texture_id(uint32_t i) const
 	{
@@ -175,6 +185,15 @@ public:
 		return begin[i];
 	}
 
+	//-----------------------------------------------------------------------------
+	ResourceId get_sprite_id(uint32_t i) const
+	{
+		CE_ASSERT(i < num_sprites(), "Index out of bounds");
+
+		ResourceId* begin = (ResourceId*) (m_data + ((PackageHeader*)m_data)->sprites_offset);
+		return begin[i];
+	}
+
 private:
 
 	char* m_data;

+ 2 - 0
engine/resource/Resource.h

@@ -40,6 +40,7 @@ const char* const LUA_EXTENSION				= "lua";
 const char* const TEXT_EXTENSION			= "text";
 const char* const MATERIAL_EXTENSION		= "material";
 const char* const SOUND_EXTENSION			= "sound";
+const char* const SPRITE_EXTENSION			= "sprite";
 const char* const CONFIG_EXTENSION			= "config";
 const char* const PACKAGE_EXTENSION			= "package";
 const char* const UNIT_EXTENSION			= "unit";
@@ -50,6 +51,7 @@ const uint32_t LUA_TYPE						= 0xD96E7C37;
 const uint32_t TEXT_TYPE					= 0x45CC650;
 const uint32_t MATERIAL_TYPE				= 0x46807A92;
 const uint32_t SOUND_TYPE					= 0xD196AB6E;
+const uint32_t SPRITE_TYPE					= 0x5DD272E5;
 const uint32_t CONFIG_TYPE					= 0x17DEA5E1;
 const uint32_t PACKAGE_TYPE					= 0xC0A2212C;
 const uint32_t UNIT_TYPE					= 0x516224CF;

+ 1 - 1
engine/resource/ResourceManager.cpp

@@ -87,7 +87,7 @@ const void* ResourceManager::lookup(const char* type, const char* name) const
 	ResourceId id = resource_id(type, name);
 	ResourceEntry* entry = find(id);
 
-	CE_ASSERT_NOT_NULL(entry);
+	CE_ASSERT(entry != NULL, "Resource not loaded: type = '%s', name = '%s'", type, name);
 
 	return entry->resource;
 }

+ 10 - 0
engine/resource/ResourcePackage.h

@@ -77,11 +77,21 @@ public:
 		{
 			m_resource_manager->load(UNIT_TYPE, m_package->get_unit_id(i));
 		}
+
+		for (uint32_t i = 0; i < m_package->num_sprites(); i++)
+		{
+			m_resource_manager->load(SPRITE_TYPE, m_package->get_sprite_id(i));
+		}
 	}
 
 	/// Unloads all the resources in the package.
 	void unload()
 	{
+		for (uint32_t i = 0; i < m_package->num_sprites(); i++)
+		{
+			m_resource_manager->unload(m_package->get_sprite_id(i));
+		}
+
 		for (uint32_t i = 0; i < m_package->num_units(); i++)
 		{
 			m_resource_manager->unload(m_package->get_unit_id(i));

+ 3 - 1
engine/resource/ResourceRegistry.cpp

@@ -29,6 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "TextureResource.h"
 #include "MeshResource.h"
 #include "SoundResource.h"
+#include "SpriteResource.h"
 #include "PackageResource.h"
 #include "UnitResource.h"
 
@@ -41,8 +42,9 @@ static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 	{ TEXTURE_TYPE, TextureResource::load, TextureResource::unload, TextureResource::online, TextureResource::offline },
 	{ MESH_TYPE, MeshResource::load, MeshResource::unload, MeshResource::online, MeshResource::offline },
 	{ SOUND_TYPE, SoundResource::load, SoundResource::unload, SoundResource::online, SoundResource::offline },
-	{ PACKAGE_TYPE, PackageResource::load, PackageResource::unload, PackageResource::online, PackageResource::offline },
 	{ UNIT_TYPE, UnitResource::load, UnitResource::unload, UnitResource::online, UnitResource::offline },
+	{ SPRITE_TYPE, SpriteResource::load, SpriteResource::unload, SpriteResource::online, SpriteResource::offline},
+	{ PACKAGE_TYPE, PackageResource::load, PackageResource::unload, PackageResource::online, PackageResource::offline },
 	{ 0, NULL, NULL, NULL, NULL }
 };
 

+ 220 - 0
engine/resource/SpriteResource.h

@@ -0,0 +1,220 @@
+/*
+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 <cstring>
+
+#include "Types.h"
+#include "Allocator.h"
+#include "File.h"
+#include "OS.h"
+#include "StringUtils.h"
+#include "List.h"
+#include "Bundle.h"
+#include "Device.h"
+#include "ResourceManager.h"
+#include "RendererTypes.h"
+#include "Renderer.h"
+#include "TextureResource.h"
+
+#define MAX_SPRITE_ANIM_FRAMES 60
+#define SPRITE_VERTEX_FRAME_SIZE 16
+
+namespace crown
+{
+
+//-----------------------------------------------------------------------------
+static const char* sprite_vs =
+	"uniform mat4      	u_model;"
+	"uniform mat4      	u_model_view_projection;"
+
+	"in vec4           	a_position;"
+	"in vec4           	a_normal;"
+	"in vec2           	a_tex_coord0;"
+	"in vec4           	a_color;"
+
+	"varying out vec2	tex_coord0;"
+	"varying out vec4	color;"
+
+	"void main(void)"
+	"{"
+	"	tex_coord0 = a_tex_coord0;"
+	"   color = a_color;"
+	"	gl_Position = u_model_view_projection * a_position;"
+	"}";
+
+//-----------------------------------------------------------------------------
+static const char* sprite_fs = 
+	"in vec2            tex_coord0;"
+	"in vec4            color;"
+
+	"uniform sampler2D  u_tex;"
+
+	"void main(void)"
+	"{"
+	"	gl_FragColor = texture(u_tex, tex_coord0);"
+	"}";
+
+const uint32_t SPRITE_VERSION = 1;
+
+//-----------------------------------------------------------------------------
+struct SpriteResourceData
+{
+	char 		m_name[128];
+	char 		m_texture[128];
+	uint32_t	m_length;
+	uint32_t	m_frame_rate;
+	uint32_t	m_playback_mode;
+	float		m_vertices[MAX_SPRITE_ANIM_FRAMES * SPRITE_VERTEX_FRAME_SIZE];
+};
+
+//-----------------------------------------------------------------------------
+class SpriteResource
+{
+public:
+
+	//-----------------------------------------------------------------------------
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
+	{
+		File* file = bundle.open(id);
+
+		const size_t file_size = file->size() - 12;
+
+		SpriteResource* res = (SpriteResource*) allocator.allocate(sizeof(SpriteResource));
+		res->m_data = (uint8_t*) allocator.allocate(file_size);
+		res->m_data_size = file_size;
+		file->read(res->m_data, res->m_data_size);
+
+		bundle.close(file);
+
+		return res;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void online(void* resource)
+	{
+		SpriteResource* sr = (SpriteResource*)resource;
+
+		static uint16_t t_indices[] = {0, 1, 2, 0, 2, 3};
+
+		Renderer* r = device()->renderer();
+
+		sr->m_vb = r->create_vertex_buffer(4, VertexFormat::P2_T2, sr->frame(0));
+		sr->m_ib = r->create_index_buffer(6, t_indices);
+		sr->m_vertex = r->create_shader(ShaderType::VERTEX, sprite_vs);
+		sr->m_fragment = r->create_shader(ShaderType::FRAGMENT, sprite_fs);
+		sr->m_program = r->create_gpu_program(sr->m_vertex, sr->m_fragment);
+		sr->m_uniform = r->create_uniform("u_tex", UniformType::INTEGER_1, 1);
+
+		// FIXME FIXME FIXME
+		TextureResource* res = (TextureResource*)device()->resource_manager()->lookup(TEXTURE_EXTENSION, sr->texture());
+		sr->m_texture = res->m_texture;
+	}
+
+	//-----------------------------------------------------------------------------
+	static void unload(Allocator& allocator, void* resource)
+	{
+		SpriteResource* res = (SpriteResource*)resource;
+		allocator.deallocate(res->m_data);
+		allocator.deallocate(res);
+	}
+
+	//-----------------------------------------------------------------------------
+	static void offline(void* resource)
+	{
+		SpriteResource* sprite = (SpriteResource*) resource;
+
+		Renderer* r = device()->renderer();
+
+		r->destroy_vertex_buffer(sprite->m_vb);
+		r->destroy_index_buffer(sprite->m_ib);
+	}
+
+	//-----------------------------------------------------------------------------
+	const char* name()
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_name;
+	}
+
+	//-----------------------------------------------------------------------------
+	const char* texture()
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_texture;		
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t length()
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_length;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t frame_rate()
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_frame_rate;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t playback_mode()
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_playback_mode;
+	}
+
+	//-----------------------------------------------------------------------------
+	float* animation()
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_vertices;
+	}
+
+	//-----------------------------------------------------------------------------
+	float* frame(uint32_t index)
+	{
+		SpriteResourceData* t_data = (SpriteResourceData*)m_data;
+		return t_data->m_vertices + SPRITE_VERTEX_FRAME_SIZE * index;
+	}
+
+public:
+
+	uint8_t*					m_data;
+	size_t						m_data_size;
+
+	TextureId 					m_texture;
+	VertexBufferId 				m_vb;
+	IndexBufferId 				m_ib;
+	ShaderId 					m_vertex;
+	ShaderId 					m_fragment;
+	GPUProgramId				m_program;
+	UniformId 					m_uniform;
+};
+
+} // namespace crown

+ 1 - 1
engine/resource/TextureResource.h

@@ -120,7 +120,7 @@ public:
 		return m_data;
 	}
 
-private:
+public:
 
 	TextureHeader		m_header;
 	uint8_t*			m_data;

+ 24 - 0
engine/resource/UnitResource.h

@@ -40,6 +40,8 @@ struct UnitHeader
 {
 	uint32_t num_renderables;
 	uint32_t renderables_offset;
+	uint32_t num_cameras;
+	uint32_t cameras_offset;
 };
 
 struct UnitRenderable
@@ -49,6 +51,11 @@ struct UnitRenderable
 	bool visible;
 };
 
+struct UnitCamera
+{
+	uint32_t name;
+};
+
 class UnitResource
 {
 public:
@@ -106,6 +113,23 @@ public:
 		return begin[i];
 	}
 
+	//-----------------------------------------------------------------------------
+	uint32_t num_cameras() const
+	{
+		CE_ASSERT_NOT_NULL(m_data);
+
+		return ((UnitHeader*)m_data)->num_cameras;
+	}
+
+	//-----------------------------------------------------------------------------
+	const UnitCamera& get_camera(uint32_t i) const
+	{
+		CE_ASSERT(i < num_cameras(), "Index out of bounds");
+
+		UnitCamera* begin = (UnitCamera*) (m_data + ((UnitHeader*)m_data)->cameras_offset);
+		return begin[i];
+	}
+
 private:
 
 	char* m_data;