From 3cc25e759293f2bd4f4d2e883903dbeaf087f513 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Mon, 6 Feb 2017 23:32:01 +0000 Subject: [PATCH] added text widget parsing and rendering --- data/layout.xml | 6 ++--- engine/app.cpp | 31 +++++++++---------------- engine/font.cpp | 45 ++++++++++++++++++++++++++++++------ engine/font.h | 9 ++++++-- engine/layout.cpp | 10 ++++++++ engine/layout.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++ engine/texture.h | 2 ++ 7 files changed, 130 insertions(+), 32 deletions(-) diff --git a/data/layout.xml b/data/layout.xml index 41fcced..576da8a 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -57,9 +57,9 @@ - - - + + + diff --git a/engine/app.cpp b/engine/app.cpp index 67b5113..74116d2 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -93,6 +93,14 @@ void App::init() glEnable(GL_DEBUG_OUTPUT); #endif +#if _WIN32 + const char* ttf = "C:\\Windows\\Fonts\\arial.ttf"; +#else + const char* ttf = "/Library/Fonts/Arial.ttf"; +#endif + FontManager::init(); + FontManager::load(kFont::Arial_11, ttf); + layout.load("data/layout.xml"); //layout["main"].update(width, height); @@ -106,13 +114,8 @@ void App::init() if (!tex.load("data/uvs.jpg")) printf("error loading image\n"); -#if _WIN32 - const char* ttf = "C:\\Windows\\Fonts\\arial.ttf"; -#else - const char* ttf = "/Library/Fonts/Arial.ttf"; -#endif - FontManager::load(kFont::Arial_11, ttf); text.create(); + text.update(kFont::Arial_11, "hello font"); plane.create<1>(400, 400); glEnable(GL_TEXTURE_2D); @@ -165,22 +168,10 @@ void App::update(float dt) glm::mat4 proj = glm::ortho(0.f, width, height, 0.f, -1.f, 1.f); glm::mat4 tran = glm::translate(glm::vec3(200, 200, 0)); - glActiveTexture(GL_TEXTURE0); - font_tex.bind(); - sampler.bind(0); ShaderManager::use(kShader::Font); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_mat4(kShaderUniform::MVP, proj*tran); - -// plane.draw_fill(); - glBindVertexArray(font_array); - glDrawElements(GL_TRIANGLES, font_array_count, GL_UNSIGNED_SHORT, 0); - glBindVertexArray(0); - - font_tex.unbind(); - sampler.unbind(); - - + ShaderManager::u_mat4(kShaderUniform::MVP, proj * tran); + text.draw(); /* static int i = 0; i = (i + 1) % 32; diff --git a/engine/font.cpp b/engine/font.cpp index 7df9a81..9d5469d 100644 --- a/engine/font.cpp +++ b/engine/font.cpp @@ -1,7 +1,9 @@ #include "pch.h" #include "font.h" +#include "shader.h" std::map FontManager::m_fonts; +Sampler FontManager::m_sampler; bool Font::load(const char* ttf) { @@ -24,6 +26,11 @@ bool Font::load(const char* ttf) return false; } +void FontManager::init() +{ + m_sampler.create(); +} + bool FontManager::load(kFont id, const char *ttf) { return m_fonts[id].load(ttf); @@ -52,24 +59,23 @@ bool TextMesh::create() void TextMesh::update(kFont id, const char* text) { + font_id = id; auto& f = FontManager::get(id); if (f.chars.size()) { - static char str[64]; - static int counter = 0; - counter++; - sprintf(str, "frame %04d", counter); - const auto len = strlen(str); + const auto len = strlen(text); float x = 0; float y = 0; std::vector v; std::vector idx; + glm::vec2 bbmin; + glm::vec2 bbmax; for (int i = 0; i < len; i++) { - int c = str[i] - f.start_char; + int c = text[i] - f.start_char; stbtt_aligned_quad q; stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true); - auto n = v.size(); + auto n = (int)v.size(); v.emplace_back(q.x0, q.y1, q.s0, q.t1); v.emplace_back(q.x0, q.y0, q.s0, q.t0); v.emplace_back(q.x1, q.y0, q.s1, q.t0); @@ -80,7 +86,14 @@ void TextMesh::update(kFont id, const char* text) idx.push_back(n+0); idx.push_back(n+2); idx.push_back(n+3); + bbmin = glm::min(bbmin, { q.x0, q.y0 }); + bbmax = glm::max(bbmax, { q.x1, q.y1 }); } + for (int i = 0; i < len*4; i++) + { + v[i] -= glm::vec4(bbmin, 0, 0); + } + bb = bbmax - bbmin; font_array_count = (int)idx.size(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW); @@ -90,3 +103,21 @@ void TextMesh::update(kFont id, const char* text) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } + +void TextMesh::draw() +{ + auto& f = FontManager::get(font_id); + if (f.font_tex.ready()) + { + glActiveTexture(GL_TEXTURE0); + f.font_tex.bind(); + FontManager::m_sampler.bind(0); + + glBindVertexArray(font_array); + glDrawElements(GL_TRIANGLES, font_array_count, GL_UNSIGNED_SHORT, 0); + glBindVertexArray(0); + + f.font_tex.unbind(); + FontManager::m_sampler.unbind(); + } +} diff --git a/engine/font.h b/engine/font.h index 269340c..7835354 100644 --- a/engine/font.h +++ b/engine/font.h @@ -4,7 +4,7 @@ enum class kFont : uint16_t { - Arial_11 = const_hash("arial-16"), + Arial_11 = const_hash("arial-11"), }; class Font @@ -23,8 +23,10 @@ public: class FontManager { - static std::map m_fonts; public: + static std::map m_fonts; + static Sampler m_sampler; + static void init(); static bool load(kFont id, const char* ttf); static const Font& get(kFont id); }; @@ -35,6 +37,9 @@ public: GLuint font_array = 0; int font_array_count = 0; GLuint font_buffers[2] = {0, 0}; + kFont font_id; + glm::vec2 bb; bool create(); void update(kFont id, const char* text); + void draw(); }; diff --git a/engine/layout.cpp b/engine/layout.cpp index 396a74f..6161441 100644 --- a/engine/layout.cpp +++ b/engine/layout.cpp @@ -47,7 +47,11 @@ void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj) glm::mat4 scale = glm::scale(glm::vec3(m_size, 1.f)); glm::mat4 pos = glm::translate(glm::vec3(m_pos, 0)); m_widget->mvp = proj * pos * scale * pivot; + m_widget->pos = pos; + m_widget->scale = scale; + m_widget->proj = proj; m_widget->clip = m_clip; + m_widget->update(); } for (auto& c : m_children) c.update_internal(m_pos, proj); @@ -184,6 +188,9 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node) case kWidget::Shape: m_widget = std::make_unique(); break; + case kWidget::Text: + m_widget = std::make_unique(); + break; } while (attr) @@ -195,6 +202,9 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node) if (m_widget) m_widget->create(); + if (widget_id == kWidget::Text) + SetSize(((WidgetText*)m_widget.get())->m_text_mesh.bb); + auto x_child = x_node->FirstChildElement(); while (x_child) { diff --git a/engine/layout.h b/engine/layout.h index dcae025..9e461bf 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -2,6 +2,7 @@ #include "shape.h" #include "util.h" #include "shader.h" +#include "font.h" enum class kAttribute : uint16_t { @@ -25,12 +26,16 @@ enum class kAttribute : uint16_t Thickness = const_hash("thickness"), BorderColor = const_hash("border-color"), Type = const_hash("type"), + Text = const_hash("text"), + FontFace = const_hash("font-face"), + FontSize = const_hash("font-size"), }; enum class kWidget : uint16_t { Border = const_hash("border"), Shape = const_hash("shape"), + Text = const_hash("text"), Ref = const_hash("ref"), }; @@ -46,11 +51,15 @@ class Widget { public: glm::mat4 mvp; + glm::mat4 proj; + glm::mat4 scale; + glm::mat4 pos; glm::vec4 clip; virtual std::unique_ptr clone() = 0; virtual void create() { } virtual void draw() { } virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { } + virtual void update() { } }; class WidgetRef : public Widget @@ -207,6 +216,55 @@ public: } }; +class WidgetText : public Widget +{ +public: + TextMesh m_text_mesh; + std::string m_text; + std::string m_font; + int m_size; + virtual std::unique_ptr clone() override + { + return nullptr; + } + virtual void create() override + { + char font[64]; + sprintf(font, "%s-%d", m_font.c_str(), m_size); + kFont font_id = (kFont)const_hash(font); + m_text_mesh.create(); + m_text_mesh.update(font_id, m_text.c_str()); + } + virtual void draw() override + { + ShaderManager::use(kShader::Font); + ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_mat4(kShaderUniform::MVP, mvp); + m_text_mesh.draw(); + } + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override + { + switch (ka) + { + case kAttribute::Text: + m_text = attr->Value(); + break; + case kAttribute::FontFace: + m_font = attr->Value(); + break; + case kAttribute::FontSize: + m_size = attr->IntValue(); + break; + default: + break; + } + } + virtual void update() override + { + mvp = proj * pos; + } +}; + class Node { friend class LayoutManager; @@ -252,6 +310,7 @@ public: void SetWidthP(float value) { YGNodeStyleSetWidthPercent(y_node, value); } void SetHeight(float value) { YGNodeStyleSetHeight(y_node, value); } void SetHeightP(float value) { YGNodeStyleSetHeightPercent(y_node, value); } + void SetSize(glm::vec2 value) { SetWidth(value.x); SetHeight(value.y); } void SetPadding(float t, float r, float b, float l) { diff --git a/engine/texture.h b/engine/texture.h index c009cd8..165c2a8 100644 --- a/engine/texture.h +++ b/engine/texture.h @@ -14,6 +14,7 @@ public: void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); } void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } void update(const uint8_t* data); + bool ready() const { return m_tex != 0; } }; class Sampler @@ -25,4 +26,5 @@ public: void set(GLint filter = GL_LINEAR, GLint wrap = GL_CLAMP_TO_EDGE); void bind(int unit); void unbind(); + bool ready() const { return id != 0; } };