added text widget parsing and rendering
This commit is contained in:
@@ -57,9 +57,9 @@
|
|||||||
</border>
|
</border>
|
||||||
</plane>
|
</plane>
|
||||||
<!-- content panel -->
|
<!-- content panel -->
|
||||||
<plane width="1" grow="1" height="100%" pad="10" wrap="1">
|
<border width="1" grow="1" height="100%" pad="10" wrap="1">
|
||||||
<ref id="rounded-inside"/>
|
<text text="hello widget" font-face="arial" font-size="11" width="100" height="100"/>
|
||||||
</plane>
|
</border>
|
||||||
</plane>
|
</plane>
|
||||||
<!-- status bar -->
|
<!-- status bar -->
|
||||||
<border height="30" width="100%" color=".15" border-color=".3" />
|
<border height="30" width="100%" color=".15" border-color=".3" />
|
||||||
|
|||||||
@@ -93,6 +93,14 @@ void App::init()
|
|||||||
glEnable(GL_DEBUG_OUTPUT);
|
glEnable(GL_DEBUG_OUTPUT);
|
||||||
#endif
|
#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.load("data/layout.xml");
|
||||||
//layout["main"].update(width, height);
|
//layout["main"].update(width, height);
|
||||||
|
|
||||||
@@ -106,13 +114,8 @@ void App::init()
|
|||||||
if (!tex.load("data/uvs.jpg"))
|
if (!tex.load("data/uvs.jpg"))
|
||||||
printf("error loading image\n");
|
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.create();
|
||||||
|
text.update(kFont::Arial_11, "hello font");
|
||||||
plane.create<1>(400, 400);
|
plane.create<1>(400, 400);
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
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 proj = glm::ortho(0.f, width, height, 0.f, -1.f, 1.f);
|
||||||
glm::mat4 tran = glm::translate(glm::vec3(200, 200, 0));
|
glm::mat4 tran = glm::translate(glm::vec3(200, 200, 0));
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
font_tex.bind();
|
|
||||||
sampler.bind(0);
|
|
||||||
ShaderManager::use(kShader::Font);
|
ShaderManager::use(kShader::Font);
|
||||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
ShaderManager::u_mat4(kShaderUniform::MVP, proj*tran);
|
ShaderManager::u_mat4(kShaderUniform::MVP, proj * tran);
|
||||||
|
text.draw();
|
||||||
// plane.draw_fill();
|
|
||||||
glBindVertexArray(font_array);
|
|
||||||
glDrawElements(GL_TRIANGLES, font_array_count, GL_UNSIGNED_SHORT, 0);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
font_tex.unbind();
|
|
||||||
sampler.unbind();
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static int i = 0;
|
static int i = 0;
|
||||||
i = (i + 1) % 32;
|
i = (i + 1) % 32;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
std::map<kFont, Font> FontManager::m_fonts;
|
std::map<kFont, Font> FontManager::m_fonts;
|
||||||
|
Sampler FontManager::m_sampler;
|
||||||
|
|
||||||
bool Font::load(const char* ttf)
|
bool Font::load(const char* ttf)
|
||||||
{
|
{
|
||||||
@@ -24,6 +26,11 @@ bool Font::load(const char* ttf)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FontManager::init()
|
||||||
|
{
|
||||||
|
m_sampler.create();
|
||||||
|
}
|
||||||
|
|
||||||
bool FontManager::load(kFont id, const char *ttf)
|
bool FontManager::load(kFont id, const char *ttf)
|
||||||
{
|
{
|
||||||
return m_fonts[id].load(ttf);
|
return m_fonts[id].load(ttf);
|
||||||
@@ -52,24 +59,23 @@ bool TextMesh::create()
|
|||||||
|
|
||||||
void TextMesh::update(kFont id, const char* text)
|
void TextMesh::update(kFont id, const char* text)
|
||||||
{
|
{
|
||||||
|
font_id = id;
|
||||||
auto& f = FontManager::get(id);
|
auto& f = FontManager::get(id);
|
||||||
if (f.chars.size())
|
if (f.chars.size())
|
||||||
{
|
{
|
||||||
static char str[64];
|
const auto len = strlen(text);
|
||||||
static int counter = 0;
|
|
||||||
counter++;
|
|
||||||
sprintf(str, "frame %04d", counter);
|
|
||||||
const auto len = strlen(str);
|
|
||||||
float x = 0;
|
float x = 0;
|
||||||
float y = 0;
|
float y = 0;
|
||||||
std::vector<glm::vec4> v;
|
std::vector<glm::vec4> v;
|
||||||
std::vector<GLushort> idx;
|
std::vector<GLushort> idx;
|
||||||
|
glm::vec2 bbmin;
|
||||||
|
glm::vec2 bbmax;
|
||||||
for (int i = 0; i < len; i++)
|
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_aligned_quad q;
|
||||||
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true);
|
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.y1, q.s0, q.t1);
|
||||||
v.emplace_back(q.x0, q.y0, q.s0, q.t0);
|
v.emplace_back(q.x0, q.y0, q.s0, q.t0);
|
||||||
v.emplace_back(q.x1, q.y0, q.s1, 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+0);
|
||||||
idx.push_back(n+2);
|
idx.push_back(n+2);
|
||||||
idx.push_back(n+3);
|
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();
|
font_array_count = (int)idx.size();
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW);
|
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);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
enum class kFont : uint16_t
|
enum class kFont : uint16_t
|
||||||
{
|
{
|
||||||
Arial_11 = const_hash("arial-16"),
|
Arial_11 = const_hash("arial-11"),
|
||||||
};
|
};
|
||||||
|
|
||||||
class Font
|
class Font
|
||||||
@@ -23,8 +23,10 @@ public:
|
|||||||
|
|
||||||
class FontManager
|
class FontManager
|
||||||
{
|
{
|
||||||
static std::map<kFont, Font> m_fonts;
|
|
||||||
public:
|
public:
|
||||||
|
static std::map<kFont, Font> m_fonts;
|
||||||
|
static Sampler m_sampler;
|
||||||
|
static void init();
|
||||||
static bool load(kFont id, const char* ttf);
|
static bool load(kFont id, const char* ttf);
|
||||||
static const Font& get(kFont id);
|
static const Font& get(kFont id);
|
||||||
};
|
};
|
||||||
@@ -35,6 +37,9 @@ public:
|
|||||||
GLuint font_array = 0;
|
GLuint font_array = 0;
|
||||||
int font_array_count = 0;
|
int font_array_count = 0;
|
||||||
GLuint font_buffers[2] = {0, 0};
|
GLuint font_buffers[2] = {0, 0};
|
||||||
|
kFont font_id;
|
||||||
|
glm::vec2 bb;
|
||||||
bool create();
|
bool create();
|
||||||
void update(kFont id, const char* text);
|
void update(kFont id, const char* text);
|
||||||
|
void draw();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 scale = glm::scale(glm::vec3(m_size, 1.f));
|
||||||
glm::mat4 pos = glm::translate(glm::vec3(m_pos, 0));
|
glm::mat4 pos = glm::translate(glm::vec3(m_pos, 0));
|
||||||
m_widget->mvp = proj * pos * scale * pivot;
|
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->clip = m_clip;
|
||||||
|
m_widget->update();
|
||||||
}
|
}
|
||||||
for (auto& c : m_children)
|
for (auto& c : m_children)
|
||||||
c.update_internal(m_pos, proj);
|
c.update_internal(m_pos, proj);
|
||||||
@@ -184,6 +188,9 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
|
|||||||
case kWidget::Shape:
|
case kWidget::Shape:
|
||||||
m_widget = std::make_unique<WidgetShape>();
|
m_widget = std::make_unique<WidgetShape>();
|
||||||
break;
|
break;
|
||||||
|
case kWidget::Text:
|
||||||
|
m_widget = std::make_unique<WidgetText>();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (attr)
|
while (attr)
|
||||||
@@ -195,6 +202,9 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
|
|||||||
if (m_widget)
|
if (m_widget)
|
||||||
m_widget->create();
|
m_widget->create();
|
||||||
|
|
||||||
|
if (widget_id == kWidget::Text)
|
||||||
|
SetSize(((WidgetText*)m_widget.get())->m_text_mesh.bb);
|
||||||
|
|
||||||
auto x_child = x_node->FirstChildElement();
|
auto x_child = x_node->FirstChildElement();
|
||||||
while (x_child)
|
while (x_child)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
#include "font.h"
|
||||||
|
|
||||||
enum class kAttribute : uint16_t
|
enum class kAttribute : uint16_t
|
||||||
{
|
{
|
||||||
@@ -25,12 +26,16 @@ enum class kAttribute : uint16_t
|
|||||||
Thickness = const_hash("thickness"),
|
Thickness = const_hash("thickness"),
|
||||||
BorderColor = const_hash("border-color"),
|
BorderColor = const_hash("border-color"),
|
||||||
Type = const_hash("type"),
|
Type = const_hash("type"),
|
||||||
|
Text = const_hash("text"),
|
||||||
|
FontFace = const_hash("font-face"),
|
||||||
|
FontSize = const_hash("font-size"),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class kWidget : uint16_t
|
enum class kWidget : uint16_t
|
||||||
{
|
{
|
||||||
Border = const_hash("border"),
|
Border = const_hash("border"),
|
||||||
Shape = const_hash("shape"),
|
Shape = const_hash("shape"),
|
||||||
|
Text = const_hash("text"),
|
||||||
Ref = const_hash("ref"),
|
Ref = const_hash("ref"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,11 +51,15 @@ class Widget
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glm::mat4 mvp;
|
glm::mat4 mvp;
|
||||||
|
glm::mat4 proj;
|
||||||
|
glm::mat4 scale;
|
||||||
|
glm::mat4 pos;
|
||||||
glm::vec4 clip;
|
glm::vec4 clip;
|
||||||
virtual std::unique_ptr<Widget> clone() = 0;
|
virtual std::unique_ptr<Widget> clone() = 0;
|
||||||
virtual void create() { }
|
virtual void create() { }
|
||||||
virtual void draw() { }
|
virtual void draw() { }
|
||||||
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { }
|
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { }
|
||||||
|
virtual void update() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class WidgetRef : public Widget
|
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<Widget> 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
|
class Node
|
||||||
{
|
{
|
||||||
friend class LayoutManager;
|
friend class LayoutManager;
|
||||||
@@ -252,6 +310,7 @@ public:
|
|||||||
void SetWidthP(float value) { YGNodeStyleSetWidthPercent(y_node, value); }
|
void SetWidthP(float value) { YGNodeStyleSetWidthPercent(y_node, value); }
|
||||||
void SetHeight(float value) { YGNodeStyleSetHeight(y_node, value); }
|
void SetHeight(float value) { YGNodeStyleSetHeight(y_node, value); }
|
||||||
void SetHeightP(float value) { YGNodeStyleSetHeightPercent(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)
|
void SetPadding(float t, float r, float b, float l)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public:
|
|||||||
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
|
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
|
||||||
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
|
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
|
||||||
void update(const uint8_t* data);
|
void update(const uint8_t* data);
|
||||||
|
bool ready() const { return m_tex != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sampler
|
class Sampler
|
||||||
@@ -25,4 +26,5 @@ public:
|
|||||||
void set(GLint filter = GL_LINEAR, GLint wrap = GL_CLAMP_TO_EDGE);
|
void set(GLint filter = GL_LINEAR, GLint wrap = GL_CLAMP_TO_EDGE);
|
||||||
void bind(int unit);
|
void bind(int unit);
|
||||||
void unbind();
|
void unbind();
|
||||||
|
bool ready() const { return id != 0; }
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user