Daniele Bartolini 10 лет назад
Родитель
Сommit
b7f220ecab
5 измененных файлов с 365 добавлено и 296 удалено
  1. 54 21
      src/lua/lua_api.cpp
  2. 251 241
      src/world/gui.cpp
  3. 34 34
      src/world/gui.h
  4. 18 0
      src/world/world.cpp
  5. 8 0
      src/world/world.h

+ 54 - 21
src/lua/lua_api.cpp

@@ -13,6 +13,7 @@
 #include "intersection.h"
 #include "lua_environment.h"
 #include "lua_stack.h"
+#include "material.h"
 #include "math_types.h"
 #include "math_utils.h"
 #include "matrix4x4.h"
@@ -1600,6 +1601,20 @@ static int world_destroy_debug_line(lua_State* L)
 	return 0;
 }
 
+static int world_create_screen_gui(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.push_gui(stack.get_world(1)->create_screen_gui(stack.get_float(2), stack.get_float(3)));
+	return 1;
+}
+
+static int world_destroy_gui(lua_State* L)
+{
+	LuaStack stack(L);
+	stack.get_world(1)->destroy_gui(*stack.get_gui(2));
+	return 0;
+}
+
 static int world_load_level(lua_State* L)
 {
 	LuaStack stack(L);
@@ -2705,8 +2720,8 @@ static int gui_resolution(lua_State* L)
 {
 	LuaStack stack(L);
 	const Vector2 resolution = stack.get_gui(1)->resolution();
-	stack.push_int(resolution.x);
-	stack.push_int(resolution.y);
+	stack.push_int((s32)resolution.x);
+	stack.push_int((s32)resolution.y);
 	return 2;
 }
 
@@ -2724,35 +2739,51 @@ static int gui_screen_to_gui(lua_State* L)
 	return 1;
 }
 
-static int gui_draw_rectangle(lua_State* L)
+static int gui_rect(lua_State* L)
 {
 	LuaStack stack(L);
-	stack.get_gui(1)->draw_rectangle(stack.get_vector3(2), stack.get_vector2(3),
-		stack.get_color4(4));
+	stack.get_gui(1)->rect(stack.get_vector2(2)
+		, stack.get_vector2(3)
+		, stack.get_resource_id(4)
+		, stack.get_color4(5)
+		);
 	return 0;
 }
 
-static int gui_draw_image(lua_State* L)
+static int gui_image(lua_State* L)
 {
 	LuaStack stack(L);
-	stack.get_gui(1)->draw_image(stack.get_string(2), stack.get_vector3(3),
-		stack.get_vector2(4), stack.get_color4(5));
+	stack.get_gui(1)->image(stack.get_vector2(2)
+		, stack.get_vector2(3)
+		, stack.get_resource_id(4)
+		, stack.get_color4(5)
+		);
 	return 0;
 }
 
-static int gui_draw_image_uv(lua_State* L)
+static int gui_image_uv(lua_State* L)
 {
 	LuaStack stack(L);
-	stack.get_gui(1)->draw_image_uv(stack.get_string(2), stack.get_vector3(3),
-		stack.get_vector2(4), stack.get_vector2(5), stack.get_vector2(6), stack.get_color4(7));
+	stack.get_gui(1)->image_uv(stack.get_vector2(2)
+		, stack.get_vector2(3)
+		, stack.get_vector2(4)
+		, stack.get_vector2(5)
+		, stack.get_resource_id(6)
+		, stack.get_color4(7)
+		);
 	return 0;
 }
 
-static int gui_draw_text(lua_State* L)
+static int gui_text(lua_State* L)
 {
 	LuaStack stack(L);
-	stack.get_gui(1)->draw_text(stack.get_string(2), stack.get_string(3), stack.get_int(4),
-		stack.get_vector3(5), stack.get_color4(6));
+	stack.get_gui(1)->text(stack.get_vector2(2)
+		, stack.get_int(3)
+		, stack.get_string(4)
+		, stack.get_resource_id(5)
+		, stack.get_resource_id(6)
+		, stack.get_color4(7)
+		);
 	return 0;
 }
 
@@ -3115,6 +3146,8 @@ void load_api(LuaEnvironment& env)
 	env.add_module_function("World", "set_sound_volume",                world_set_sound_volume);
 	env.add_module_function("World", "create_debug_line",               world_create_debug_line);
 	env.add_module_function("World", "destroy_debug_line",              world_destroy_debug_line);
+	env.add_module_function("World", "create_screen_gui",               world_create_screen_gui);
+	env.add_module_function("World", "destroy_gui",                     world_destroy_gui);
 	env.add_module_function("World", "load_level",                      world_load_level);
 	env.add_module_function("World", "scene_graph",                     world_scene_graph);
 	env.add_module_function("World", "render_world",                    world_render_world);
@@ -3261,13 +3294,13 @@ void load_api(LuaEnvironment& env)
 	env.add_module_function("Material", "set_vector2", material_set_vector2);
 	env.add_module_function("Material", "set_vector3", material_set_vector3);
 
-	env.add_module_function("Gui", "resolution",     gui_resolution);
-	env.add_module_function("Gui", "move",           gui_move);
-	env.add_module_function("Gui", "screen_to_gui",  gui_screen_to_gui);
-	env.add_module_function("Gui", "draw_rectangle", gui_draw_rectangle);
-	env.add_module_function("Gui", "draw_image",     gui_draw_image);
-	env.add_module_function("Gui", "draw_image_uv",  gui_draw_image_uv);
-	env.add_module_function("Gui", "draw_text",      gui_draw_text);
+	env.add_module_function("Gui", "resolution",    gui_resolution);
+	env.add_module_function("Gui", "move",          gui_move);
+	env.add_module_function("Gui", "screen_to_gui", gui_screen_to_gui);
+	env.add_module_function("Gui", "rect",          gui_rect);
+	env.add_module_function("Gui", "image",         gui_image);
+	env.add_module_function("Gui", "image_uv",      gui_image_uv);
+	env.add_module_function("Gui", "text",          gui_text);
 
 	env.add_module_function("Display", "modes",    display_modes);
 	env.add_module_function("Display", "set_mode", display_set_mode);

+ 251 - 241
src/world/gui.cpp

@@ -9,122 +9,122 @@
 #include "material_manager.h"
 #include "material_resource.h"
 #include "matrix4x4.h"
+#include "resource_manager.h"
+#include "string_utils.h"
+#include "utf8.h"
 #include "vector2.h"
 #include "vector3.h"
 #include <bgfx/bgfx.h>
 
 namespace crown
 {
-struct VertexData
+Gui::Gui(ResourceManager& rm, ShaderManager& sm, MaterialManager& mm, u16 width, u16 height)
+	: _resource_manager(&rm)
+	, _shader_manager(&sm)
+	, _material_manager(&mm)
+	, _width(width)
+	, _height(height)
+	, _projection(MATRIX4X4_IDENTITY)
+	, _world(MATRIX4X4_IDENTITY)
 {
-	f32 x;
-	f32 y;
-	f32 u;
-	f32 v;
-};
+	orthographic(_projection, 0, width, 0, height, -0.01f, 100.0f);
 
-struct IndexData
-{
-	u16 a;
-	u16 b;
-};
-
-#define UTF8_ACCEPT 0
-
-static const u8 s_utf8d[364] =
-{
-	// The first part of the table maps bytes to character classes that
-	// to reduce the size of the transition table and create bitmasks.
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
-	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-	8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-	10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
-
-	// The second part is a transition table that maps a combination
-	// of a state of the automaton and a character class to a state.
-	 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
-	12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
-	12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
-	12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
-	12,36,12,12,12,12,12,12,12,12,12,12
-};
-
-static u32 utf8_decode(u32* state, u32* code_point, u8 character)
-{
-	u32 byte = character;
-	u32 type = s_utf8d[byte];
-
-	*code_point = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*code_point << 6) : (0xff >> type) & (byte);
-	*state = s_utf8d[256 + *state + type];
-
-	return *state;
-}
-
-bgfx::VertexDecl Gui::s_pos_col;
-bgfx::VertexDecl Gui::s_pos_col_tex;
-
-void Gui::init()
-{
-	Gui::s_pos_col
-		.begin()
-		.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
-		.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
-		.end();
-
-	Gui::s_pos_col_tex
+	_pos_tex_col
 		.begin()
-		.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
+		.add(bgfx::Attrib::Position,  3, bgfx::AttribType::Float)
 		.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, true)
-		.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
+		.add(bgfx::Attrib::Color0,    4, bgfx::AttribType::Uint8, true)
 		.end();
 }
 
-Gui::Gui(u16 width, u16 height, const char* material)
-	: m_width(width)
-	, m_height(height)
-	, m_pose(MATRIX4X4_IDENTITY)
-{
-	orthographic(m_projection, 0, width, 0, height, -0.01f, 100.0f);
-}
-
 Vector2 Gui::resolution() const
 {
-	return vector2(m_width, m_height);
+	return vector2(_width, _height);
 }
 
 void Gui::move(const Vector2& pos)
 {
-	set_identity(m_pose);
-	set_translation(m_pose, vector3(pos.x, pos.y, 0));
+	set_identity(_world);
+	set_translation(_world, vector3(pos.x, pos.y, 0));
 }
 
 Vector2 Gui::screen_to_gui(const Vector2& pos)
 {
-	return vector2(pos.x, m_height - pos.y);
+	return vector2(pos.x, _height - pos.y);
 }
 
-void Gui::draw_rectangle(const Vector3& pos, const Vector2& size, const Color4& color)
+void Gui::triangle(const Vector3& a, const Vector3& b, const Vector3& c, StringId64 material, const Color4& color)
 {
 	bgfx::TransientVertexBuffer tvb;
 	bgfx::TransientIndexBuffer tib;
-	bgfx::allocTransientVertexBuffer(&tvb, 4, Gui::s_pos_col);
+	bgfx::allocTransientVertexBuffer(&tvb, 3, _pos_tex_col);
+	bgfx::allocTransientIndexBuffer(&tib, 3);
+
+	VertexData* vd = (VertexData*)tvb.data;
+	vd[0].pos.x = a.x;
+	vd[0].pos.y = a.y;
+	vd[0].pos.z = a.z;
+	vd[0].uv.x  = 0.0f;
+	vd[0].uv.y  = 0.0f;
+	vd[0].col   = to_abgr(color);
+
+	vd[1].pos.x = b.x;
+	vd[1].pos.y = b.y;
+	vd[1].pos.z = b.z;
+	vd[1].uv.x  = 1.0f;
+	vd[1].uv.y  = 0.0f;
+	vd[1].col   = to_abgr(color);
+
+	vd[2].pos.x = c.x;
+	vd[2].pos.y = c.y;
+	vd[2].pos.z = c.z;
+	vd[2].uv.x  = 1.0f;
+	vd[2].uv.y  = 1.0f;
+	vd[2].col   = to_abgr(color);
+
+	u16* inds = (u16*)tib.data;
+	inds[0] = 0;
+	inds[1] = 1;
+	inds[2] = 2;
+}
+
+void Gui::rect3d(const Vector3& pos, const Vector2& size, StringId64 material, const Color4& color)
+{
+	bgfx::TransientVertexBuffer tvb;
+	bgfx::TransientIndexBuffer tib;
+	bgfx::allocTransientVertexBuffer(&tvb, 4, _pos_tex_col);
 	bgfx::allocTransientIndexBuffer(&tib, 6);
 
-	f32* verts = (f32*) tvb.data;
-	verts[0] = pos.x;
-	verts[1] = pos.y;
-	verts[2] = pos.x + size.x;
-	verts[3] = pos.y;
-	verts[4] = pos.x + size.x;
-	verts[5] = pos.y + size.y;
-	verts[6] = pos.x;
-	verts[7] = pos.y + size.y;
-
-	u16* inds = (u16*) tib.data;
+	VertexData* vd = (VertexData*)tvb.data;
+	vd[0].pos.x = pos.x;
+	vd[0].pos.y = pos.y;
+	vd[0].pos.z = pos.z;
+	vd[0].uv.x  = 0.0f;
+	vd[0].uv.y  = 1.0f;
+	vd[0].col   = to_abgr(color);
+
+	vd[1].pos.x = pos.x + size.x;
+	vd[1].pos.y = pos.y;
+	vd[1].pos.z = pos.z;
+	vd[1].uv.x  = 1.0f;
+	vd[1].uv.y  = 1.0f;
+	vd[1].col   = to_abgr(color);
+
+	vd[2].pos.x = pos.x + size.x;
+	vd[2].pos.y = pos.y + size.y;
+	vd[2].pos.z = pos.z;
+	vd[2].uv.x  = 1.0f;
+	vd[2].uv.y  = 0.0f;
+	vd[2].col   = to_abgr(color);
+
+	vd[3].pos.x = pos.x;
+	vd[3].pos.y = pos.y + size.y;
+	vd[3].pos.z = pos.z;
+	vd[3].uv.x  = 0.0f;
+	vd[3].uv.y  = 0.0f;
+	vd[3].col   = to_abgr(color);
+
+	u16* inds = (u16*)tib.data;
 	inds[0] = 0;
 	inds[1] = 1;
 	inds[2] = 2;
@@ -132,47 +132,55 @@ void Gui::draw_rectangle(const Vector3& pos, const Vector2& size, const Color4&
 	inds[4] = 2;
 	inds[5] = 3;
 
-	bgfx::setViewTransform(1, to_float_ptr(MATRIX4X4_IDENTITY), to_float_ptr(m_projection));
-	bgfx::setViewRect(1, 0, 0, m_width, m_height);
-	bgfx::setState(BGFX_STATE_DEFAULT);
 	bgfx::setVertexBuffer(&tvb);
 	bgfx::setIndexBuffer(&tib);
+	bgfx::setTransform(to_float_ptr(_projection));
+	_material_manager->create_material(material);
+	_material_manager->get(material)->bind(*_resource_manager, *_shader_manager, 2);
 }
 
-void Gui::draw_image(const char* material, const Vector3& pos, const Vector2& size, const Color4& color)
+void Gui::rect(const Vector2& pos, const Vector2& size, StringId64 material, const Color4& color)
 {
-	draw_image_uv(material, pos, size, vector2(0, 0), vector2(1, 1), color);
+	rect3d(vector3(pos.x, pos.y, 0.0f), size, material, color);
 }
 
-void Gui::draw_image_uv(const char* material, const Vector3& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, const Color4& color)
+void Gui::image_uv3d(const Vector3& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, StringId64 material, const Color4& color)
 {
 	bgfx::TransientVertexBuffer tvb;
 	bgfx::TransientIndexBuffer tib;
-	bgfx::allocTransientVertexBuffer(&tvb, 4, Gui::s_pos_col_tex);
+	bgfx::allocTransientVertexBuffer(&tvb, 4, _pos_tex_col);
 	bgfx::allocTransientIndexBuffer(&tib, 6);
 
-	f32* verts = (f32*) tvb.data;
-	verts[0] = pos.x;
-	verts[1] = pos.y;
-	verts[2] = uv0.x;
-	verts[3] = uv0.y;
-
-	verts[4] = pos.x + size.x;
-	verts[5] = pos.y;
-	verts[6] = uv1.x;
-	verts[7] = uv0.y;
-
-	verts[8] = pos.x + size.x;
-	verts[9] = pos.y + size.y;
-	verts[10] = uv1.x;
-	verts[11] = uv1.y;
-
-	verts[12] = pos.x;
-	verts[13] = pos.y + size.y;
-	verts[14] = uv0.x;
-	verts[15] = uv1.y;
-
-	u16* inds = (u16*) tib.data;
+	VertexData* vd = (VertexData*)tvb.data;
+	vd[0].pos.x = pos.x;
+	vd[0].pos.y = pos.y;
+	vd[0].pos.z = pos.z;
+	vd[0].uv.x  = 0.0f;
+	vd[0].uv.y  = 1.0f;
+	vd[0].col   = to_abgr(color);
+
+	vd[1].pos.x = pos.x + size.x;
+	vd[1].pos.y = pos.y;
+	vd[1].pos.z = pos.z;
+	vd[1].uv.x  = 1.0f;
+	vd[1].uv.y  = 1.0f;
+	vd[1].col   = to_abgr(color);
+
+	vd[2].pos.x = pos.x + size.x;
+	vd[2].pos.y = pos.y + size.y;
+	vd[2].pos.z = pos.z;
+	vd[2].uv.x  = 1.0f;
+	vd[2].uv.y  = 0.0f;
+	vd[2].col   = to_abgr(color);
+
+	vd[3].pos.x = pos.x;
+	vd[3].pos.y = pos.y + size.y;
+	vd[3].pos.z = pos.z;
+	vd[3].uv.x  = 0.0f;
+	vd[3].uv.y  = 0.0f;
+	vd[3].col   = to_abgr(color);
+
+	u16* inds = (u16*)tib.data;
 	inds[0] = 0;
 	inds[1] = 1;
 	inds[2] = 2;
@@ -180,137 +188,139 @@ void Gui::draw_image_uv(const char* material, const Vector3& pos, const Vector2&
 	inds[4] = 2;
 	inds[5] = 3;
 
-	bgfx::setViewTransform(1, to_float_ptr(MATRIX4X4_IDENTITY), to_float_ptr(m_projection));
-	bgfx::setViewRect(1, 0, 0, m_width, m_height);
-	bgfx::setState(BGFX_STATE_DEFAULT);
 	bgfx::setVertexBuffer(&tvb);
 	bgfx::setIndexBuffer(&tib);
 }
 
-void Gui::draw_text(const char* str, const char* font, u32 font_size, const Vector3& pos, const Color4& color)
+void Gui::image_uv(const Vector2& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, StringId64 material, const Color4& color)
+{
+	image_uv3d(vector3(pos.x, pos.y, 0.0f), size, uv0, uv1, material, color);
+}
+
+void Gui::image3d(const Vector3& pos, const Vector2& size, StringId64 material, const Color4& color)
+{
+	image_uv3d(pos, size, VECTOR2_ZERO, VECTOR2_ONE, material, color);
+}
+
+void Gui::image(const Vector2& pos, const Vector2& size, StringId64 material, const Color4& color)
+{
+	image3d(vector3(pos.x, pos.y, 0.0f), size, material, color);
+}
+
+void Gui::text3d(const Vector3& pos, u32 font_size, const char* str, StringId64 font, StringId64 material, const Color4& color)
+{
+	const FontResource* fr = (FontResource*)_resource_manager->get(RESOURCE_TYPE_FONT, font);
+	const f32 scale = (f32)font_size / (f32)fr->font_size;
+	const u32 len = strlen32(str);
+
+	bgfx::TransientVertexBuffer tvb;
+	bgfx::TransientIndexBuffer tib;
+	bgfx::allocTransientVertexBuffer(&tvb, 4 * len, _pos_tex_col);
+	bgfx::allocTransientIndexBuffer(&tib, 6 * len);
+
+	u16 index = 0;
+	f32 x_pen_advance = 0.0f;
+	f32 y_pen_advance = 0.0f;
+
+	Vector2 m_pen;
+
+	u32 state = 0;
+	u32 code_point = 0;
+	for (u32 i = 0; i < len; i++)
+	{
+		switch (str[i])
+		{
+			case '\n':
+			{
+				x_pen_advance = 0.0f;
+				y_pen_advance -= fr->font_size;
+				continue;
+			}
+			case '\t':
+			{
+				x_pen_advance += font_size * 4;
+				continue;
+			}
+		}
+
+		if (utf8::decode(&state, &code_point, str[i]) == UTF8_ACCEPT)
+		{
+			const GlyphData& g = *font_resource::get_glyph(fr, code_point);
+
+			const f32 baseline = g.height - g.y_offset;
+
+			// Set pen position
+			m_pen.x = pos.x + g.x_offset;
+			m_pen.y = pos.y - baseline;
+
+			// Position coords
+			const f32 x0 = (m_pen.x + x_pen_advance) * scale;
+			const f32 y0 = (m_pen.y + y_pen_advance) * scale;
+			const f32 x1 = (m_pen.x + g.width + x_pen_advance) * scale;
+			const f32 y1 = (m_pen.y + g.height + y_pen_advance) * scale;
+
+			// Texture coords
+			const f32 u0 = g.x / fr->texture_size;
+			const f32 v1 = g.y / fr->texture_size; // Upper-left char corner
+			const f32 u1 = u0 + g.width  / fr->texture_size;
+			const f32 v0 = v1 + g.height / fr->texture_size; // Bottom-left char corner
+
+			// Fill vertex buffer
+			VertexData* vd = (VertexData*)&tvb.data[i*4*sizeof(VertexData)];
+			vd[0].pos.x = x0;
+			vd[0].pos.y = y0;
+			vd[0].pos.z = pos.z;
+			vd[0].uv.x  = u0;
+			vd[0].uv.y  = v0;
+			vd[0].col   = to_abgr(color);
+
+			vd[1].pos.x = x1;
+			vd[1].pos.y = y0;
+			vd[1].pos.z = pos.z;
+			vd[1].uv.x  = u1;
+			vd[1].uv.y  = v0;
+			vd[1].col   = to_abgr(color);
+
+			vd[2].pos.x = x1;
+			vd[2].pos.y = y1;
+			vd[2].pos.z = pos.z;
+			vd[2].uv.x  = u1;
+			vd[2].uv.y  = v1;
+			vd[2].col   = to_abgr(color);
+
+			vd[3].pos.x = x0;
+			vd[3].pos.y = y1;
+			vd[3].pos.z = pos.z;
+			vd[3].uv.x  = u0;
+			vd[3].uv.y  = v1;
+			vd[3].col   = to_abgr(color);
+
+			// Fill index buffer
+			u16* inds = (u16*)&tib.data[i*6*sizeof(u16)];
+			inds[0] = index + 0;
+			inds[1] = index + 1;
+			inds[2] = index + 2;
+			inds[3] = index + 0;
+			inds[4] = index + 2;
+			inds[5] = index + 3;
+
+			// Advance pen position
+			x_pen_advance += g.x_advance;
+
+			index += 4;
+		}
+	}
+
+	bgfx::setVertexBuffer(&tvb);
+	bgfx::setIndexBuffer(&tib);
+	bgfx::setTransform(to_float_ptr(_projection));
+	_material_manager->create_material(material);
+	_material_manager->get(material)->bind(*_resource_manager, *_shader_manager, 2);
+}
+
+void Gui::text(const Vector2& pos, u32 font_size, const char* str, StringId64 font, StringId64 material, const Color4& color)
 {
-	// Renderer* r = device()->renderer();
-
-	// const FontResource* resource = (FontResource*) device()->resource_manager()->get("font", font);
-	// Vector2 m_pen;
-
-	// const f32 scale = ((f32)font_size / (f32)resource->font_size());
-	// const u32 str_len = strlen32(str);
-
-	// TransientVertexBuffer vb;
-	// TransientIndexBuffer ib;
-
-	// r->reserve_transient_vertex_buffer(&vb, 4 * str_len, VertexFormat::P2_T2);
-	// r->reserve_transient_index_buffer(&ib, 6 * str_len);
-
-	// u16 index = 0;
-	// f32 x_pen_advance = 0.0f;
-	// f32 y_pen_advance = 0.0f;
-
-	// u32 state = 0;
-	// u32 code_point = 0;
-	// for (u32 i = 0; i < str_len; i++)
-	// {
-	// 	switch (str[i])
-	// 	{
-	// 		case '\n':
-	// 		{
-	// 			x_pen_advance = 0.0f;
-	// 			y_pen_advance -= resource->font_size();
-	// 			continue;
-	// 		}
-	// 		case '\t':
-	// 		{
-	// 			x_pen_advance += font_size * 4;
-	// 			continue;
-	// 		}
-	// 	}
-
-	// 	if (utf8_decode(&state, &code_point, str[i]) == UTF8_ACCEPT)
-	// 	{
-	// 		FontGlyphData g = resource->get_glyph(code_point);
-
-	// 		const f32 baseline = g.height - g.y_offset;
-
-	// 		// Set pen position
-	// 		m_pen.x = pos.x + g.x_offset;
-	// 		m_pen.y = pos.y - baseline;
-
-	// 		// Position coords
-	// 		const f32 x0 = (m_pen.x + x_pen_advance) * scale;
-	// 		const f32 y0 = (m_pen.y + y_pen_advance) * scale;
-	// 		const f32 x1 = (m_pen.x + g.width + x_pen_advance) * scale;
-	// 		const f32 y1 = (m_pen.y + g.height + y_pen_advance) * scale;
-
-	// 		// Texture coords
-	// 		const f32 u0 = (f32) g.x / 512;
-	// 		const f32 v0 = (f32) g.y / 512;
-	// 		const f32 u1 = u0 + ((f32) g.width) / 512;
-	// 		const f32 v1 = v0 - ((f32) g.height) / 512;
-
-	// 		// Fill vertex buffer
-	// 		(*(VertexData*)(vb.data)).x		= x0;
-	// 		(*(VertexData*)(vb.data)).y		= y0;
-	// 		(*(VertexData*)(vb.data)).u		= u0;
-	// 		(*(VertexData*)(vb.data)).v		= v1;
-	// 		vb.data += sizeof(VertexData);
-
-	// 		(*(VertexData*)(vb.data)).x		= x1;
-	// 		(*(VertexData*)(vb.data)).y		= y0;
-	// 		(*(VertexData*)(vb.data)).u		= u1;
-	// 		(*(VertexData*)(vb.data)).v		= v1;
-	// 		vb.data += sizeof(VertexData);
-
-	// 		(*(VertexData*)(vb.data)).x		= x1;
-	// 		(*(VertexData*)(vb.data)).y		= y1;
-	// 		(*(VertexData*)(vb.data)).u		= u1;
-	// 		(*(VertexData*)(vb.data)).v		= v0;
-	// 		vb.data += sizeof(VertexData);
-
-	// 		(*(VertexData*)(vb.data)).x		= x0;
-	// 		(*(VertexData*)(vb.data)).y		= y1;
-	// 		(*(VertexData*)(vb.data)).u		= u0;
-	// 		(*(VertexData*)(vb.data)).v		= v0;
-	// 		vb.data += sizeof(VertexData);
-
-	// 		// Fill index buffer
-	// 		(*(IndexData*)(ib.data)).a		= index;
-	// 		(*(IndexData*)(ib.data)).b		= index + 1;
-	// 		ib.data += sizeof(IndexData);
-
-	// 		(*(IndexData*)(ib.data)).a		= index + 2;
-	// 		(*(IndexData*)(ib.data)).b		= index;
-	// 		ib.data += sizeof(IndexData);
-
-	// 		(*(IndexData*)(ib.data)).a		= index + 2;
-	// 		(*(IndexData*)(ib.data)).b		= index + 3;
-	// 		ib.data += sizeof(IndexData);
-
-	// 		// Advance pen position
-	// 		x_pen_advance += g.x_advance;
-
-	// 		index += 4;
-	// 	}
-	// }
-
-	// const MaterialResource* mr = (MaterialResource*) device()->resource_manager()->get(resource->material());
-	// const TextureResource* tr = (TextureResource*) device()->resource_manager()->get(mr->get_texture_layer(0));
-
-	// r->set_layer_view(1, matrix4x4::IDENTITY);
-	// r->set_layer_projection(1, m_projection);
-	// r->set_layer_viewport(1, 0, 0, 1000, 625);
-	// r->set_state(STATE_COLOR_WRITE
-	// 				| STATE_CULL_CW
-	// 				| STATE_BLEND_EQUATION_ADD
-	// 				| STATE_BLEND_FUNC(STATE_BLEND_FUNC_SRC_ALPHA, STATE_BLEND_FUNC_ONE_MINUS_SRC_ALPHA));
-	// r->set_pose(m_pose);
-	// r->set_program(render_world_globals::default_font_program());
-	// r->set_texture(0, render_world_globals::default_font_uniform(), tr->texture(),
-	// 				TEXTURE_FILTER_LINEAR | TEXTURE_WRAP_U_CLAMP_REPEAT | TEXTURE_WRAP_V_CLAMP_REPEAT);
-	// r->set_uniform(render_world_globals::default_color_uniform(), UniformType::FLOAT_4, color4::to_float_ptr(color), 1);
-	// r->set_vertex_buffer(vb);
-	// r->set_index_buffer(ib);
-	// r->commit(1, (s32) pos.z);
+	text3d(vector3(pos.x, pos.y, 0.0f), font_size, str, font, material, color);
 }
 
 } // namespace crown

+ 34 - 34
src/world/gui.h

@@ -5,57 +5,57 @@
 
 #pragma once
 
-#include "color4.h"
-#include "material.h"
 #include "math_types.h"
 #include "world_types.h"
+#include "resource_types.h"
 #include <bgfx/bgfx.h>
 
 namespace crown
 {
-class RenderWorld;
-
-/// Manages the rendering of GUI objects.
+/// Immediate mode Gui.
 ///
 /// @ingroup World
 struct Gui
 {
-	Gui(u16 width, u16 height, const char* material);
+	struct VertexData
+	{
+		Vector3 pos;
+		Vector2 uv;
+		u32 col;
+	};
+
+	struct IndexData
+	{
+		u16 a;
+		u16 b;
+	};
+
+	ResourceManager* _resource_manager;
+	ShaderManager* _shader_manager;
+	MaterialManager* _material_manager;
+	u16 _width;
+	u16 _height;
+	Matrix4x4 _projection;
+	Matrix4x4 _world;
+	bgfx::VertexDecl _pos_tex_col;
+
+	Gui(ResourceManager& rm, ShaderManager& sm, MaterialManager& mm, u16 width, u16 height);
 
 	Vector2 resolution() const;
 	void move(const Vector2& pos);
 
 	Vector2 screen_to_gui(const Vector2& pos);
 
-	/// Draws a rectangle of size @a size at @a pos.
-	/// @note Higher values of pos.z make the object appear in front of other objects.
-	void draw_rectangle(const Vector3& pos, const Vector2& size, const Color4& color = COLOR4_WHITE);
-
-	/// Draws an image with the given @a material.
-	/// @note Higher values of pos.z make the object appear in front of other objects.
-	void draw_image(const char* material, const Vector3& pos, const Vector2& size, const Color4& color = COLOR4_WHITE);
-
-	/// Draws an image with the given @a material and @a uv0 and @a uv1 coordinates.
-	/// @note Higher values of pos.z make the object appear in front of other objects.
-	void draw_image_uv(const char* material, const Vector3& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, const Color4& color = COLOR4_WHITE);
-
-	/// Draws the text @a str with the given @a font and @a font_size.
-	/// @note Higher values of pos.z make the object appear in front of other objects.
-	void draw_text(const char* str, const char* font, u32 font_size, const Vector3& pos, const Color4& color = COLOR4_WHITE);
-
-public:
-
-	u16 m_width;
-	u16 m_height;
-	Matrix4x4 m_projection;
-	Matrix4x4 m_pose;
-
-	static void init();
-
-private:
+	void triangle(const Vector3& a, const Vector3& b, const Vector3& c, StringId64 material, const Color4& color);
 
-	static bgfx::VertexDecl s_pos_col;
-	static bgfx::VertexDecl s_pos_col_tex;
+	void rect3d(const Vector3& pos, const Vector2& size, StringId64 material, const Color4& color);
+	void rect(const Vector2& pos, const Vector2& size, StringId64 material, const Color4& color);
+	void image_uv3d(const Vector3& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, StringId64 material, const Color4& color);
+	void image_uv(const Vector2& pos, const Vector2& size, const Vector2& uv0, const Vector2& uv1, StringId64 material, const Color4& color);
+	void image3d(const Vector3& pos, const Vector2& size, StringId64 material, const Color4& color);
+	void image(const Vector2& pos, const Vector2& size, StringId64 material, const Color4& color);
+	void text3d(const Vector3& pos, u32 font_size, const char* str, StringId64 font, StringId64 material, const Color4& color);
+	void text(const Vector2& pos, u32 font_size, const char* str, StringId64 font, StringId64 material, const Color4& color);
 };
 
 } // namespace crown

+ 18 - 0
src/world/world.cpp

@@ -5,6 +5,7 @@
 
 #include "debug_line.h"
 #include "error.h"
+#include "gui.h"
 #include "hash.h"
 #include "level.h"
 #include "lua_environment.h"
@@ -27,6 +28,8 @@ World::World(Allocator& a, ResourceManager& rm, ShaderManager& sm, MaterialManag
 	: _marker(MARKER)
 	, _allocator(&a)
 	, _resource_manager(&rm)
+	, _shader_manager(&sm)
+	, _material_manager(&mm)
 	, _lua_environment(&env)
 	, _unit_manager(&um)
 	, _lines(NULL)
@@ -520,6 +523,21 @@ void World::destroy_debug_line(DebugLine& line)
 	CE_DELETE(*_allocator, &line);
 }
 
+Gui* World::create_screen_gui(f32 scale_w, f32 scale_h)
+{
+	return CE_NEW(*_allocator, Gui)(*_resource_manager
+		, *_shader_manager
+		, *_material_manager
+		, 1280
+		, 720
+		);
+}
+
+void World::destroy_gui(Gui& gui)
+{
+	CE_DELETE(*_allocator, &gui);
+}
+
 Level* World::load_level(const LevelResource& lr, const Vector3& pos, const Quaternion& rot)
 {
 	Level* level = CE_NEW(*_allocator, Level)(*_allocator, *this, lr);

+ 8 - 0
src/world/world.h

@@ -143,6 +143,12 @@ public:
 	/// Destroys the debug @a line.
 	void destroy_debug_line(DebugLine& line);
 
+	/// Creates a new screen-space Gui.
+	Gui* create_screen_gui(f32 scale_w, f32 scale_h);
+
+	/// Destroys the @a gui.
+	void destroy_gui(Gui& gui);
+
 	/// Loads the level @a name into the world.
 	Level* load_level(const LevelResource& lr, const Vector3& pos, const Quaternion& rot);
 	Level* load_level(StringId64 name, const Vector3& pos, const Quaternion& rot);
@@ -205,6 +211,8 @@ private:
 
 	Allocator* _allocator;
 	ResourceManager* _resource_manager;
+	ShaderManager* _shader_manager;
+	MaterialManager* _material_manager;
 	LuaEnvironment* _lua_environment;
 	UnitManager* _unit_manager;