From b1abb42dd57bcb4f0370fb3e604a6ef32b66ee94 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 11 Feb 2017 01:40:40 +0000 Subject: [PATCH] big refactoring to merge node and widgets into a single node hierarchy --- engine/app.cpp | 27 ++-- engine/layout.cpp | 212 ++++++++++++++++++----------- engine/layout.h | 330 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 439 insertions(+), 130 deletions(-) diff --git a/engine/app.cpp b/engine/app.cpp index 3f299e7..cbf8a8b 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -132,8 +132,8 @@ void App::init() ShaderManager::create(kShader::UVs, shader_v, shader_uv_f); ShaderManager::create(kShader::Font, shader_font_v, shader_font_f); ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f); - WidgetBorder::init(); - WidgetImage::init(); + NodeBorder::init(); + NodeImage::init(); if (!tex.load("data/uvs.jpg")) printf("error loading image\n"); @@ -179,14 +179,14 @@ void App::update(float dt) } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_SCISSOR_TEST); + //glEnable(GL_SCISSOR_TEST); for (auto& n : layout[main_id]) { - if (n.m_display && n.m_widget) + if (n.m_display) { - auto box = n.m_widget->clip; + auto box = n.m_clip; glScissor((int)box.x, (int)(height - box.y - box.w), (int)box.z, (int)box.w); - n.m_widget->draw(); + n.draw(); } } glDisable(GL_SCISSOR_TEST); @@ -229,16 +229,25 @@ void App::resize(float w, float h) void App::mouse_down(int button, float x, float y) { constexpr auto main_id = const_hash("main"); - printf("mouse click %f %f\n", x, y); MouseEvent e; + e.m_type = kEventType::MouseDownL; e.m_pos = { x, y }; layout[main_id].on_event(&e); + printf("mouse click %f %f\n", x, y); } void App::mouse_move(float x, float y) { - + constexpr auto main_id = const_hash("main"); + MouseEvent e; + e.m_type = kEventType::MouseMove; + e.m_pos = { x, y }; + layout[main_id].on_event(&e); } void App::mouse_up(int button, float x, float y) { - + constexpr auto main_id = const_hash("main"); + MouseEvent e; + e.m_type = kEventType::MouseUpL; + e.m_pos = { x, y }; + layout[main_id].on_event(&e); } diff --git a/engine/layout.cpp b/engine/layout.cpp index b1025e0..510dd4d 100644 --- a/engine/layout.cpp +++ b/engine/layout.cpp @@ -2,9 +2,9 @@ #include "layout.h" #include "util.h" -Plane WidgetBorder::m_plane; -Plane WidgetImage::m_plane; -Sampler WidgetImage::m_sampler; +Plane NodeBorder::m_plane; +Plane NodeImage::m_plane; +Sampler NodeImage::m_sampler; Node* Node::find(const char* ids) { @@ -20,23 +20,49 @@ Node* Node::find(const char* ids) kEventResult Node::on_event(Event* e) { for (auto& c : m_children) - if (c.on_event(e) == kEventResult::Handled) - return kEventResult::Handled; - if (m_widget) + if (c->on_event(e) == kEventResult::Consumed) + return kEventResult::Consumed; + switch (e->m_cat) { - switch (e->m_cat) + case kEventCategory::MouseEvent: + { + MouseEvent* me = static_cast(e); + bool inside = point_in_rect(me->m_pos, m_clip); + bool inside_old = m_mouse_inside; + switch (e->m_type) { - case kEventCategory::MouseEvent: - if (point_in_rect(((MouseEvent*)e)->m_pos, m_clip) && m_widget->on_event(e) == kEventResult::Handled) - return kEventResult::Handled; + case kEventType::MouseDownL: + case kEventType::MouseDownR: + case kEventType::MouseUpL: + case kEventType::MouseUpR: + if (inside && handle_event(e) == kEventResult::Consumed) + return kEventResult::Consumed; break; - default: - if (m_widget->on_event(e) == kEventResult::Handled) - return kEventResult::Handled; + case kEventType::MouseMove: + if (inside_old == false && inside == true) + { + MouseEvent e2 = *me; + e2.m_type = kEventType::MouseEnter; + handle_event(&e2); + } + m_mouse_inside = inside; + handle_event(e); + if (inside_old == true && inside == false) + { + MouseEvent e2 = *me; + e2.m_type = kEventType::MouseLeave; + handle_event(&e2); + } break; } + break; } - return kEventResult::UnHandled; + default: + if (handle_event(e) == kEventResult::Consumed) + return kEventResult::Consumed; + break; + } + return kEventResult::Available; } void Node::update(float width, float height) @@ -76,20 +102,13 @@ void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj) m_clip = glm::vec4(m_pos, m_size); } - if (m_widget) - { - glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f)); - glm::mat4 scale = glm::scale(glm::vec3(glm::ceil(m_size), 1.f)); - glm::mat4 pos = glm::translate(glm::vec3(glm::floor(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(); - } + glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f)); + glm::mat4 scale = glm::scale(glm::vec3(glm::ceil(m_size), 1.f)); + glm::mat4 pos = glm::translate(glm::vec3(glm::floor(m_pos), 0)); + m_mvp = proj * pos * scale * pivot; + m_proj = proj; for (auto& c : m_children) - c.update_internal(m_pos, proj); + c->update_internal(m_pos, proj); } void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) @@ -237,8 +256,6 @@ void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) break; } default: - if (m_widget) - m_widget->parse_attributes(ka, attr); break; } } @@ -246,78 +263,104 @@ void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) void Node::load_internal(const tinyxml2::XMLElement* x_node) { m_name = x_node->Name(); + auto attr = x_node->FirstAttribute(); - - kWidget widget_id = (kWidget)const_hash(x_node->Name()); - switch (widget_id) - { - case kWidget::Border: - m_widget = std::make_unique(); - break; - case kWidget::Shape: - m_widget = std::make_unique(); - break; - case kWidget::Text: - m_widget = std::make_unique(); - break; - case kWidget::Image: - m_widget = std::make_unique(); - break; - } - while (attr) { parse_attributes((kAttribute)const_hash(attr->Name()), attr); attr = attr->Next(); } - if (m_widget) - m_widget->create(); - - if (widget_id == kWidget::Text) - SetSize(((WidgetText*)m_widget.get())->m_text_mesh.bb); + create(); auto x_child = x_node->FirstChildElement(); while (x_child) { - //Node n; - if (strcmp("ref", x_child->Name()) == 0) + kWidget child_id = (kWidget)const_hash(x_child->Name()); + switch (child_id) + { + case kWidget::Border: + { + auto n = new NodeBorder(); + m_children.emplace_back(n); + n->parent = this; + n->m_manager = m_manager; + YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node)); + n->load_internal(x_child); + break; + } +// case kWidget::Shape: +// break; + case kWidget::Image: + { + auto n = new NodeImage(); + m_children.emplace_back(n); + n->parent = this; + n->m_manager = m_manager; + YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node)); + n->load_internal(x_child); + break; + } + case kWidget::Text: + { + auto n = new NodeText(); + m_children.emplace_back(n); + n->parent = this; + n->m_manager = m_manager; + YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node)); + n->load_internal(x_child); + break; + } + case kWidget::Ref: { auto ids = x_child->Attribute("id"); auto id = const_hash(ids); auto& ref = (*m_manager)[id]; - m_children.push_back(ref.clone()); - m_children.back().parent = this; - YGNodeInsertChild(y_node, m_children.back().y_node, YGNodeGetChildCount(y_node)); + auto n = ref.clone(); + m_children.emplace_back(n); + n->parent = this; + n->m_manager = m_manager; + YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node)); + break; } - else + default: { - m_children.emplace_back(); - auto& n = m_children.back(); - n.parent = this; - n.m_manager = m_manager; - YGNodeInsertChild(y_node, n.y_node, YGNodeGetChildCount(y_node)); - n.load_internal(x_child); + auto n = new Node(); + m_children.emplace_back(n); + n->parent = this; + n->m_manager = m_manager; + YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node)); + n->load_internal(x_child); + break; + } } x_child = x_child->NextSiblingElement(); } } -Node Node::clone() +Node* Node::clone() { - Node n; - YGNodeCopyStyle(n.y_node, y_node); - if (m_widget) - n.m_widget = m_widget->clone(); - n.m_manager = m_manager; + Node* n = clone_instantiate(); + clone_copy(n); + return n; +} + +Node* Node::clone_instantiate() const +{ + return new Node(); +} + +void Node::clone_copy(Node* dest) const +{ + YGNodeCopyStyle(dest->y_node, y_node); + dest->m_manager = m_manager; for (auto& c : m_children) { - n.m_children.push_back(std::move(c.clone())); - auto& cn = n.m_children.back(); // child node reference - cn.parent = &n; - YGNodeInsertChild(n.y_node, cn.y_node, YGNodeGetChildCount(n.y_node)); + Node* cn = c->clone(); + dest->m_children.emplace_back(cn); + cn->parent = dest; + YGNodeInsertChild(dest->y_node, cn->y_node, YGNodeGetChildCount(dest->y_node)); } - return std::move(n); } bool LayoutManager::load(const char* path) @@ -352,15 +395,24 @@ bool LayoutManager::load(const char* path) if (p == m_layouts.end()) { auto& node = m_layouts[id]; - node.m_manager = this; + kWidget node_id = (kWidget)const_hash(current->Name()); + switch (node_id) + { + case kWidget::Border: + node.reset(new NodeBorder()); + break; + default: + node.reset(new Node()); + break; + } + node->m_manager = this; // try to copy the old size values if (old.count(id)) { - const auto& old_node = old[id]; - YGNodeCopyStyle(node.y_node, old_node.y_node); + const auto& old_node = *old[id]; + YGNodeCopyStyle(node->y_node, old_node.y_node); } - if (!current->NoChildren()) - node.load_internal(current->FirstChildElement()); + node->load_internal(current); } else { diff --git a/engine/layout.h b/engine/layout.h index a472343..de6ab7d 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -54,8 +54,8 @@ enum class kShapeType : uint16_t enum class kEventResult : uint8_t { - Handled, - UnHandled, + Consumed, + Available, }; enum class kEventCategory : uint8_t @@ -69,6 +69,8 @@ enum class kEventType : uint8_t MouseMove, MouseUpL, MouseUpR, + MouseEnter, + MouseLeave, }; class Event @@ -93,23 +95,15 @@ public: glm::mat4 scale; glm::mat4 pos; glm::vec4 clip; - virtual std::unique_ptr clone() = 0; + bool m_mouse_inside = false; + virtual Widget* clone() = 0; virtual void create() { } virtual void draw() { } virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { } virtual void update() { } - virtual kEventResult on_event(Event* e) { return kEventResult::UnHandled; } + virtual kEventResult on_event(Event* e) { return kEventResult::Available; } }; - -class WidgetRef : public Widget -{ -public: - uint16_t id; - virtual void create() { } - virtual void draw() { } - virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { } -}; - +/* class WidgetBorder : public Widget { public: @@ -121,11 +115,11 @@ public: { m_plane.create<1>(1, 1); } - virtual std::unique_ptr clone() override + virtual Widget* clone() override { - auto ret = std::make_unique(); + WidgetBorder* ret = new WidgetBorder(); *ret = *this; - return std::move(ret); + return ret; } virtual void draw() override { @@ -172,8 +166,15 @@ public: } virtual kEventResult on_event(Event* e) { - m_color = rand_color(); - return kEventResult::Handled; + switch (e->m_type) + { + case kEventType::MouseEnter: + m_color = rand_color(); + break; + default: + break; + } + return kEventResult::Consumed; } }; @@ -186,11 +187,11 @@ public: glm::vec4 m_border_color; float m_thinkness{ 1 }; float m_radius{ .5f }; - virtual std::unique_ptr clone() override + virtual Widget* clone() override { - auto ret = std::make_unique(); + WidgetShape* ret = new WidgetShape(); //*ret = *this; - return std::move(ret); + return ret; } virtual void create() override { @@ -272,11 +273,11 @@ public: std::string m_font; glm::vec4 m_color{ 1, 1, 1, 1 }; int m_size; - virtual std::unique_ptr clone() override + virtual Widget* clone() override { - auto ret = std::make_unique(); + WidgetText* ret = new WidgetText(); *ret = *this; - return std::move(ret); + return ret; } virtual void create() override { @@ -329,8 +330,8 @@ public: } virtual kEventResult on_event(Event* e) { - m_color = rand_color(); - return kEventResult::Handled; + //m_color = rand_color(); + return kEventResult::Consumed; } }; @@ -350,11 +351,11 @@ public: m_plane.create<1>(1, 1); m_sampler.create(); } - virtual std::unique_ptr clone() override + virtual Widget* clone() override { - auto ret = std::make_unique(); + WidgetImage* ret = new WidgetImage(); *ret = *this; - return std::move(ret); + return ret; } virtual void create() override { @@ -413,9 +414,27 @@ public: virtual kEventResult on_event(Event* e) { MouseEvent* me = static_cast(e); - return kEventResult::UnHandled; + return kEventResult::Available; } }; +class WidgetButton : public Widget +{ +public: + std::unique_ptr m_border; + std::unique_ptr m_text; + virtual Widget* clone() + { + WidgetButton* ret = new WidgetButton(); + ret->m_border.reset((WidgetBorder*)m_border->clone()); + return std::move(ret); + } + virtual void create() { } + virtual void draw() { } + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { } + virtual void update() { } + virtual kEventResult on_event(Event* e) { return kEventResult::Available; } +}; +*/ class Node { @@ -428,8 +447,12 @@ class Node public: uint16_t m_nodeID; std::string m_nodeID_s; - std::vector m_children; - std::unique_ptr m_widget; + std::vector> m_children; + + glm::mat4 m_proj; + glm::mat4 m_mvp; + bool m_mouse_inside = false; + glm::vec2 m_pos; glm::vec2 m_size; glm::vec4 m_clip; @@ -442,10 +465,9 @@ public: { m_name = std::move(o.m_name); m_nodeID_s = std::move(o.m_nodeID_s); - m_widget = std::move(o.m_widget); m_children = std::move(o.m_children); for (auto& c : m_children) - c.parent = this; + c->parent = this; m_nodeID = o.m_nodeID; m_display = o.m_display; parent = o.parent; @@ -495,12 +517,16 @@ public: void update(float width, float height); void update_internal(const glm::vec2& origin, const glm::mat4& proj); - void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr); + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr); void load_internal(const tinyxml2::XMLElement* x_node); - void draw(); - Node clone(); + virtual void draw() { } + Node* clone(); + virtual Node* clone_instantiate() const; + virtual void clone_copy(Node* dest) const; Node* find(const char* ids); kEventResult on_event(Event* e); + virtual kEventResult handle_event(Event* e) { return kEventResult::Available; } + virtual void create() { }; class iterator { @@ -517,7 +543,7 @@ public: { m_nodes.pop(); for (auto& c : m_current->m_children) - m_nodes.push(&c); + m_nodes.push(c.get()); m_current = m_nodes.size() ? m_nodes.top() : nullptr; return *this; } @@ -536,14 +562,236 @@ public: } }; +class NodeBorder : public Node +{ + static Plane m_plane; + glm::vec4 m_color; + glm::vec4 m_border_color; + float m_thinkness{ 1 }; +public: + static void init() + { + m_plane.create<1>(1, 1); + } + virtual Node* clone_instantiate() const override { return new NodeBorder(); } + virtual void clone_copy(Node* dest) const override + { + Node::clone_copy(dest); + NodeBorder* n = static_cast(dest); + n->m_color = m_color; + n->m_border_color = m_border_color; + n->m_thinkness = m_thinkness; + } + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override + { + Node::parse_attributes(ka, attr); + switch (ka) + { + case kAttribute::Color: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + m_color = glm::vec4(pad.x); + else + m_color = pad; + break; + } + case kAttribute::BorderColor: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + m_border_color = glm::vec4(pad.x); + else + m_border_color = pad; + break; + } + case kAttribute::Thickness: + m_thinkness = attr->FloatValue(); + break; + default: + break; + } + } + virtual void draw() override + { + ShaderManager::use(kShader::Color); + ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp); + + ShaderManager::u_vec4(kShaderUniform::Col, m_color); + m_plane.draw_fill(); + + glLineWidth(m_thinkness); + ShaderManager::u_vec4(kShaderUniform::Col, m_border_color); + m_plane.draw_stroke(); + } + virtual kEventResult handle_event(Event* e) override + { + switch (e->m_type) + { + case kEventType::MouseEnter: + m_color = rand_color(); + break; + default: + break; + } + return kEventResult::Consumed; + } +}; + +class NodeText : public Node +{ + TextMesh m_text_mesh; + std::string m_text; + std::string m_font; + glm::vec4 m_color{ 1, 1, 1, 1 }; + int m_size; +public: + virtual Node* clone_instantiate() const override { return new NodeText(); } + virtual void clone_copy(Node* dest) const override + { + Node::clone_copy(dest); + NodeText* n = static_cast(dest); + } + 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()); + SetSize(m_text_mesh.bb); + } + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override + { + Node::parse_attributes(ka, attr); + 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; + case kAttribute::Color: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + m_color = glm::vec4(pad.x); + else + m_color = pad; + break; + } + default: + break; + } + } + virtual void draw() override + { + glm::mat4 pos = glm::translate(glm::vec3(glm::floor(m_pos), 0)); + m_mvp = m_proj * pos; + ShaderManager::use(kShader::Font); + ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp); + ShaderManager::u_vec4(kShaderUniform::Col, m_color); + glEnable(GL_BLEND); + m_text_mesh.draw(); + glDisable(GL_BLEND); + } +}; + +class NodeImage : public Node +{ +public: + static Plane m_plane; + static Sampler m_sampler; + bool m_use_atlas; + glm::vec4 m_region; + glm::vec2 m_off; + glm::vec2 m_sz; + std::string m_path; + uint16_t m_id; + static void init() + { + m_plane.create<1>(1, 1); + m_sampler.create(); + } + virtual Node* clone_instantiate() const override { return new NodeImage(); } + virtual void clone_copy(Node* dest) const override + { + Node::clone_copy(dest); + NodeImage* n = static_cast(dest); + } + virtual void create() override + { + if (TextureManager::load(m_path.c_str())) + { + auto tex_sz = TextureManager::get(m_id).size(); + m_off = m_region.xy / tex_sz; + m_sz = (m_region.zw - m_region.xy) / tex_sz; + } + } + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override + { + Node::parse_attributes(ka, attr); + switch (ka) + { + case kAttribute::Path: + m_path = attr->Value(); + m_id = const_hash(attr->Value()); + break; + case kAttribute::Region: + { + glm::vec4 v; + int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w); + if (n == 4) + { + m_region = v; + m_use_atlas = true; + } + break; + } + default: + break; + } + } + virtual void draw() override + { + TextureManager::get(m_id).bind(); + m_sampler.bind(0); + glEnable(GL_BLEND); + if (m_use_atlas) + { + ShaderManager::use(kShader::Atlas); + ShaderManager::u_vec2(kShaderUniform::Tof, m_off); + ShaderManager::u_vec2(kShaderUniform::Tsz, m_sz); + } + else + { + ShaderManager::use(kShader::Texture); + } + ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp); + m_plane.draw_fill(); + m_sampler.unbind(); + TextureManager::get(m_id).unbind(); + glDisable(GL_BLEND); + } +}; + class LayoutManager { - std::map m_layouts; + std::map> m_layouts; std::string m_path; struct stat m_file_info { 0 }; public: bool load(const char* path); bool reload(); - Node& operator[](uint16_t id) { return m_layouts[id]; } + Node& operator[](uint16_t id) { return *m_layouts[id]; } //Node& operator[](const char* ids) { return m_layouts[const_hash(ids)]; } };