From a4be7c0e4d29bd5fe4354402333b913ad4e1b1bd Mon Sep 17 00:00:00 2001 From: omigamedev Date: Fri, 27 Jan 2017 13:20:39 +0000 Subject: [PATCH] complete refactoring and cleanup old layout loading code --- data/layout.xml | 4 +- engine.vcxproj | 2 + engine.vcxproj.filters | 6 + engine/app.cpp | 631 +---------------------------------------- engine/app.hpp | 10 +- engine/layout.cpp | 206 ++++++++++++++ engine/layout.h | 171 +++++++++++ engine/shape.hpp | 98 +------ 8 files changed, 398 insertions(+), 730 deletions(-) create mode 100644 engine/layout.cpp create mode 100644 engine/layout.h diff --git a/data/layout.xml b/data/layout.xml index d960740..22c5272 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -19,13 +19,13 @@ - + - + diff --git a/engine.vcxproj b/engine.vcxproj index 0dfa780..a6b7a33 100644 --- a/engine.vcxproj +++ b/engine.vcxproj @@ -152,6 +152,7 @@ + Create @@ -184,6 +185,7 @@ + diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters index a436275..53df085 100644 --- a/engine.vcxproj.filters +++ b/engine.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + @@ -65,5 +68,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/engine/app.cpp b/engine/app.cpp index f8c684b..7576fbd 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -9,533 +9,6 @@ void App::create() height = 500; } -glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b) -{ - // convert from [x,y,w,h] to [x1,y1,x2,y1] - a = glm::vec4(a.xy(), a.xy() + a.zw()); - b = glm::vec4(b.xy(), b.xy() + b.zw()); - auto o = glm::vec4(glm::max(a.xy(), b.xy()), glm::min(a.zw(), b.zw())); - o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy())); - return o; -} - -class Node -{ - const Node* parent{ nullptr }; - YGNodeRef y_node{ nullptr }; - struct stat m_file_info { 0 }; - -public: - std::vector children; - glm::vec4 color; - glm::vec2 m_pos; - glm::vec2 m_size; - glm::vec4 m_clip; - Node(const Node&) = delete; - Node& operator=(const Node&) = delete; - Node& operator=(Node&& o) { return Node(std::forward(o)); } - Node(Node&& o) - { - children = std::move(o.children); - parent = o.parent; - y_node = o.y_node; - m_pos = o.m_pos; - m_size = o.m_size; - m_clip = o.m_clip; - color = o.color; - m_file_info = o.m_file_info; - o.y_node = nullptr; - o.parent = nullptr; - } - Node() { y_node = YGNodeNew(); } - ~Node() - { -// children.clear(); - if (y_node) - YGNodeFree(y_node); - } - - void SetWidth(float value) { YGNodeStyleSetWidth(y_node, value); } - 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 SetPadding(float t, float r, float b, float l) - { - YGNodeStyleSetPadding(y_node, YGEdgeTop, t); - YGNodeStyleSetPadding(y_node, YGEdgeRight, r); - YGNodeStyleSetPadding(y_node, YGEdgeBottom, b); - YGNodeStyleSetPadding(y_node, YGEdgeLeft, l); - } - - void SetFlexGrow(float value) { YGNodeStyleSetFlexGrow(y_node, value); } - void SetFlexShrink(float value) { YGNodeStyleSetFlexShrink(y_node, value); } - void SetFlexDir(YGFlexDirection value) { YGNodeStyleSetFlexDirection(y_node, value); } - void SetFlexWrap(YGWrap value) { YGNodeStyleSetFlexWrap(y_node, value); } - - void update(float width, float height) - { - YGNodeStyleSetWidth(y_node, width); - YGNodeStyleSetHeight(y_node, height); - YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR); - update_internal({ 0, 0 }); - } - - void update_internal(glm::vec2 origin) - { - float x = YGNodeLayoutGetLeft(y_node); - float y = YGNodeLayoutGetTop(y_node); - float w = YGNodeLayoutGetWidth(y_node); - float h = YGNodeLayoutGetHeight(y_node); - m_pos = origin + glm::vec2(x, y); - m_size = glm::vec2(w, h); - if (!parent) - m_clip = glm::vec4(m_pos, m_size); - else - m_clip = rect_intersection(glm::vec4(m_pos, m_size), parent->m_clip); - for (auto& c : children) - c.update_internal(m_pos); - } - - void parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr) - { - switch (ka) - { - case att::kAttribute::Width: - if (strcmp(attr->Value(), "auto") == 0) - { - YGNodeStyleSetWidth(y_node, YGUndefined); - YGNodeStyleSetWidthPercent(y_node, YGUndefined); - } - else - { - if (strchr(attr->Value(), '%')) - YGNodeStyleSetWidthPercent(y_node, attr->FloatValue()); - else - YGNodeStyleSetWidth(y_node, attr->FloatValue()); - } - break; - case att::kAttribute::MinWidth: - if (strchr(attr->Value(), '%')) - YGNodeStyleSetMinWidthPercent(y_node, attr->FloatValue()); - else - YGNodeStyleSetMinWidth(y_node, attr->FloatValue()); - break; - case att::kAttribute::MaxWidth: - YGNodeStyleSetMaxWidth(y_node, attr->FloatValue()); - break; - case att::kAttribute::Height: - if (strcmp(attr->Value(), "auto") == 0) - { - YGNodeStyleSetHeight(y_node, YGUndefined); - YGNodeStyleSetHeightPercent(y_node, YGUndefined); - } - else - { - if (strchr(attr->Value(), '%')) - YGNodeStyleSetHeightPercent(y_node, attr->FloatValue()); - else - YGNodeStyleSetHeight(y_node, attr->FloatValue()); - } - break; - case att::kAttribute::MinHeight: - YGNodeStyleSetMinHeight(y_node, attr->FloatValue()); - break; - case att::kAttribute::MaxHeight: - YGNodeStyleSetMaxHeight(y_node, attr->FloatValue()); - break; - case att::kAttribute::Grow: - YGNodeStyleSetFlexGrow(y_node, attr->FloatValue()); - break; - case att::kAttribute::Shrink: - YGNodeStyleSetFlexShrink(y_node, attr->FloatValue()); - break; - case att::kAttribute::FlexDir: - { - YGFlexDirection dir = YGFlexDirectionRow; - if (strcmp("col", attr->Value()) == 0) - dir = YGFlexDirectionColumn; - else if (strcmp("col-reverse", attr->Value()) == 0) - dir = YGFlexDirectionColumnReverse; - else if (strcmp("row", attr->Value()) == 0) - dir = YGFlexDirectionRow; - else if (strcmp("row-reverse", attr->Value()) == 0) - dir = YGFlexDirectionRowReverse; - YGNodeStyleSetFlexDirection(y_node, dir); - break; - } - case att::kAttribute::FlexWrap: - YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap); - break; - case att::kAttribute::Padding: - { - glm::vec4 pad; - int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); - if (n == 1) - { - YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.x); - } - else - { - YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.y); - YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.z); - YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.w); - } - break; - } - case att::kAttribute::Margin: - { - glm::vec4 pad; - int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); - if (n == 1) - { - YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.x); - } - else - { - YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.y); - YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.z); - YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.w); - } - break; - } - case att::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) - { - color = glm::vec4(pad.x); - } - else - { - color = pad; - } - break; - } - default: - // other_attributes_handler() - break; - } - } - - void load(const char* path) - { - struct stat tmp_info; - if (stat("data/layout.xml", &tmp_info) != 0) - return; - if (tmp_info.st_mtime <= m_file_info.st_mtime) - return; - m_file_info = tmp_info; - - children.clear(); - YGNodeReset(y_node); - - using NodePair = std::pair; - std::stack stack; - - tinyxml2::XMLDocument xml; - auto ret = xml.LoadFile(path); - load_internal(xml.RootElement()); - } - - void load_internal(const tinyxml2::XMLElement* x_node) - { - auto attr = x_node->FirstAttribute(); - while (attr) - { - parse_attributes(att::value(attr->Name()), attr); - attr = attr->Next(); - } - - auto x_child = x_node->FirstChildElement(); - while (x_child) - { - //Node n; - children.emplace_back(); - auto& n = children.back(); - n.parent = this; - YGNodeInsertChild(y_node, n.y_node, YGNodeGetChildCount(y_node)); - n.load_internal(x_child); - x_child = x_child->NextSiblingElement(); - } - } -}; - -void App::update_layout() -{ - YGNodeCalculateLayout(y_root, YGUndefined, YGUndefined, YGDirectionLTR); - std::stack y_stack; - y_stack.push(y_root); - auto y_current = y_root; - while (y_current) - { - y_stack.pop(); - auto ctx = reinterpret_cast(YGNodeGetContext(y_current)); - if (!ctx) - { - ctx = new glm::vec4(); - YGNodeSetContext(y_current, ctx); - } - - if (y_current == y_root) - { - ctx->x = YGNodeLayoutGetLeft(y_current); - ctx->y = YGNodeLayoutGetTop(y_current); - ctx->z = YGNodeLayoutGetWidth(y_current); - ctx->w = YGNodeLayoutGetHeight(y_current); - } - - int n = YGNodeGetChildCount(y_current); - for (int i = 0; i < n; i++) - { - auto y_child = YGNodeGetChild(y_current, i); - auto ctx_child = reinterpret_cast(YGNodeGetContext(y_child)); - if (!ctx_child) ctx_child = new glm::vec4(); - float x = YGNodeLayoutGetLeft(y_child); - float y = YGNodeLayoutGetTop(y_child); - float w = YGNodeLayoutGetWidth(y_child); - float h = YGNodeLayoutGetHeight(y_child); - ctx_child->x = ctx->x + x; - ctx_child->y = ctx->y + y; - ctx_child->z = w; - ctx_child->w = h; - *ctx_child = rect_intersection(*ctx_child, *ctx); - YGNodeSetContext(y_child, ctx_child); - y_stack.emplace(y_child); - } - y_current = y_stack.size() ? y_stack.top() : nullptr; - } -} - -void App::load_layout() -{ - struct stat tmp_info; - if (stat("data/layout.xml", &tmp_info) != 0) - return; - if (tmp_info.st_mtime <= g_file_info.st_mtime) - return; - g_file_info = tmp_info; - - if (y_root) - YGNodeFreeRecursive(y_root); - shapes_list.clear(); - - y_root = YGNodeNew(); - YGNodeStyleSetWidth(y_root, width); - //YGNodeStyleSetWidthPercent(y_root, 100); - YGNodeStyleSetHeight(y_root, height); - //YGNodeStyleSetHeightPercent(y_root, 100); - //YGNodeStyleSetFlexDirection(y_root, YGFlexDirectionRow); - //YGNodeStyleSetFlexWrap(y_root, YGWrapWrap); - //YGNodeStyleSetPadding(y_root, YGEdgeAll, 0); - //YGNodeStyleSetPadding(y_root, YGEdgeTop, 0); - //YGNodeStyleSetPadding(y_root, YGEdgeRight, 0); - //YGNodeStyleSetPadding(y_root, YGEdgeBottom, 0); - //YGNodeStyleSetPadding(y_root, YGEdgeLeft, 0); - //YGNodeStyleSetJustifyContent(y_root, YGJustifyFlexStart); - - using NodePair = std::pair; - std::stack stack; - - tinyxml2::XMLDocument xml; - auto ret = xml.LoadFile("data/layout.xml"); - auto x_root = xml.RootElement(); - - NodePair current = { y_root, x_root }; - stack.push(current); - while (current.first && current.second) - { - stack.pop(); - auto y_root = current.first; - auto child = current.second->FirstChildElement(); - //YGNodeStyleSetPosition(y_root, YGEdgeAll, 0); - //YGNodeStyleSetPositionType(y_root, YGPositionTypeRelative); - while (child) - { - auto y_node = YGNodeNew(); - stack.emplace(y_node, child); - auto attr = child->FirstAttribute(); - std::unique_ptr shape; - if (strcmp("plane", child->Name()) == 0) - { - shape = std::make_unique(); - shape->create<5>(100.f, 100.f); - shape->y_node = y_node; - YGNodeSetContext(y_node, shape.get()); - } - printf("Element %s: ", child->Name()); - //YGNodeStyleSetWidth(y_node, 0); - //YGNodeStyleSetWidthPercent(y_node, 100); - //YGNodeStyleSetHeight(y_node, 0); - //YGNodeStyleSetHeightPercent(y_node, 100); - //YGNodeStyleSetPadding(y_node, YGEdgeAll, 0); - //YGNodeStyleSetPadding(y_node, YGEdgeTop, 0); - //YGNodeStyleSetPadding(y_node, YGEdgeRight, 0); - //YGNodeStyleSetPadding(y_node, YGEdgeBottom, 0); - //YGNodeStyleSetPadding(y_node, YGEdgeLeft, 0); - - //YGNodeStyleSetPosition(y_node, YGEdgeAll, 0); - //YGNodeStyleSetPosition(y_node, YGEdgeTop, 0); - //YGNodeStyleSetPosition(y_node, YGEdgeRight, 0); - //YGNodeStyleSetPosition(y_node, YGEdgeBottom, 0); - //YGNodeStyleSetPosition(y_node, YGEdgeLeft, 0); - // - //YGNodeStyleSetOverflow(y_node, YGOverflowHidden); - - while (attr) - { - const auto ka = att::value(attr->Name()); - printf("%s=%s ", attr->Name(), attr->Value()); - switch (ka) - { - case att::kAttribute::Width: - if (strcmp(attr->Value(), "auto") == 0) - { - YGNodeStyleSetWidth(y_node, YGUndefined); - YGNodeStyleSetWidthPercent(y_node, YGUndefined); - } - else - { - if (strchr(attr->Value(), '%')) - YGNodeStyleSetWidthPercent(y_node, attr->FloatValue()); - else - YGNodeStyleSetWidth(y_node, attr->FloatValue()); - } - break; - case att::kAttribute::MinWidth: - if (strchr(attr->Value(), '%')) - YGNodeStyleSetMinWidthPercent(y_node, attr->FloatValue()); - else - YGNodeStyleSetMinWidth(y_node, attr->FloatValue()); - break; - case att::kAttribute::MaxWidth: - YGNodeStyleSetMaxWidth(y_node, attr->FloatValue()); - break; - case att::kAttribute::Height: - if (strcmp(attr->Value(), "auto") == 0) - { - YGNodeStyleSetHeight(y_node, YGUndefined); - YGNodeStyleSetHeightPercent(y_node, YGUndefined); - } - else - { - if (strchr(attr->Value(), '%')) - YGNodeStyleSetHeightPercent(y_node, attr->FloatValue()); - else - YGNodeStyleSetHeight(y_node, attr->FloatValue()); - } - break; - case att::kAttribute::MinHeight: - YGNodeStyleSetMinHeight(y_node, attr->FloatValue()); - break; - case att::kAttribute::MaxHeight: - YGNodeStyleSetMaxHeight(y_node, attr->FloatValue()); - break; - case att::kAttribute::Grow: - YGNodeStyleSetFlexGrow(y_node, attr->FloatValue()); - break; - case att::kAttribute::Shrink: - YGNodeStyleSetFlexShrink(y_node, attr->FloatValue()); - break; - case att::kAttribute::FlexDir: - { - YGFlexDirection dir = YGFlexDirectionRow; - if (strcmp("col", attr->Value()) == 0) - dir = YGFlexDirectionColumn; - else if (strcmp("col-reverse", attr->Value()) == 0) - dir = YGFlexDirectionColumnReverse; - else if (strcmp("row", attr->Value()) == 0) - dir = YGFlexDirectionRow; - else if (strcmp("row-reverse", attr->Value()) == 0) - dir = YGFlexDirectionRowReverse; - YGNodeStyleSetFlexDirection(y_node, dir); - break; - } - case att::kAttribute::FlexWrap: - YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap); - break; - case att::kAttribute::Padding: - { - glm::vec4 pad; - int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); - if (n == 1) - { - YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.x); - } - else - { - YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.y); - YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.z); - YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.w); - } - break; - } - case att::kAttribute::Margin: - { - glm::vec4 pad; - int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); - if (n == 1) - { - YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.x); - } - else - { - YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); - YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.y); - YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.z); - YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.w); - } - break; - } - case att::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) - { - if (shape) - shape->color = glm::vec4(pad.x); - } - else - { - if (shape) - shape->color = pad; - } - break; - } - default: - break; - } - attr = attr->Next(); - } - int n = YGNodeGetChildCount(y_root); - YGNodeInsertChild(y_root, y_node, n); - if (shape) - shapes_list.push_back(std::move(shape)); - child = child->NextSiblingElement(); - printf("\n"); - } - current = stack.size() ? stack.top() : NodePair{ nullptr, nullptr }; - } - update_layout(); -} -Node nn; void App::init() { static const char* shader_v = @@ -601,30 +74,15 @@ void App::init() glEnable(GL_DEBUG_OUTPUT); #endif - load_layout(); - nn.load("data/layout.xml"); - nn.update(width, height); - - for (auto& s : shapes_list) - { - float w = YGNodeLayoutGetWidth(s->y_node); - float h = YGNodeLayoutGetHeight(s->y_node); - float x = YGNodeLayoutGetLeft(s->y_node); - float y = YGNodeLayoutGetTop(s->y_node); - printf("layout w=%f h=%f x=%f y=%f\n", w, h, x, y); - } + layout.load("data/layout.xml"); + layout.update(width, height); sampler.create(); shader.create(shader_v, shader_f); shader_color.create(shader_color_v, shader_color_f); shader_uv.create(shader_v, shader_uv_f); plane.create<5>(1, 1); - circle.create<10>(25); - circle2.create<10>(25, Circle::kUVMapping::Tube); - circle3.create<10>(25, 12, Circle::kUVMapping::Tube); - circle4.create<10>(25, 12, Circle::kUVMapping::Planar); - rounded.create<3>(50, 50, 10); - slice.create(50, 50, 10, .3f); + if (!tex.load("data/uvs.jpg")) printf("error loading image\n"); @@ -653,50 +111,12 @@ void App::update(float dt) { glm::mat4 proj = glm::ortho(0.f, width, height, 0.f, -1.f, 1.f); - //Shape* shapes[] = { &circle, &circle2, &circle3, &circle4, &plane, &rounded, &slice }; - glClearColor(.1f, .1f, .1f, 1.f); glViewport(0, 0, (GLsizei)width, (GLsizei)height); glClear(GL_COLOR_BUFFER_BIT); - load_layout(); + layout.reload(); -/* - auto s = glm::scale(glm::vec3(1.5)); - int h = 100; - for (int i = 0; i < sizeof(shapes)/sizeof(Shape*); i++) - { - shader.use(); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glActiveTexture(GL_TEXTURE0); - tex.bind(); - sampler.bind(0); - shader.u_int("tex", 0); - shader.u_mat4("mvp", proj * glm::translate(glm::vec3{75 + h * 1, 75 + h * i, 0.f}) * s); - shapes[i]->draw_fill(); - tex.unbind(); - - shader_color.use(); - shader_color.u_mat4("mvp", proj * glm::translate(glm::vec3{75 + h * 2, 75 + h * i, 0.f}) * s); - shader_color.u_vec4("col", {1, 1, 1, 1}); - shapes[i]->draw_stroke(); - - shader_color.u_mat4("mvp", proj * glm::translate(glm::vec3{75 + h * 0, 75 + h * i, 0.f}) * s); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - shapes[i]->draw_fill(); - - shader_uv.use(); - shader_uv.u_mat4("mvp", proj * glm::translate(glm::vec3{75 + h * 3, 75 + h * i, 0.f}) * s); - shader_uv.u_int("tex", 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - shapes[i]->draw_fill(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - shader_uv.u_mat4("mvp", proj * glm::translate(glm::vec3{75 + h * 4, 75 + h * i, 0.f}) * s); - shapes[i]->draw_fill(); - tex.unbind(); - } -*/ glActiveTexture(GL_TEXTURE0); tex.bind(); sampler.bind(0); @@ -706,42 +126,10 @@ void App::update(float dt) shader_color.u_vec4("col", { .3f, .3f, .3f, 1 }); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -// for (auto& s : shapes_list) -// { -// auto layout = *reinterpret_cast(YGNodeGetContext(s->y_node)); -// auto y_parent = YGNodeGetParent(s->y_node); -// if (y_parent && YGNodeGetContext(y_parent)) -// { -// auto box = *reinterpret_cast(YGNodeGetContext(y_parent)); -// glEnable(GL_SCISSOR_TEST); -// glScissor(box.x, height - box.y - 1 - box.w, box.z, box.w); -// } -// //glScissor(10, height - 10 - 1 - 50, 480, 50); -// -// glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f)); -// glm::mat4 scale = glm::scale(glm::vec3(layout.zw(), 1.f)); -// glm::mat4 pos = glm::translate(glm::vec3(layout.xy(), 0)); -// auto mvp = proj * pos * scale * pivot; -// -// //shader_uv.use(); -// //shader_uv.u_mat4("mvp", mvp); -// //plane.draw_fill(); -// -// shader_color.u_vec4("col", s->color); -// shader_color.use(); -// shader_color.u_mat4("mvp", mvp); -// plane.draw_fill(); -// -// shader_color.u_vec4("col", { 1, 1, 1, 1 }); -// shader_color.use(); -// shader_color.u_mat4("mvp", mvp); -// plane.draw_stroke(); -// glDisable(GL_SCISSOR_TEST); -// } std::stack nodes; - Node* current = &nn; + Node* current = &layout; nodes.push(current); - //glEnable(GL_SCISSOR_TEST); + glEnable(GL_SCISSOR_TEST); while (current) { nodes.pop(); @@ -752,7 +140,7 @@ void App::update(float dt) auto mvp = proj * pos * scale * pivot; auto box = current->m_clip; - glScissor(box.x, height - box.y - 1 - box.w, box.z, box.w); + glScissor(box.x, height - box.y - box.w, box.z, box.w); shader_color.u_vec4("col", current->color); shader_color.use(); @@ -796,10 +184,7 @@ void App::resize(float w, float h) { width = w; height = h; - YGNodeStyleSetWidth(y_root, width); - YGNodeStyleSetHeight(y_root, height); - update_layout(); - nn.update(width, height); + layout.update(width, height); } void App::mouse_down(int button, float x, float y) diff --git a/engine/app.hpp b/engine/app.hpp index 7379b5a..4ff7072 100644 --- a/engine/app.hpp +++ b/engine/app.hpp @@ -3,6 +3,7 @@ #include "shader.hpp" #include "shape.hpp" #include "texture.hpp" +#include "layout.h" class App { @@ -11,13 +12,8 @@ class App Shader shader_color; Shader shader_uv; Plane plane; - std::vector> shapes_list; - Circle circle, circle2, circle3, circle4; - Rounded rounded; - Slice9 slice; Texture2D tex; - YGNodeRef y_root { nullptr }; - struct stat g_file_info { 0 }; + Node layout; public: static App I; float width; @@ -29,6 +25,4 @@ public: void mouse_down(int button, float x, float y); void mouse_move(float x, float y); void mouse_up(int button, float x, float y); - void update_layout(); - void load_layout(); }; diff --git a/engine/layout.cpp b/engine/layout.cpp new file mode 100644 index 0000000..9850c31 --- /dev/null +++ b/engine/layout.cpp @@ -0,0 +1,206 @@ +#include "pch.h" +#include "layout.h" + +void Node::update(float width, float height) +{ + YGNodeStyleSetWidth(y_node, width); + YGNodeStyleSetHeight(y_node, height); + YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR); + update_internal({ 0, 0 }); +} + +void Node::update_internal(glm::vec2 origin) +{ + float x = YGNodeLayoutGetLeft(y_node); + float y = YGNodeLayoutGetTop(y_node); + float w = YGNodeLayoutGetWidth(y_node); + float h = YGNodeLayoutGetHeight(y_node); + m_pos = origin + glm::vec2(x, y); + m_size = glm::vec2(w, h); + if (!parent) + m_clip = glm::vec4(m_pos, m_size); + else + m_clip = rect_intersection(glm::vec4(m_pos, m_size), parent->m_clip); + for (auto& c : children) + c.update_internal(m_pos); +} + +void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr) +{ + switch (ka) + { + case att::kAttribute::Width: + if (strcmp(attr->Value(), "auto") == 0) + { + YGNodeStyleSetWidth(y_node, YGUndefined); + YGNodeStyleSetWidthPercent(y_node, YGUndefined); + } + else + { + if (strchr(attr->Value(), '%')) + YGNodeStyleSetWidthPercent(y_node, attr->FloatValue()); + else + YGNodeStyleSetWidth(y_node, attr->FloatValue()); + } + break; + case att::kAttribute::MinWidth: + if (strchr(attr->Value(), '%')) + YGNodeStyleSetMinWidthPercent(y_node, attr->FloatValue()); + else + YGNodeStyleSetMinWidth(y_node, attr->FloatValue()); + break; + case att::kAttribute::MaxWidth: + YGNodeStyleSetMaxWidth(y_node, attr->FloatValue()); + break; + case att::kAttribute::Height: + if (strcmp(attr->Value(), "auto") == 0) + { + YGNodeStyleSetHeight(y_node, YGUndefined); + YGNodeStyleSetHeightPercent(y_node, YGUndefined); + } + else + { + if (strchr(attr->Value(), '%')) + YGNodeStyleSetHeightPercent(y_node, attr->FloatValue()); + else + YGNodeStyleSetHeight(y_node, attr->FloatValue()); + } + break; + case att::kAttribute::MinHeight: + YGNodeStyleSetMinHeight(y_node, attr->FloatValue()); + break; + case att::kAttribute::MaxHeight: + YGNodeStyleSetMaxHeight(y_node, attr->FloatValue()); + break; + case att::kAttribute::Grow: + YGNodeStyleSetFlexGrow(y_node, attr->FloatValue()); + break; + case att::kAttribute::Shrink: + YGNodeStyleSetFlexShrink(y_node, attr->FloatValue()); + break; + case att::kAttribute::FlexDir: + { + YGFlexDirection dir = YGFlexDirectionRow; + if (strcmp("col", attr->Value()) == 0) + dir = YGFlexDirectionColumn; + else if (strcmp("col-reverse", attr->Value()) == 0) + dir = YGFlexDirectionColumnReverse; + else if (strcmp("row", attr->Value()) == 0) + dir = YGFlexDirectionRow; + else if (strcmp("row-reverse", attr->Value()) == 0) + dir = YGFlexDirectionRowReverse; + YGNodeStyleSetFlexDirection(y_node, dir); + break; + } + case att::kAttribute::FlexWrap: + YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap); + break; + case att::kAttribute::Padding: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + { + YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); + YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.x); + YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.x); + YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.x); + } + else + { + YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x); + YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.y); + YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.z); + YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.w); + } + break; + } + case att::kAttribute::Margin: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + { + YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); + YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.x); + YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.x); + YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.x); + } + else + { + YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x); + YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.y); + YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.z); + YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.w); + } + break; + } + case att::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) + { + color = glm::vec4(pad.x); + } + else + { + color = pad; + } + break; + } + default: + // other_attributes_handler() + break; + } +} + +void Node::load(const char* path) +{ + struct stat tmp_info; + if (stat(path, &tmp_info) != 0) + return; + if (tmp_info.st_mtime <= m_file_info.st_mtime) + return; + m_file_info = tmp_info; + m_path = path; + + children.clear(); + YGNodeReset(y_node); + + tinyxml2::XMLDocument xml; + auto ret = xml.LoadFile(path); + load_internal(xml.RootElement()); +} + +void Node::load_internal(const tinyxml2::XMLElement* x_node) +{ + auto attr = x_node->FirstAttribute(); + while (attr) + { + parse_attributes(att::value(attr->Name()), attr); + attr = attr->Next(); + } + + auto x_child = x_node->FirstChildElement(); + while (x_child) + { + //Node n; + children.emplace_back(); + auto& n = children.back(); + n.parent = this; + YGNodeInsertChild(y_node, n.y_node, YGNodeGetChildCount(y_node)); + n.load_internal(x_child); + x_child = x_child->NextSiblingElement(); + } +} + +void Node::reload() +{ + float w = YGNodeLayoutGetWidth(y_node); + float h = YGNodeLayoutGetHeight(y_node); + // avoid conflict when assigning the same string from c_str + std::string path_copy = m_path; + load(path_copy.c_str()); + update(w, h); +} diff --git a/engine/layout.h b/engine/layout.h new file mode 100644 index 0000000..c6f5bbd --- /dev/null +++ b/engine/layout.h @@ -0,0 +1,171 @@ +#pragma once + +namespace att +{ + enum class kAttribute : uint8_t { + Width, MinWidth, MaxWidth, + Height, MinHeight, MaxHeight, + Divisions, InnerRadius, OuterRadius, + Grow, Shrink, FlexDir, FlexWrap, + Padding, Margin, + Color + }; + + struct AttributeBase + { + kAttribute id; + }; + + typedef std::map> AttrubutesMap; + + template + struct Attribute : public AttributeBase + { + static const kAttribute static_id = T; + V value; + Attribute() : value{ 0 } { id = static_id; } + Attribute(V v) : value(v) { id = static_id; } + }; + + struct typemap + { + const char* name; + kAttribute value; + }; + static constexpr typemap map[] = + { + { "width", kAttribute::Width }, + { "min-width", kAttribute::MinWidth }, + { "max-width", kAttribute::MaxWidth }, + { "height", kAttribute::Height }, + { "min-height", kAttribute::MinHeight }, + { "max-height", kAttribute::MaxHeight }, + { "divisions", kAttribute::Divisions }, + { "inner-radius", kAttribute::InnerRadius }, + { "outer-radius", kAttribute::OuterRadius }, + { "grow", kAttribute::Grow }, + { "shrink", kAttribute::Shrink }, + { "dir", kAttribute::FlexDir }, + { "wrap", kAttribute::FlexWrap }, + { "pad", kAttribute::Padding }, + { "margin", kAttribute::Margin }, + { "color", kAttribute::Color }, + }; + static constexpr int map_size = sizeof(map) / sizeof(typemap) - 1; + constexpr bool same(const char* a, const char* b) + { + return (*a && *b) ? (*a == *b && same(a + 1, b + 1)) : !(*a || *b); + } + constexpr const kAttribute value(char const *name, int i = 0) + { + return ((i >= map_size) || same(map[i].name, name)) ? + map[i].value : value(name, i + 1); + } + constexpr const char* string(const kAttribute value, int i = 0) + { + return (map[i].value == value) ? map[i].name : string(value, i + 1); + } + + //constexpr const char* string(kAttribute a) { return names[(int)a]; } + + // template + // constexpr const char* string(const Attribute a) { return names[(int)a.id]; } + +#define DECLARE_ATTRIBUTE(N,T) \ + struct N : public Attribute \ + { using Attribute::Attribute; }; + + DECLARE_ATTRIBUTE(Width, float); + DECLARE_ATTRIBUTE(MinWidth, float); + DECLARE_ATTRIBUTE(MaxWidth, float); + DECLARE_ATTRIBUTE(Height, float); + DECLARE_ATTRIBUTE(MinHeight, float); + DECLARE_ATTRIBUTE(MaxHeight, float); + DECLARE_ATTRIBUTE(Divisions, int); + DECLARE_ATTRIBUTE(InnerRadius, float); + DECLARE_ATTRIBUTE(OuterRadius, float); + DECLARE_ATTRIBUTE(Grow, float); + DECLARE_ATTRIBUTE(Shrink, float); + DECLARE_ATTRIBUTE(FlexDir, int); + DECLARE_ATTRIBUTE(FlexWrap, int); + DECLARE_ATTRIBUTE(Padding, glm::vec4); + DECLARE_ATTRIBUTE(Margin, glm::vec4); + DECLARE_ATTRIBUTE(Color, glm::vec4); + +#undef DECLARE_ATTRIBUTE +} + +class Node +{ + const Node* parent{ nullptr }; + YGNodeRef y_node{ nullptr }; + struct stat m_file_info { 0 }; + std::string m_path; + +public: + std::vector children; + glm::vec4 color; + glm::vec2 m_pos; + glm::vec2 m_size; + glm::vec4 m_clip; + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; + Node& operator=(Node&& o) { return Node(std::forward(o)); } + Node(Node&& o) + { + children = std::move(o.children); + for (auto& c : children) + c.parent = this; + parent = o.parent; + y_node = o.y_node; + m_pos = o.m_pos; + m_size = o.m_size; + m_clip = o.m_clip; + color = o.color; + m_file_info = o.m_file_info; + o.y_node = nullptr; + o.parent = nullptr; + } + Node() { y_node = YGNodeNew(); } + ~Node() + { + children.clear(); + if (y_node) + YGNodeFree(y_node); + } + + void SetWidth(float value) { YGNodeStyleSetWidth(y_node, value); } + 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 SetPadding(float t, float r, float b, float l) + { + YGNodeStyleSetPadding(y_node, YGEdgeTop, t); + YGNodeStyleSetPadding(y_node, YGEdgeRight, r); + YGNodeStyleSetPadding(y_node, YGEdgeBottom, b); + YGNodeStyleSetPadding(y_node, YGEdgeLeft, l); + } + + void SetFlexGrow(float value) { YGNodeStyleSetFlexGrow(y_node, value); } + void SetFlexShrink(float value) { YGNodeStyleSetFlexShrink(y_node, value); } + void SetFlexDir(YGFlexDirection value) { YGNodeStyleSetFlexDirection(y_node, value); } + void SetFlexWrap(YGWrap value) { YGNodeStyleSetFlexWrap(y_node, value); } + + glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b) + { + // convert from [x,y,w,h] to [x1,y1,x2,y1] + a = glm::vec4(a.xy(), a.xy() + a.zw()); + b = glm::vec4(b.xy(), b.xy() + b.zw()); + auto o = glm::vec4(glm::max(a.xy(), b.xy()), glm::min(a.zw(), b.zw())); + o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy())); + return o; + } + + void update(float width, float height); + void update_internal(glm::vec2 origin); + void parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr); + void load(const char* path); + void load_internal(const tinyxml2::XMLElement* x_node); + void reload(); +}; diff --git a/engine/shape.hpp b/engine/shape.hpp index 9119286..bb87e6b 100644 --- a/engine/shape.hpp +++ b/engine/shape.hpp @@ -1,99 +1,5 @@ #pragma once - -namespace att -{ - enum class kAttribute : uint8_t { - Width, MinWidth, MaxWidth, - Height, MinHeight, MaxHeight, - Divisions, InnerRadius, OuterRadius, - Grow, Shrink, FlexDir, FlexWrap, - Padding, Margin, - Color - }; - - struct AttributeBase - { - kAttribute id; - }; - - typedef std::map> AttrubutesMap; - - template - struct Attribute : public AttributeBase - { - static const kAttribute static_id = T; - V value; - Attribute() : value{0} { id = static_id; } - Attribute(V v) : value(v) { id = static_id; } - }; - - struct typemap - { - const char* name; - kAttribute value; - }; - static constexpr typemap map[] = - { - { "width", kAttribute::Width }, - { "min-width", kAttribute::MinWidth }, - { "max-width", kAttribute::MaxWidth }, - { "height", kAttribute::Height }, - { "min-height", kAttribute::MinHeight }, - { "max-height", kAttribute::MaxHeight }, - { "divisions", kAttribute::Divisions }, - { "inner-radius", kAttribute::InnerRadius }, - { "outer-radius", kAttribute::OuterRadius }, - { "grow", kAttribute::Grow }, - { "shrink", kAttribute::Shrink }, - { "dir", kAttribute::FlexDir }, - { "wrap", kAttribute::FlexWrap }, - { "pad", kAttribute::Padding }, - { "margin", kAttribute::Margin }, - { "color", kAttribute::Color }, - }; - constexpr int map_size = sizeof(map) / sizeof(typemap) - 1; - constexpr bool same(const char* a, const char* b) - { - return (*a && *b) ? (*a == *b && same(a + 1, b + 1)) : !(*a || *b); - } - constexpr const kAttribute value(char const *name, int i = 0) - { - return ((i >= map_size) || same(map[i].name, name)) ? - map[i].value : value(name, i + 1); - } - constexpr const char* string(const kAttribute value, int i = 0) - { - return (map[i].value == value) ? map[i].name : string(value, i + 1); - } - - //constexpr const char* string(kAttribute a) { return names[(int)a]; } - -// template -// constexpr const char* string(const Attribute a) { return names[(int)a.id]; } - -#define DECLARE_ATTRIBUTE(N,T) \ - struct N : public Attribute \ - { using Attribute::Attribute; }; - - DECLARE_ATTRIBUTE(Width, float); - DECLARE_ATTRIBUTE(MinWidth, float); - DECLARE_ATTRIBUTE(MaxWidth, float); - DECLARE_ATTRIBUTE(Height, float); - DECLARE_ATTRIBUTE(MinHeight, float); - DECLARE_ATTRIBUTE(MaxHeight, float); - DECLARE_ATTRIBUTE(Divisions, int); - DECLARE_ATTRIBUTE(InnerRadius, float); - DECLARE_ATTRIBUTE(OuterRadius, float); - DECLARE_ATTRIBUTE(Grow, float); - DECLARE_ATTRIBUTE(Shrink, float); - DECLARE_ATTRIBUTE(FlexDir, int); - DECLARE_ATTRIBUTE(FlexWrap, int); - DECLARE_ATTRIBUTE(Padding, glm::vec4); - DECLARE_ATTRIBUTE(Margin, glm::vec4); - DECLARE_ATTRIBUTE(Color, glm::vec4); - -#undef DECLARE_ATTRIBUTE -} +#include "layout.h" class Shape { @@ -104,8 +10,6 @@ protected: GLvoid* ioff[2]{ 0 }; struct vertex_t { glm::vec4 pos; glm::vec2 uvs; }; public: - YGNodeRef y_node; - glm::vec4 color; att::AttrubutesMap attribs; bool create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize); void draw_fill() const;