Kaynağa Gözat

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

Daniele Bartolini 12 yıl önce
ebeveyn
işleme
e557da8d65

+ 3 - 0
engine/CMakeLists.txt

@@ -307,6 +307,7 @@ set (RESOURCE_SRC
 	resource/MeshResource.cpp
 	resource/LuaResource.cpp
 	resource/GuiResource.cpp
+	resource/FontResource.cpp
 )
 
 set (RESOURCE_HEADERS
@@ -327,6 +328,7 @@ set (RESOURCE_HEADERS
 	resource/SpriteResource.h
 	resource/PhysicsResource.h
 	resource/GuiResource.h
+	resource/FontResource.h
 )
 
 if (CROWN_DEBUG OR CROWN_DEVELOPMENT)
@@ -444,6 +446,7 @@ set (GUI_HEADERS
 	gui/GuiRect.h
 	gui/GuiTriangle.h
 	gui/GuiImage.h
+	gui/GuiText.h
 )
 
 set (CROWN_LIBRARIES)

+ 5 - 0
engine/compilers/BundleCompiler.cpp

@@ -50,6 +50,7 @@ namespace sound_resource { extern void compile(Filesystem&, const char*, File*);
 namespace sprite_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace material_resource { extern void compile(Filesystem&, const char*, File*); }
 namespace gui_resource { extern void compile(Filesystem&, const char*, File*); }
+namespace font_resource { extern void compile(Filesystem&, const char*, File*); }
 
 //-----------------------------------------------------------------------------
 BundleCompiler::BundleCompiler()
@@ -171,6 +172,10 @@ bool BundleCompiler::compile(const char* bundle_dir, const char* source_dir, con
 			{
 				physics_config_resource::compile(root_fs, filename, out_file);
 			}
+			else if (resource_type_hash == FONT_TYPE)
+			{
+				font_resource::compile(root_fs, filename, out_file);
+			}
 			else
 			{
 				Log::e("Oops, unknown resource type!");

+ 103 - 4
engine/gui/Gui.cpp

@@ -35,10 +35,12 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector3.h"
 #include "Vector2.h"
 #include "Color4.h"
+#include "FontResource.h"
 
 #include "GuiRect.h"
 #include "GuiTriangle.h"
 #include "GuiImage.h"
+#include "GuiText.h"
 
 namespace crown
 {
@@ -50,8 +52,12 @@ GPUProgramId		gui_default_program;
 GPUProgramId		gui_texture_program;
 UniformId			gui_albedo_0;
 
+ShaderId			font_vs;
+ShaderId			font_fs;
+GPUProgramId		font_program;
+UniformId			font_uniform;
+
 static const char* default_vertex =
-	"uniform mat4      	u_model;"
 	"uniform mat4      	u_model_view_projection;"
 
 	"attribute vec4    	a_position;"
@@ -87,6 +93,37 @@ static const char* texture_fragment =
 	"	gl_FragColor = texture2D(u_albedo_0, tex_coord0);"
 	"}";
 
+static const char* sdf_vertex =
+	"uniform mat4      	u_model_view_projection;"
+
+	"attribute vec4		a_position;"
+	"attribute vec2		a_tex_coord0;"
+	"attribute vec4		a_color;"
+
+	"varying vec2		v_tex_coord;"
+	"varying vec4		v_color;"
+
+	"void main(void)"
+	"{"
+	"	gl_Position = u_model_view_projection * a_position;"
+	"	v_tex_coord = a_tex_coord0;"
+	"	v_color = vec4(1, 1, 1, 1);"
+	"}";
+
+static const char* sdf_fragment =
+	"uniform sampler2D u_texture;"
+
+	"varying vec4 v_color;"
+	"varying vec2 v_tex_coord;"
+
+	"const float smoothing = 1.0/16.0;"
+
+	"void main() {"
+		"float distance = texture2D(u_texture, v_tex_coord).a;"
+		"float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);"
+		"gl_FragColor = vec4(v_color.rgb, alpha);"
+	"}";
+
 //-----------------------------------------------------------------------------
 Gui::Gui(RenderWorld& render_world, GuiResource* gr, Renderer& r)
 	: m_render_world(render_world)
@@ -95,6 +132,7 @@ Gui::Gui(RenderWorld& render_world, GuiResource* gr, Renderer& r)
 	, m_rect_pool(default_allocator(), MAX_GUI_RECTS, sizeof(GuiRect), CE_ALIGNOF(GuiRect))
 	, m_triangle_pool(default_allocator(), MAX_GUI_TRIANGLES, sizeof(GuiTriangle), CE_ALIGNOF(GuiTriangle))
 	, m_image_pool(default_allocator(), MAX_GUI_IMAGES, sizeof(GuiImage), CE_ALIGNOF(GuiImage))
+	, m_text_pool(default_allocator(), MAX_GUI_TEXTS, sizeof(GuiText), CE_ALIGNOF(GuiText))
 {
 	// orthographic projection
 	Vector2 size = m_resource->gui_size();
@@ -113,6 +151,13 @@ Gui::Gui(RenderWorld& render_world, GuiResource* gr, Renderer& r)
 	gui_texture_program = m_r.create_gpu_program(gui_default_vs, gui_texture_fs);
 	gui_albedo_0 = m_r.create_uniform("u_albedo_0", UniformType::INTEGER_1, 1);
 
+	// FIXME FIXME FIXME -- Shaders init should not be here
+	font_vs = m_r.create_shader(ShaderType::VERTEX, sdf_vertex);
+	font_fs = m_r.create_shader(ShaderType::FRAGMENT, sdf_fragment);
+	font_program = m_r.create_gpu_program(font_vs, font_fs);
+	font_uniform = m_r.create_uniform("u_texture", UniformType::INTEGER_1, 1);
+
+
 	// Gui's rects creation
 	for (uint32_t i = 0; i < m_resource->num_rects(); i++)
 	{
@@ -144,26 +189,36 @@ Gui::Gui(RenderWorld& render_world, GuiResource* gr, Renderer& r)
 
 		create_image(mat, pos, size);
 	}
+
+	// Manage texts creation
+
+	FontResource* res = (FontResource*) device()->resource_manager()->lookup("font", "fonts/veramobi_sdf");
+	create_text("&", res, 100, Vector3(300, 400, 0));
 }
 
 //-----------------------------------------------------------------------------
 Gui::~Gui()
 {
-	for (uint32_t i = 0; i < m_resource->num_rects(); i++)
+	for (uint32_t i = 0; i < m_rects.size(); i++)
 	{
 		CE_DELETE(m_rect_pool, m_rects[i]);
 	}
 
-	for (uint32_t i = 0; i < m_resource->num_triangles(); i++)
+	for (uint32_t i = 0; i < m_triangles.size(); i++)
 	{
 		CE_DELETE(m_triangle_pool, m_triangles[i]);
 	}
 
-	for (uint32_t i = 0; i < m_resource->num_images(); i++)
+	for (uint32_t i = 0; i < m_images.size(); i++)
 	{
 		CE_DELETE(m_image_pool, m_images[i]);
 	}
 
+	for (uint32_t i = 0; i < m_texts.size(); i++)
+	{
+		CE_DELETE(m_text_pool, m_texts[i]);
+	}
+
 	// FIXME FIXME FIXME -- Shaders destruction should not be here
 	m_r.destroy_uniform(gui_albedo_0);
 	m_r.destroy_gpu_program(gui_texture_program);
@@ -171,6 +226,12 @@ Gui::~Gui()
 	m_r.destroy_shader(gui_texture_fs);
 	m_r.destroy_shader(gui_default_fs);
 	m_r.destroy_shader(gui_default_vs);
+
+	// FIXME FIXME FIXME -- Shaders destruction should not be here
+	m_r.destroy_uniform(font_uniform);
+	m_r.destroy_gpu_program(font_program);
+	m_r.destroy_shader(font_vs);
+	m_r.destroy_shader(font_fs);
 }
 
 //-----------------------------------------------------------------------------
@@ -264,6 +325,29 @@ void Gui::destroy_image(GuiImageId id)
 	m_images.destroy(id);
 }
 
+//-----------------------------------------------------------------------------
+GuiTextId Gui::create_text(const char* str, const FontResource* font, uint32_t font_size, const Vector3& pos)
+{
+	GuiText* text = CE_NEW(m_text_pool, GuiText)(m_render_world, m_r, font, str, font_size, pos);
+	return m_texts.create(text);
+}
+
+//-----------------------------------------------------------------------------
+void Gui::update_text(GuiTextId id)
+{
+	// Must be implemented
+}
+
+//-----------------------------------------------------------------------------
+void Gui::destroy_text(GuiTextId id)
+{
+	CE_ASSERT(m_texts.has(id), "GuiText does not exists");
+
+	GuiText* text = m_texts.lookup(id);
+	CE_DELETE(m_text_pool, text);
+	m_texts.destroy(id);
+}
+
 //-----------------------------------------------------------------------------
 void Gui::render()
 {
@@ -319,6 +403,21 @@ void Gui::render()
 
 		m_images[i]->render(gui_albedo_0);
 	}
+
+	for (uint32_t i = 0; i < m_texts.size(); i++)
+	{
+		m_r.set_program(font_program);
+		m_r.set_state(STATE_DEPTH_WRITE 
+		| STATE_COLOR_WRITE 
+		| STATE_ALPHA_WRITE 
+		| STATE_CULL_CW
+		| STATE_PRIMITIVE_TRIANGLES
+		| STATE_BLEND_EQUATION_ADD 
+		| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
+		m_r.set_pose(m_pose);
+
+		m_texts[i]->render(gui_albedo_0);
+	}
 }
 
 } // namespace crown

+ 10 - 1
engine/gui/Gui.h

@@ -36,6 +36,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #define MAX_GUI_RECTS 64
 #define MAX_GUI_TRIANGLES 64
 #define MAX_GUI_IMAGES 64
+#define MAX_GUI_TEXTS 64
 
 namespace crown
 {
@@ -44,17 +45,19 @@ typedef Id UniformId;
 typedef Id GuiRectId;
 typedef Id GuiTriangleId;
 typedef Id GuiImageId;
+typedef Id GuiTextId;
 
 struct Renderer;
 struct RenderWorld;
-struct Vector3;
 struct GuiResource;
 struct GuiRect;
 struct GuiTriangle;
 struct GuiImage;
+struct GuiText;
 struct Vector3;
 struct Vector2;
 struct Color4;
+struct FontResource;
 
 struct Gui
 {
@@ -76,6 +79,10 @@ struct Gui
 	void				update_image(GuiImageId id, const Vector3& pos, const Vector2& size);
 	void				destroy_image(GuiImageId);
 
+	GuiTextId			create_text(const char* str, const FontResource* font, uint32_t font_size, const Vector3& pos);
+	void				update_text(GuiTextId id);
+	void				destroy_text(GuiTextId id);
+
 	void				render();
 
 public:
@@ -90,10 +97,12 @@ public:
 	PoolAllocator		m_rect_pool;
 	PoolAllocator		m_triangle_pool;
 	PoolAllocator		m_image_pool;
+	PoolAllocator		m_text_pool;
 
 	IdArray<MAX_GUI_RECTS, GuiRect*> m_rects;
 	IdArray<MAX_GUI_TRIANGLES, GuiTriangle*> m_triangles;
 	IdArray<MAX_GUI_IMAGES, GuiImage*> m_images;
+	IdArray<MAX_GUI_TEXTS, GuiText*> m_texts;
 };
 
 } // namespace crown

+ 1 - 1
engine/gui/GuiImage.h

@@ -99,7 +99,7 @@ public:
 	RenderWorld& m_render_world;
 	Renderer& m_r;
 
-	float m_vertices[6*4];
+	float m_vertices[4*4];
 	uint16_t m_indices[2*3];
 
 	MaterialId m_material;

+ 134 - 0
engine/gui/GuiText.h

@@ -0,0 +1,134 @@
+/*
+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 "Matrix4x4.h"
+#include "RendererTypes.h"
+#include "StringUtils.h"
+#include "Log.h"
+#include "FontResource.h"
+
+namespace crown
+{
+
+struct Vector3;
+struct Vector2;
+struct Color4;
+
+struct GuiText
+{
+	//-------------------------------------------------------------------------
+	GuiText(RenderWorld& render_world, Renderer& r, const FontResource* fr, const char* str, uint32_t font_size, const Vector3& pos)
+		: m_render_world(render_world)
+		, m_r(r)
+		, m_resource(fr)
+	{
+		MaterialResource* mat = (MaterialResource*) device()->resource_manager()->data(m_resource->material());
+		m_material = m_render_world.create_material(mat);
+
+		FontGlyphData g = m_resource->get_glyph(str[0]);
+
+		// update(pos, Vector2(100, 100));
+		float x 		= (float) g.x / 512.0f;
+		float y 		= (float) (512 - g.y) / 512.0f;
+		float width 	= (float) g.width / 512.0f;
+		float height 	= (float) g.height / 512.0f;
+
+		float u0 = x;
+		float v0 = y;
+		float u1 = x + width;
+		float v1 = y - height;
+
+		m_vertices[0] = pos.x;
+		m_vertices[1] = pos.y;
+		m_vertices[2] = u0;
+		m_vertices[3] = v1;
+
+		m_vertices[4] = pos.x + font_size;
+		m_vertices[5] = pos.y;
+		m_vertices[6] = u1; 
+		m_vertices[7] = v1;
+
+		m_vertices[8] = pos.x + font_size; 
+		m_vertices[9] = pos.y - font_size;
+		m_vertices[10] = u1;
+		m_vertices[11] = v0;
+
+		m_vertices[12] = pos.x; 
+		m_vertices[13] = pos.y - font_size;
+		m_vertices[14] = u0;
+		m_vertices[15] = v0;
+
+		m_indices[0] = 0; m_indices[1] = 1;
+		m_indices[2] = 2; m_indices[3] = 0;
+		m_indices[4] = 2; m_indices[5] = 3;
+
+		m_vb = m_r.create_vertex_buffer(4, VertexFormat::P2_T2, m_vertices);
+		m_ib = m_r.create_index_buffer(6, m_indices);
+	}
+
+	//-------------------------------------------------------------------------
+	~GuiText()
+	{
+		m_r.destroy_vertex_buffer(m_vb);
+		m_r.destroy_index_buffer(m_ib);
+
+		m_render_world.destroy_material(m_material);
+	}
+
+	//-------------------------------------------------------------------------
+	void update(const Vector3& pos, const Vector2& size)
+	{
+	}
+
+	//-------------------------------------------------------------------------
+	void render(UniformId uniform)
+	{
+		Material* material = m_render_world.lookup_material(m_material);
+		material->bind(m_r, uniform);
+
+		m_r.set_vertex_buffer(m_vb);
+		m_r.set_index_buffer(m_ib);
+		m_r.commit(1);
+	}
+
+public:
+
+	RenderWorld& m_render_world;
+	Renderer& m_r;
+	const FontResource* m_resource;
+
+	float m_vertices[4*4];
+	uint16_t m_indices[2*3];
+
+	VertexBufferId m_vb;
+	IndexBufferId m_ib;
+	MaterialId m_material;
+};
+
+} // namespace crown
+

+ 2 - 2
engine/renderers/RenderWorld.h

@@ -61,8 +61,8 @@ public:
 	~RenderWorld();
 
 	MeshId		create_mesh(MeshResource* mr, SceneGraph& sg, int32_t node);
-	void 		destroy_mesh(MeshId id);
-	Mesh* 		lookup_mesh(MeshId mesh);
+	void		destroy_mesh(MeshId id);
+	Mesh*		lookup_mesh(MeshId mesh);
 
 	SpriteId	create_sprite(SpriteResource* sr, SceneGraph& sg, int32_t node);
 	void		destroy_sprite(SpriteId id);

+ 109 - 0
engine/resource/FontResource.cpp

@@ -0,0 +1,109 @@
+/*
+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 "FontResource.h"
+#include "JSONParser.h"
+#include "Allocator.h"
+#include "Filesystem.h"
+#include "Hash.h"
+#include "Bundle.h"
+#include "Types.h"
+
+
+namespace crown
+{
+namespace font_resource
+{
+
+//-----------------------------------------------------------------------------
+void parse_glyph(JSONElement e, FontGlyphData& glyph)
+{
+	JSONElement id = e.key("id");
+	JSONElement x = e.key("x");
+	JSONElement y = e.key("y");
+	JSONElement width = e.key("width");
+	JSONElement height = e.key("height");
+	JSONElement x_offset = e.key("x_offset");
+	JSONElement y_offset = e.key("y_offset");
+	JSONElement x_advance = e.key("x_advance");
+
+	glyph.id = id.to_int();
+	glyph.x = x.to_int();
+	glyph.y = y.to_int();
+	glyph.width = width.to_int();
+	glyph.height = height.to_int();
+	glyph.x_offset = x_offset.to_float();
+	glyph.y_offset = y_offset.to_float();
+	glyph.x_advance = x_advance.to_float();
+}
+
+//-----------------------------------------------------------------------------
+void compile(Filesystem& fs, const char* resource_path, File* out_file)
+{
+	File* file = fs.open(resource_path, FOM_READ);
+	char* buf = (char*)default_allocator().allocate(file->size());
+	file->read(buf, file->size());
+
+	// Out buffer
+	FontHeader h;
+	List<FontGlyphData> m_glyphs(default_allocator());
+
+	JSONParser json(buf);
+	JSONElement root = json.root();
+
+	JSONElement mat = root.key("material");
+	JSONElement count = root.key("count");
+	JSONElement glyphs = root.key("glyphs");
+
+	DynamicString material_name;
+	mat.to_string(material_name);
+	material_name += ".material";
+
+	uint32_t num_glyphs = count.to_int();
+	
+	for (uint32_t i = 0; i < num_glyphs; i++)
+	{
+		FontGlyphData data;
+		parse_glyph(glyphs[i], data);
+		m_glyphs.push_back(data);
+	}
+
+	fs.close(file);
+	default_allocator().deallocate(buf);
+
+	h.material.id = hash::murmur2_64(material_name.c_str(), string::strlen(material_name.c_str()), 0);
+	h.num_glyphs = m_glyphs.size();
+
+	out_file->write((char*) &h, sizeof(FontHeader));
+
+	if (m_glyphs.size() > 0)
+	{
+		out_file->write((char*) m_glyphs.begin(), sizeof(FontGlyphData) * h.num_glyphs);
+	}
+}
+
+} // namespace font_resource
+} // namespace crown

+ 97 - 5
engine/resource/FontResource.h

@@ -30,19 +30,80 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Resource.h"
 #include "Bundle.h"
 #include "Allocator.h"
+#include "File.h"
+#include "Assert.h"
+#include "Log.h"
 
 namespace crown
 {
 
+// Glyph metrics:
+// --------------
+//
+//                   x_min|<-------- width -------->|x_max
+//                        |                         |
+//              |   	  +-------------------------+--------------- y_max
+//              |         |    ggggggggg   ggggg    |     ^        ^
+//              |         |   g:::::::::ggg::::g    |     |        |
+//              |         |  g:::::::::::::::::g    |     |        |
+//              |         | g::::::ggggg::::::gg    |     |        |
+//              |         | g:::::g     g:::::g     |     |        |
+//    x_offset -|-------->| g:::::g     g:::::g     |  y_offset    |
+//              |         | g:::::g     g:::::g     |     |        |
+//              |         | g::::::g    g:::::g     |     |        |
+//              |         | g:::::::ggggg:::::g     |     |        |
+//              |         |  g::::::::::::::::g     |     |      height
+//              |         |   gg::::::::::::::g     |     |        |
+//  baseline ---*---------|---- gggggggg::::::g-----*--------      |
+//            / |         |             g:::::g     |              |
+//     origin   |         | gggggg      g:::::g     |              |
+//              |         | g:::::gg   gg:::::g     |              |
+//              |         |  g::::::ggg:::::::g     |              |
+//              |         |   gg:::::::::::::g      |              |
+//              |         |     ggg::::::ggg        |              |
+//              |         |         gggggg          |              v
+//              |         +-------------------------+--------------- y_min
+//              |                                   |
+//              |------------- x_advance ---------->|
+
+
+//-----------------------------------------------------------------------------
+struct FontHeader
+{
+	ResourceId material;
+	uint32_t num_glyphs;
+};
+
+//-----------------------------------------------------------------------------
+struct FontGlyphData
+{
+	uint32_t id;
+	uint32_t x;
+	uint32_t y;
+	uint32_t width;
+	uint32_t height;
+	float x_offset;
+	float y_offset;
+	float x_advance;
+};
+
+//-----------------------------------------------------------------------------
 class FontResource
 {
 public:
 
 	//-----------------------------------------------------------------------------
-	static void* load(Allocator& /*allocator*/, Bundle& /*bundle*/, ResourceId /*id*/)
+	static void* load(Allocator& allocator, Bundle& bundle, ResourceId id)
 	{
-		return NULL;
-		// TODO
+		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;
 	}
 
 	//-----------------------------------------------------------------------------
@@ -53,9 +114,10 @@ public:
 	}
 
 	//-----------------------------------------------------------------------------
-	static void unload(Allocator& /*allocator*/, void* /*resource*/)
+	static void unload(Allocator& allocator, void* resource)
 	{
-		// TODO
+		CE_ASSERT_NOT_NULL(resource);
+		allocator.deallocate(resource);
 	}
 
 	//-----------------------------------------------------------------------------
@@ -64,6 +126,36 @@ public:
 		// TODO
 	}
 
+	//-----------------------------------------------------------------------------
+	ResourceId material() const
+	{
+		return ((FontHeader*) this)->material;
+	}
+
+	//-----------------------------------------------------------------------------
+	uint32_t num_glyphs() const
+	{
+		return ((FontHeader*)this)->num_glyphs;
+	}
+
+	//-----------------------------------------------------------------------------
+	FontGlyphData get_glyph(const uint8_t index) const
+	{
+		CE_ASSERT(index < num_glyphs(), "Index out of bounds");
+
+		FontGlyphData* begin = (FontGlyphData*) (((char*) this) + sizeof(FontHeader));
+
+		for (uint32_t i = 0; i < num_glyphs(); i++)
+		{
+			if (begin[i].id == index)
+			{
+				return begin[i];
+			}
+		}
+
+		CE_FATAL("Glyph not found");
+	}
+
 private:
 
 	// Disable construction

+ 31 - 1
engine/resource/PackageResource.cpp

@@ -59,6 +59,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	List<ResourceId> m_physics(default_allocator());
 	List<ResourceId> m_materials(default_allocator());
 	List<ResourceId> m_guis(default_allocator());
+	List<ResourceId> m_fonts(default_allocator());
 
 	// Check for resource types
 	if (root.has_key("texture"))
@@ -265,7 +266,30 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 			id.id = hash::murmur2_64(guis_name.c_str(), guis_name.length(), 0);
 			m_guis.push_back(id);
 		}
-	}	
+	}
+
+	// Check for fonts
+	if (root.has_key("font"))
+	{
+		JSONElement fonts_array = root.key("font");
+		uint32_t fonts_array_size = fonts_array.size();
+
+		for (uint32_t i = 0; i < fonts_array_size; i++)
+		{
+			DynamicString font_name;
+			fonts_array[i].to_string(font_name); font_name += ".font";
+
+			if (!fs.is_file(font_name.c_str()))
+			{
+				Log::e("font '%s' does not exist.", font_name.c_str());
+				return;				
+			}
+
+			ResourceId id;
+			id.id = hash::murmur2_64(font_name.c_str(), font_name.length(), 0);
+			m_fonts.push_back(id);
+		}
+	}
 
 	PackageHeader header;
 	header.num_textures = m_texture.size();
@@ -277,6 +301,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	header.num_physics = m_physics.size();
 	header.num_materials = m_materials.size();
 	header.num_guis = m_guis.size();
+	header.num_fonts = m_fonts.size();
 
 	header.textures_offset = sizeof(PackageHeader);
 	header.scripts_offset  = header.textures_offset + sizeof(ResourceId) * header.num_textures;
@@ -287,6 +312,7 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	header.physics_offset = header.sprites_offset + sizeof(ResourceId) * header.num_sprites;
 	header.materials_offset = header.physics_offset + sizeof(ResourceId) * header.num_physics;
 	header.guis_offset = header.materials_offset + sizeof(ResourceId) * header.num_materials;
+	header.fonts_offset = header.guis_offset + sizeof(ResourceId) * header.num_guis;
 
 	out_file->write((char*) &header, sizeof(PackageHeader));
 
@@ -326,6 +352,10 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 	{
 		out_file->write((char*) m_guis.begin(), sizeof(ResourceId) * header.num_guis);
 	}
+	if (m_fonts.size() > 0)
+	{
+		out_file->write((char*) m_fonts.begin(), sizeof(ResourceId) * header.num_fonts);
+	}
 }
 
 } // namespace package_resource

+ 16 - 0
engine/resource/PackageResource.h

@@ -56,6 +56,8 @@ struct PackageHeader
 	uint32_t materials_offset;
 	uint32_t num_guis;
 	uint32_t guis_offset;
+	uint32_t num_fonts;
+	uint32_t fonts_offset;
 };
 
 struct PackageResource
@@ -145,6 +147,12 @@ struct PackageResource
 		return ((PackageHeader*) this)->num_guis;
 	}
 
+	//-----------------------------------------------------------------------------
+	uint32_t num_fonts() const
+	{
+		return ((PackageHeader*) this)->num_fonts;
+	}
+
 	//-----------------------------------------------------------------------------
 	ResourceId get_texture_id(uint32_t i) const
 	{
@@ -226,6 +234,14 @@ struct PackageResource
 		return begin[i];
 	}
 
+	//-----------------------------------------------------------------------------
+	ResourceId get_font_id(uint32_t i) const
+	{
+		CE_ASSERT(i < num_fonts(), "Index out of bounds");
+
+		ResourceId* begin = (ResourceId*) ((char*) this + ((PackageHeader*) this)->fonts_offset);
+		return begin[i];
+	}
 
 private:
 

+ 2 - 0
engine/resource/Resource.h

@@ -47,6 +47,7 @@ namespace crown
 #define PHYSICS_EXTENSION			"physics"
 #define GUI_EXTENSION				"gui"
 #define PHYSICS_CONFIG_EXTENSION	"physics_config"
+#define FONT_EXTENSION				"font"
 
 #define TEXTURE_TYPE				0x0DEED4F7
 #define MESH_TYPE					0x742FBC9A
@@ -61,6 +62,7 @@ namespace crown
 #define PHYSICS_TYPE				0xFA32C012
 #define GUI_TYPE					0x2C56149A
 #define PHYSICS_CONFIG_TYPE			0x514F14A1
+#define FONT_TYPE					0x536DC7D4
 
 /// ResourceId uniquely identifies a resource by its name and type.
 /// In order to speed up the lookup by the manager, it also keeps

+ 10 - 0
engine/resource/ResourcePackage.h

@@ -97,11 +97,21 @@ public:
 		{
 			m_resource_manager->load(GUI_TYPE, m_package->get_gui_id(i));
 		}
+
+		for (uint32_t i = 0; i < m_package->num_fonts(); i++)
+		{
+			m_resource_manager->load(FONT_TYPE, m_package->get_font_id(i));
+		}
 	}
 
 	/// Unloads all the resources in the package.
 	void unload()
 	{
+		for (uint32_t i = 0; i < m_package->num_fonts(); i++)
+		{
+			m_resource_manager->unload(m_package->get_font_id(i));
+		}
+
 		for (uint32_t i = 0; i < m_package->num_guis(); i++)
 		{
 			m_resource_manager->unload(m_package->get_gui_id(i));

+ 2 - 0
engine/resource/ResourceRegistry.cpp

@@ -35,6 +35,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "PhysicsResource.h"
 #include "MaterialResource.h"
 #include "GuiResource.h"
+#include "FontResource.h"
 
 namespace crown
 {
@@ -52,6 +53,7 @@ static const ResourceCallback RESOURCE_CALLBACK_REGISTRY[] =
 	{ MATERIAL_TYPE, MaterialResource::load, MaterialResource::unload, MaterialResource::online, MaterialResource::offline },
 	{ GUI_TYPE, GuiResource::load, GuiResource::unload, GuiResource::online, GuiResource::offline },
 	{ PHYSICS_CONFIG_TYPE, PhysicsConfigResource::load, PhysicsConfigResource::unload, PhysicsConfigResource::online, PhysicsConfigResource::offline },
+	{ FONT_TYPE, FontResource::load, FontResource::unload, FontResource::online, FontResource::offline },
 	{ 0, NULL, NULL, NULL, NULL }
 };