#include "pch.h" #include "app.hpp" App App::I; // singleton void App::create() { width = 800; height = 800; } 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) { float x = YGNodeLayoutGetLeft(y_current); float y = YGNodeLayoutGetTop(y_current); float w = YGNodeLayoutGetWidth(y_current); float h = YGNodeLayoutGetHeight(y_current); ctx = new glm::vec4(x, y, w, h); YGNodeSetContext(y_current, ctx); } 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); float pt = 0;//YGNodeLayoutGetPadding(y_current, YGEdgeTop); float pr = 0;//YGNodeLayoutGetPadding(y_current, YGEdgeRight); float pb = 0;//YGNodeLayoutGetPadding(y_current, YGEdgeBottom); float pl = 0;//YGNodeLayoutGetPadding(y_current, YGEdgeLeft); ctx_child->x = ctx->x + x + pl; ctx_child->y = ctx->y + y + pt; ctx_child->z = w - (pl + pr); ctx_child->w = h - (pt + pb); 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) { printf("Element %s: ", child->Name()); auto y_node = YGNodeNew(); stack.emplace(y_node, child); auto attr = child->FirstAttribute(); if (strcmp("plane", child->Name()) == 0) { auto shape = std::make_unique(); //shape->create<5>(100.f, 100.f); shape->y_node = y_node; shapes_list.push_back(std::move(shape)); YGNodeSetContext(y_node, shape.get()); } 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); while (attr) { const auto ka = att::value(attr->Name()); printf("%s=%s ", attr->Name(), attr->Value()); switch (ka) { case att::kAttribute::Width: 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 (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; } default: break; } attr = attr->Next(); } int n = YGNodeGetChildCount(y_root); YGNodeInsertChild(y_root, y_node, n); child = child->NextSiblingElement(); printf("\n"); } current = stack.size() ? stack.top() : NodePair{ nullptr, nullptr }; } update_layout(); } void App::init() { static const char* shader_v = "#version 150\n" "uniform mat4 mvp;" "in vec4 pos;" "in vec2 uvs;" "out vec3 uv;" "void main(){" " uv = vec3(uvs, pos.w);" " gl_Position = mvp * vec4(pos.xyz, 1.f);" "}"; static const char* shader_f = "#version 150\n" "uniform sampler2D tex;" "in vec3 uv;" "out vec4 frag;" "void main(){" //" frag = texture(tex, uv.xy/uv.z);" " frag = texture(tex, uv.xy);" "}"; static const char* shader_uv_f = "#version 150\n" "uniform sampler2D tex;" "in vec3 uv;" "out vec4 frag;" "void main(){" " frag = vec4(uv.xy,0,1);" "}"; static const char* shader_color_v = "#version 150\n" "uniform mat4 mvp;" "in vec4 pos;" "void main(){" " gl_Position = mvp * pos;" "}"; static const char* shader_color_f = "#version 150\n" "uniform vec4 col;" "out vec4 frag;" "void main(){" " frag = col;" "}"; load_layout(); 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); } 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"); glEnable(GL_TEXTURE); glDisable(GL_DEPTH_TEST); glPointSize(5); glLineWidth(4); //int n; //glGetIntegerv(GL_NUM_EXTENSIONS, &n); //for (int i = 0; i < n; i++) //{ // const unsigned char* s = glGetStringi(GL_EXTENSIONS, i); // printf("GL ext %03d: %s\n", i, s); //} printf("GL version: %s\n", glGetString(GL_VERSION)); printf("GL vendor: %s\n", glGetString(GL_VENDOR)); printf("GL renderer: %s\n", glGetString(GL_RENDERER)); GLfloat width_range[2]; glGetFloatv(GL_LINE_WIDTH_RANGE, width_range); printf("GL line range: %f - %f\n", width_range[0], width_range[1]); } 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(); /* 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); shader.use(); shader.u_int("tex", 0); shader_color.use(); shader_color.u_vec4("col", { .3f, .3f, .3f, 1 }); 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); auto layout = *reinterpret_cast(YGNodeGetContext(s->y_node)); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 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.use(); shader_color.u_mat4("mvp", mvp); plane.draw_stroke(); } tex.unbind(); sampler.unbind(); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //shader_color.use(); //shader_color.u_mat4("mvp", proj * glm::translate(glm::vec3{width/2, height/2, 0.f}) * glm::scale(glm::vec3(8))); //shader_color.u_vec4("col", {1, 1, 1, 1}); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //tex.bind(); //shader.use(); //shader.u_mat4("mvp", proj * glm::translate(glm::vec3{ width / 2, height / 2, 0.f }) * glm::scale(glm::vec3(8))); //shader.u_int("tex", 0); //circle3.draw_fill(); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //shader_color.use(); //shader_color.u_mat4("mvp", proj * glm::translate(glm::vec3{width/2, height/2, 0.f}) * glm::scale(glm::vec3(8))); //shader_color.u_vec4("col", {1, 1, 1, 1}); //glLineWidth(2); //circle3.draw_fill(); } void App::resize(float w, float h) { width = w; height = h; YGNodeStyleSetWidth(y_root, width); YGNodeStyleSetHeight(y_root, height); update_layout(); }