diff --git a/data/layout.xml b/data/layout.xml
index 8603411..42106ae 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -1,5 +1,13 @@
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/engine/app.cpp b/engine/app.cpp
index 425d0ec..078adf3 100644
--- a/engine/app.cpp
+++ b/engine/app.cpp
@@ -9,6 +9,39 @@ void App::create()
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);
+ ctx = new glm::vec2(x, y);
+ 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::vec2();
+ ctx_child->x = ctx->x + YGNodeLayoutGetLeft(y_child);
+ ctx_child->y = ctx->y + YGNodeLayoutGetTop(y_child);
+ YGNodeSetContext(y_child, ctx_child);
+ y_stack.emplace(y_child);
+ }
+ y_current = y_stack.size() ? y_stack.top() : nullptr;
+ }
+}
+
void App::init()
{
static const char* shader_v =
@@ -56,52 +89,131 @@ void App::init()
auto w = att::Width(10.f);
printf("type: %d\n", att::value("Height"));
- std::vector> s;
- auto y_root = YGNodeNew();
+ y_root = YGNodeNew();
+ YGNodeStyleSetWidth(y_root, width);
+ YGNodeStyleSetHeight(y_root, height);
+ YGNodeStyleSetFlexDirection(y_root, YGFlexDirectionRow);
+ YGNodeStyleSetFlexWrap(y_root, YGWrapWrap);
+ //YGNodeStyleSetJustifyContent(y_root, YGJustifyFlexStart);
+
+ using NodePair = std::pair;
+ std::stack stack;
+
tinyxml2::XMLDocument xml;
auto ret = xml.LoadFile("data\\layout.xml");
- auto root = xml.RootElement();
- auto child = root->FirstChildElement();
- while (child)
- {
- printf("Element %s: ", child->Name());
- auto attr = child->FirstAttribute();
- auto y_node = YGNodeNew();
- std::unique_ptr shape = std::make_unique();
- 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());
- shape->attribs[ka] = std::make_unique(attr->FloatValue());
- break;
- case att::kAttribute::Height:
- if (strchr(attr->Value(), '%'))
- YGNodeStyleSetHeightPercent(y_node, attr->FloatValue());
- else
- YGNodeStyleSetHeight(y_node, attr->FloatValue());
- shape->attribs[ka] = std::make_unique(attr->FloatValue());
- break;
- }
- attr = attr->Next();
- }
+ auto x_root = xml.RootElement();
- YGNodeInsertChild(y_root, y_node, 0);
- printf("\n");
- child = child->NextSiblingElement();
+ 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);
+ YGNodeStyleSetPadding(y_root, YGEdgeAll, 0);
+ YGNodeStyleSetMargin(y_root, YGEdgeAll, 0);
+ YGNodeStyleSetPositionType(y_root, YGPositionTypeRelative);
+ YGNodeStyleSetPosition(y_root, YGEdgeAll, 0);
+ YGNodeStyleSetPadding(y_root, YGEdgeAll, 0);
+ YGNodeStyleSetMargin(y_root, YGEdgeAll, 0);
+ 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());
+ }
+ 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;
+ }
+ 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();
+
+ 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>(50, 50);
+ plane.create<5>(1, 1);
circle.create<10>(25);
circle2.create<10>(25, Circle::kUVMapping::Tube);
circle3.create<10>(25, 12, Circle::kUVMapping::Tube);
@@ -111,11 +223,10 @@ void App::init()
if (!tex.load("data/uvs.jpg"))
printf("error loading image\n");
- glViewport(0, 0, width, height);
glEnable(GL_TEXTURE);
glDisable(GL_DEPTH_TEST);
glPointSize(5);
- glLineWidth(1);
+ glLineWidth(4);
//int n;
//glGetIntegerv(GL_NUM_EXTENSIONS, &n);
@@ -135,21 +246,15 @@ void App::init()
void App::update(float dt)
{
-// static float theta = 0;
-// theta += M_PI * 0.5f * dt;
-// float red = fabsf(sinf(theta));
-
-// glm::mat4 proj = glm::perspective(glm::radians(85.f), 1.f, .1f, 100.f);
-// glm::mat4 model = glm::translate(glm::vec3(0, 0, 0));
-// glm::mat4 view = glm::lookAt(glm::vec3(sinf(theta), 0, 1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
-
- glm::mat4 proj = glm::ortho(0.f, (float)width, (float)height, 0.f, -1.f, 1.f);
+ 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(red, 0, 0, 1);
+ glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glClear(GL_COLOR_BUFFER_BIT);
-
+
+/*
auto s = glm::scale(glm::vec3(1.5));
int h = 100;
for (int i = 0; i < sizeof(shapes)/sizeof(Shape*); i++)
@@ -184,6 +289,41 @@ void App::update(float dt)
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", { 0, 0, 1, 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 loc = 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(w, h, 1.f));
+ glm::mat4 pos = glm::translate(glm::vec3(*loc, 0));
+ auto mvp = proj * pos * scale * pivot;
+
+ shader_uv.use();
+ shader.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)));
@@ -203,3 +343,12 @@ void App::update(float dt)
//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();
+}
diff --git a/engine/app.hpp b/engine/app.hpp
index 4a1e200..e0806fa 100644
--- a/engine/app.hpp
+++ b/engine/app.hpp
@@ -11,15 +11,19 @@ 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;
public:
static App I;
- int width;
- int height;
+ float width;
+ float height;
void init();
void create();
void update(float dt);
+ void resize(float w, float h);
+ void update_layout();
};
diff --git a/engine/main.cpp b/engine/main.cpp
index 1805bf8..c31ce4a 100644
--- a/engine/main.cpp
+++ b/engine/main.cpp
@@ -211,7 +211,7 @@ int main()
PIXELFORMATDESCRIPTOR pfd;
App::I.create();
- RECT clientRect = { 0, 0, App::I.width, App::I.height };
+ RECT clientRect = { 0, 0, (int)App::I.width, (int)App::I.height };
// Inizialize data structures to zero
memset(&wc, 0, sizeof(wc));
@@ -288,7 +288,7 @@ int main()
wglDeleteContext(hRC);
DestroyWindow(hWnd);
- hWnd = CreateWindow(wc.lpszClassName, L"New Engine", WS_OVERLAPPEDWINDOW,
+ hWnd = CreateWindow(wc.lpszClassName, L"UI Layout Engine", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, clientRect.right - clientRect.left,
clientRect.bottom - clientRect.top, 0, 0, hInst, 0);
@@ -350,6 +350,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
case WM_CLOSE:
PostQuitMessage(0);
break;
+ case WM_SIZE:
+ App::I.resize((float)LOWORD(lp), (float)HIWORD(lp));
+ App::I.update(0.f);
+ SwapBuffers(hDC);
+ break;
case WM_KEYDOWN:
keys[wp] = true;
break;
diff --git a/engine/pch.h b/engine/pch.h
index c578d9c..7c7d3bb 100644
--- a/engine/pch.h
+++ b/engine/pch.h
@@ -1,7 +1,6 @@
#pragma once
#ifdef __APPLE__
- #include
#include
#elif _WIN32
#define _USE_MATH_DEFINES
@@ -13,6 +12,7 @@
#include