refactor layout.h into single file per Node* classes

This commit is contained in:
2017-05-13 21:58:04 +01:00
parent 51e355d039
commit 1f6c688258
55 changed files with 3600 additions and 2675 deletions

View File

@@ -163,6 +163,29 @@
<ClCompile Include="engine\layout.cpp" />
<ClCompile Include="engine\log.cpp" />
<ClCompile Include="engine\main.cpp" />
<ClCompile Include="engine\node.cpp" />
<ClCompile Include="engine\node_border.cpp" />
<ClCompile Include="engine\node_button.cpp" />
<ClCompile Include="engine\node_button_custom.cpp" />
<ClCompile Include="engine\node_canvas.cpp" />
<ClCompile Include="engine\node_checkbox.cpp" />
<ClCompile Include="engine\node_color_quad.cpp" />
<ClCompile Include="engine\node_dialog_open.cpp" />
<ClCompile Include="engine\node_icon.cpp" />
<ClCompile Include="engine\node_image.cpp" />
<ClCompile Include="engine\node_image_texture.cpp" />
<ClCompile Include="engine\node_message_box.cpp" />
<ClCompile Include="engine\node_panel_brush.cpp" />
<ClCompile Include="engine\node_panel_color.cpp" />
<ClCompile Include="engine\node_panel_layer.cpp" />
<ClCompile Include="engine\node_panel_stroke.cpp" />
<ClCompile Include="engine\node_popup_menu.cpp" />
<ClCompile Include="engine\node_settings.cpp" />
<ClCompile Include="engine\node_slider.cpp" />
<ClCompile Include="engine\node_stroke_preview.cpp" />
<ClCompile Include="engine\node_text.cpp" />
<ClCompile Include="engine\node_text_input.cpp" />
<ClCompile Include="engine\node_viewport.cpp" />
<ClCompile Include="engine\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
@@ -207,6 +230,29 @@
<ClInclude Include="engine\keymap.h" />
<ClInclude Include="engine\layout.h" />
<ClInclude Include="engine\log.h" />
<ClInclude Include="engine\node.h" />
<ClInclude Include="engine\node_border.h" />
<ClInclude Include="engine\node_button.h" />
<ClInclude Include="engine\node_button_custom.h" />
<ClInclude Include="engine\node_canvas.h" />
<ClInclude Include="engine\node_checkbox.h" />
<ClInclude Include="engine\node_color_quad.h" />
<ClInclude Include="engine\node_dialog_open.h" />
<ClInclude Include="engine\node_icon.h" />
<ClInclude Include="engine\node_image.h" />
<ClInclude Include="engine\node_image_texture.h" />
<ClInclude Include="engine\node_message_box.h" />
<ClInclude Include="engine\node_panel_brush.h" />
<ClInclude Include="engine\node_panel_color.h" />
<ClInclude Include="engine\node_panel_layer.h" />
<ClInclude Include="engine\node_panel_stroke.h" />
<ClInclude Include="engine\node_popup_menu.h" />
<ClInclude Include="engine\node_settings.h" />
<ClInclude Include="engine\node_slider.h" />
<ClInclude Include="engine\node_stroke_preview.h" />
<ClInclude Include="engine\node_text.h" />
<ClInclude Include="engine\node_text_input.h" />
<ClInclude Include="engine\node_viewport.h" />
<ClInclude Include="engine\pch.h" />
<ClInclude Include="engine\rtt.h" />
<ClInclude Include="engine\shader.h" />

View File

@@ -13,6 +13,12 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\ui">
<UniqueIdentifier>{600b8daa-4234-4c37-b4ba-c22cad7d1dc3}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\ui">
<UniqueIdentifier>{2c3e7ce5-d3f4-4731-b05f-5e288c7e6e63}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="engine\app.cpp">
@@ -45,9 +51,6 @@
<ClCompile Include="libs\yoga\yoga\Yoga.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="engine\layout.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="engine\font.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -81,6 +84,78 @@
<ClCompile Include="engine\canvas_modes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="engine\node.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_border.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_button.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_button_custom.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_canvas.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_checkbox.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_color_quad.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_dialog_open.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_icon.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_image.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_image_texture.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_message_box.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_panel_brush.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_panel_color.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_panel_layer.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_panel_stroke.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_popup_menu.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_settings.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_slider.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_stroke_preview.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_text.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_text_input.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\node_viewport.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
<ClCompile Include="engine\layout.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="engine\app.h">
@@ -101,9 +176,6 @@
<ClInclude Include="engine\texture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="engine\layout.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="engine\font.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -140,5 +212,77 @@
<ClInclude Include="engine\canvas_modes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="engine\node.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_border.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_button.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_button_custom.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_canvas.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_checkbox.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_color_quad.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_dialog_open.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_icon.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_image.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_image_texture.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_message_box.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_panel_brush.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_panel_color.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_panel_layer.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_panel_stroke.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_popup_menu.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_settings.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_slider.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_stroke_preview.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_text.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_text_input.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_viewport.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\layout.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -1,6 +1,8 @@
#include "pch.h"
#include "log.h"
#include "app.h"
#include "node_icon.h"
#include "node_dialog_open.h"
using namespace ui;

View File

@@ -6,6 +6,14 @@
#include "texture.h"
#include "layout.h"
#include "font.h"
#include "node_message_box.h"
#include "node_settings.h"
#include "node_popup_menu.h"
#include "node_panel_brush.h"
#include "node_panel_layer.h"
#include "node_panel_color.h"
#include "node_panel_stroke.h"
#include "node_canvas.h"
class App
{

View File

@@ -154,7 +154,7 @@ public:
m_canvas->m_layers[m_layer_idx].m_rtt[i].bindTexture();
glm::vec2 box_sz = m_box[i].zw() - m_box[i].xy();
glTexSubImage2D(GL_TEXTURE_2D, 0, m_box[i].x, m_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get());
glTexSubImage2D(GL_TEXTURE_2D, 0, (int)m_box[i].x, (int)m_box[i].y, (int)box_sz.x, (int)box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get());
m_canvas->m_layers[m_layer_idx].m_rtt[i].unbindTexture();
}
}
@@ -163,7 +163,7 @@ public:
size_t mem = 0;
for (int i = 0; i < 6; i++)
{
glm::vec2 sz = m_box[i].zw() - m_box[i].xy();
glm::ivec2 sz = m_box[i].zw() - m_box[i].xy();
mem += sz.x * sz.y * 4 + sizeof(*this);
}
return mem;

View File

@@ -4,6 +4,7 @@
#include "layout.h"
#include "canvas.h"
#include "shader.h"
#include "node_canvas.h"
NodeCanvas* CanvasMode::node;
ui::Canvas* CanvasMode::canvas;

View File

@@ -3,537 +3,8 @@
#include "layout.h"
#include "util.h"
#include "asset.h"
using namespace ui;
Plane NodeBorder::m_plane;
Plane NodeImage::m_plane;
Sampler NodeImage::m_sampler;
std::map<std::string, glm::vec4> NodeIcon::m_icons;
kEventResult Node::on_event(Event* e)
{
if (current_mouse_capture)
return current_mouse_capture->on_event(e);
kEventResult ret = kEventResult::Available;
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it)
{
if ((*it)->on_event(e) == kEventResult::Consumed)
{
if (m_flood_events)
{
ret = kEventResult::Consumed;
}
else
{
return kEventResult::Consumed;
}
}
}
if (ret == kEventResult::Consumed)
return ret;
switch (e->m_cat)
{
case kEventCategory::MouseEvent:
{
if (m_mouse_ignore)
break;
MouseEvent* me = static_cast<MouseEvent*>(e);
bool inside = point_in_rect(me->m_pos, m_clip);
bool inside_old = m_mouse_inside;
m_mouse_inside = inside;
switch (e->m_type)
{
case kEventType::MouseDownL:
case kEventType::MouseDownR:
case kEventType::MouseUpL:
case kEventType::MouseUpR:
if ((inside || m_mouse_captured) && handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
case kEventType::MouseMove:
if (inside_old == false && inside == true)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseEnter;
handle_event(&e2);
}
if (inside || m_mouse_captured)
ret = handle_event(e);
if (inside_old == true && inside == false)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseLeave;
handle_event(&e2);
}
break;
default:
if (handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
break;
}
default:
if (handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
return ret;
}
const Node* Node::init_template(const char* id)
{
const auto& m_template = static_cast<Node*>((*m_manager)[const_hash(id)]->m_children[0].get());
for (auto& c : m_template->m_children)
{
auto node = c->clone();
add_child(node);
node->init();
node->create();
node->loaded();
}
YGNodeCopyStyle(y_node, m_template->y_node);
return m_template;
}
void Node::add_child(Node* n)
{
m_children.emplace_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
}
void Node::add_child(Node* n, int index)
{
m_children.emplace_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, index);
}
void Node::add_child(std::shared_ptr<Node> n)
{
m_children.push_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
}
void Node::add_child(std::shared_ptr<Node> n, int index)
{
m_children.push_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, index);
}
void Node::remove_child(Node* n)
{
auto i = std::find_if(m_children.begin(), m_children.end(), [=](auto& ptr) { return ptr.get() == n; });
if (i != m_children.end())
{
YGNodeRemoveChild(y_node, n->y_node);
m_children.erase(i);
}
}
void Node::remove_all_children()
{
for (auto& n : m_children)
YGNodeRemoveChild(y_node, n->y_node);
m_children.clear();
}
void Node::move_child(Node* n, int index)
{
YGNodeRemoveChild(y_node, n->y_node);
YGNodeInsertChild(y_node, n->y_node, index);
}
void Node::move_child_offset(Node* n, int offset)
{
int count = YGNodeGetChildCount(y_node);
for (int i = 0; i < count; i++)
{
if (YGNodeGetChild(y_node, i) == n->y_node)
{
int new_index = glm::clamp<int>(i + offset, 0, count - 1);
YGNodeRemoveChild(y_node, n->y_node);
YGNodeInsertChild(y_node, n->y_node, new_index);
break;
}
}
}
int Node::get_child_index(Node* n)
{
int count = YGNodeGetChildCount(y_node);
for (int i = 0; i < count; i++)
{
if (YGNodeGetChild(y_node, i) == n->y_node)
{
return i;
}
}
return -1;
}
void Node::update(float width, float height, float zoom)
{
m_zoom = zoom;
YGNodeStyleSetWidth(y_node, width / zoom);
YGNodeStyleSetHeight(y_node, height / zoom);
YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR);
m_proj = glm::ortho(0.f, width / zoom, height / zoom, 0.f, -1.f, 1.f);
update_internal({ 0, 0 }, m_proj);
}
void Node::update()
{
YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR);
update_internal({ 0, 0 }, m_proj);
}
void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj)
{
float x = YGNodeLayoutGetLeft(y_node);
float y = YGNodeLayoutGetTop(y_node);
float w = YGNodeLayoutGetWidth(y_node);
float h = YGNodeLayoutGetHeight(y_node);
auto old_size = m_size;
m_pos = glm::floor(origin + glm::vec2(x, y));
m_size = glm::floor(glm::vec2(w, h));
if (parent)
{
// correct the padding clip
// should not clip the padded area
// useful to draw decorations
float pt = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeTop);
float pr = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeRight);
float pb = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeBottom);
float pl = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeLeft);
glm::vec2 off_p(pl, pt);
glm::vec2 off_s(pr, pb);
m_clip_uncut = glm::vec4(m_pos - off_p, m_size + off_p + off_s);
m_clip = rect_intersection(m_clip_uncut, parent->m_clip);
}
else
{
m_clip = glm::vec4(m_pos, m_size);
}
glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f));
glm::mat4 scale = glm::scale(glm::vec3(m_size, 1.f));
glm::mat4 prescale = glm::scale(glm::vec3(m_scale, 1.f));
glm::mat4 pos = glm::translate(glm::vec3(m_pos, 0));
m_mvp = proj * pos * scale * pivot * prescale;
m_proj = proj;
for (int i = 0; i < m_children.size(); i++)
{
if (m_children[i]->m_destroyed)
{
remove_child(m_children[i].get());
i--;
}
}
if (m_size != old_size)
handle_resize(old_size, m_size);
for (auto& c : m_children)
c->update_internal(m_pos, proj);
}
void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
switch (ka)
{
case kAttribute::id:
m_nodeID_s = attr->Value();
m_nodeID = const_hash(attr->Value());
break;
case 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 kAttribute::MinWidth:
YGNodeStyleSetMinWidth(y_node, attr->FloatValue());
break;
case kAttribute::MaxWidth:
YGNodeStyleSetMaxWidth(y_node, attr->FloatValue());
break;
case 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 kAttribute::MinHeight:
YGNodeStyleSetMinHeight(y_node, attr->FloatValue());
break;
case kAttribute::MaxHeight:
YGNodeStyleSetMaxHeight(y_node, attr->FloatValue());
break;
case kAttribute::Grow:
YGNodeStyleSetFlexGrow(y_node, attr->FloatValue());
break;
case kAttribute::Shrink:
YGNodeStyleSetFlexShrink(y_node, attr->FloatValue());
break;
case 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 kAttribute::FlexWrap:
YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap);
break;
case kAttribute::Justify:
{
YGJustify v = YGJustifyFlexStart;
if (strcmp("center", attr->Value()) == 0)
v = YGJustifyCenter;
else if (strcmp("flex-start", attr->Value()) == 0)
v = YGJustifyFlexStart;
else if (strcmp("flex-end", attr->Value()) == 0)
v = YGJustifyFlexEnd;
else if (strcmp("space-around", attr->Value()) == 0)
v = YGJustifySpaceAround;
else if (strcmp("space-between", attr->Value()) == 0)
v = YGJustifySpaceBetween;
YGNodeStyleSetJustifyContent(y_node, v);
break;
}
case kAttribute::Align:
{
YGAlign v = YGAlignStretch;
if (strcmp("stretch", attr->Value()) == 0)
v = YGAlignStretch;
else if (strcmp("flex-start", attr->Value()) == 0)
v = YGAlignFlexStart;
else if (strcmp("flex-end", attr->Value()) == 0)
v = YGAlignFlexEnd;
else if (strcmp("center", attr->Value()) == 0)
v = YGAlignCenter;
YGNodeStyleSetAlignItems(y_node, v);
break;
}
case kAttribute::Positioning:
{
YGPositionType v = YGPositionTypeRelative;
if (strcmp("relative", attr->Value()) == 0)
v = YGPositionTypeRelative;
else if (strcmp("absolute", attr->Value()) == 0)
v = YGPositionTypeAbsolute;
YGNodeStyleSetPositionType(y_node, v);
break;
}
case kAttribute::Position:
{
glm::vec4 v;
int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
if (n == 2)
{
YGNodeStyleSetPosition(y_node, YGEdgeLeft, v.x);
YGNodeStyleSetPosition(y_node, YGEdgeTop, v.y);
}
else
{
YGNodeStyleSetPadding(y_node, YGEdgeLeft, v.x);
YGNodeStyleSetPadding(y_node, YGEdgeTop, v.y);
YGNodeStyleSetPadding(y_node, YGEdgeRight, v.z);
YGNodeStyleSetPadding(y_node, YGEdgeBottom, v.w);
}
break;
}
case 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 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 kAttribute::FloodEvents:
m_flood_events = attr->IntValue() > 0;
break;
default:
break;
}
}
void Node::load_internal(const tinyxml2::XMLElement* x_node)
{
m_name = x_node->Name();
init();
auto attr = x_node->FirstAttribute();
while (attr)
{
parse_attributes((kAttribute)const_hash(attr->Name()), attr);
attr = attr->Next();
}
create();
auto x_child = x_node->FirstChildElement();
while (x_child)
{
kWidget child_id = (kWidget)const_hash(x_child->Name());
switch (child_id)
{
#define CASE(W,C) case W: { auto n = new C(); add_child(n); n->load_internal(x_child); break; }
CASE(kWidget::Node, Node);
CASE(kWidget::Border, NodeBorder);
CASE(kWidget::Image, NodeImage);
CASE(kWidget::ImageTexture, NodeImageTexture);
CASE(kWidget::Icon, NodeIcon);
CASE(kWidget::Text, NodeText);
CASE(kWidget::TextInput, NodeTextInput);
CASE(kWidget::Button , NodeButton);
CASE(kWidget::ButtonCustom, NodeButtonCustom);
CASE(kWidget::SliderH, NodeSliderH);
CASE(kWidget::SliderV, NodeSliderV);
CASE(kWidget::SliderHue, NodeSliderHue);
CASE(kWidget::PopupMenu, NodePopupMenu);
CASE(kWidget::Viewport, NodeViewport);
CASE(kWidget::CheckBox, NodeCheckBox);
CASE(kWidget::Layer, NodeLayer);
CASE(kWidget::PanelLayer, NodePanelLayer);
CASE(kWidget::PanelBrush, NodePanelBrush);
CASE(kWidget::PanelColor, NodePanelColor);
CASE(kWidget::PanelStroke, NodePanelStroke);
CASE(kWidget::ColorQuad, NodeColorQuad);
CASE(kWidget::StrokePreview, NodeStrokePreview);
CASE(kWidget::Canvas, NodeCanvas);
#undef CASE
case kWidget::Ref:
{
auto ids = x_child->Attribute("id");
auto id = const_hash(ids);
auto& ref = (*m_manager)[id]->m_children[0];
auto n = ref->clone();
n->m_nodeID_s = ids;
n->m_nodeID = id;
add_child(n);
break;
}
default:
{
LOG("instancing UNKNOWN node: %s", x_child->Name());
auto n = new Node();
add_child(n);
n->load_internal(x_child);
break;
}
}
x_child = x_child->NextSiblingElement();
}
loaded();
}
Node* Node::clone()
{
Node* n = clone_instantiate();
clone_copy(n);
clone_children(n);
clone_finalize(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;
dest->m_name = m_name;
dest->m_nodeID_s = m_nodeID_s;
dest->m_nodeID = m_nodeID;
dest->m_display = m_display;
dest->m_pos = m_pos;
dest->m_size = m_size;
dest->m_clip = m_clip;
dest->m_flood_events = m_flood_events;
}
void Node::clone_children(Node* dest) const
{
for (auto& c : m_children)
{
Node* cn = c->clone();
dest->m_children.emplace_back(cn);
cn->parent = dest;
cn->m_manager = dest->m_manager;
YGNodeInsertChild(dest->y_node, cn->y_node, YGNodeGetChildCount(dest->y_node));
}
}
#include "node.h"
#include "node_border.h"
bool LayoutManager::load(const char* path)
{

File diff suppressed because it is too large Load Diff

804
engine/node.cpp Normal file
View File

@@ -0,0 +1,804 @@
#include "pch.h"
#include "log.h"
#include "node.h"
#include "layout.h"
#include "util.h"
#include "asset.h"
#include "node_border.h"
#include "node_image.h"
#include "node_image_texture.h"
#include "node_icon.h"
#include "node_text.h"
#include "node_text_input.h"
#include "node_button.h"
#include "node_button_custom.h"
#include "node_slider.h"
#include "node_popup_menu.h"
#include "node_viewport.h"
#include "node_checkbox.h"
#include "node_panel_layer.h"
#include "node_panel_brush.h"
#include "node_panel_color.h"
#include "node_panel_stroke.h"
#include "node_color_quad.h"
#include "node_stroke_preview.h"
#include "node_canvas.h"
void Node::watch(std::function<void(Node*)> observer)
{
observer(this);
for (auto& c : m_children)
c->watch(observer);
}
void Node::destroy()
{
m_destroyed = true;
}
Node* Node::root()
{
Node* ret = this;
while (ret->parent)
ret = ret->parent;
return ret;
}
kEventResult Node::on_event(Event* e)
{
if (current_mouse_capture)
return current_mouse_capture->on_event(e);
kEventResult ret = kEventResult::Available;
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it)
{
if ((*it)->on_event(e) == kEventResult::Consumed)
{
if (m_flood_events)
{
ret = kEventResult::Consumed;
}
else
{
return kEventResult::Consumed;
}
}
}
if (ret == kEventResult::Consumed)
return ret;
switch (e->m_cat)
{
case kEventCategory::MouseEvent:
{
if (m_mouse_ignore)
break;
MouseEvent* me = static_cast<MouseEvent*>(e);
bool inside = point_in_rect(me->m_pos, m_clip);
bool inside_old = m_mouse_inside;
m_mouse_inside = inside;
switch (e->m_type)
{
case kEventType::MouseDownL:
case kEventType::MouseDownR:
case kEventType::MouseUpL:
case kEventType::MouseUpR:
if ((inside || m_mouse_captured) && handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
case kEventType::MouseMove:
if (inside_old == false && inside == true)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseEnter;
handle_event(&e2);
}
if (inside || m_mouse_captured)
ret = handle_event(e);
if (inside_old == true && inside == false)
{
MouseEvent e2 = *me;
e2.m_type = kEventType::MouseLeave;
handle_event(&e2);
}
break;
default:
if (handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
break;
}
default:
if (handle_event(e) == kEventResult::Consumed)
return kEventResult::Consumed;
break;
}
return ret;
}
kEventResult Node::handle_event(Event* e)
{
return kEventResult::Available;
}
void Node::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
{
}
void Node::create()
{
}
void Node::init()
{
}
void Node::loaded()
{
}
const Node* Node::init_template(const char* id)
{
const auto& m_template = static_cast<Node*>((*m_manager)[const_hash(id)]->m_children[0].get());
for (auto& c : m_template->m_children)
{
auto node = c->clone();
add_child(node);
node->init();
node->create();
node->loaded();
}
YGNodeCopyStyle(y_node, m_template->y_node);
return m_template;
}
void Node::add_child(Node* n)
{
m_children.emplace_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
}
void Node::add_child(Node* n, int index)
{
m_children.emplace_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, index);
}
void Node::add_child(std::shared_ptr<Node> n)
{
m_children.push_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, YGNodeGetChildCount(y_node));
}
void Node::add_child(std::shared_ptr<Node> n, int index)
{
m_children.push_back(n);
n->parent = this;
n->m_manager = m_manager;
YGNodeInsertChild(y_node, n->y_node, index);
}
void Node::remove_child(Node* n)
{
auto i = std::find_if(m_children.begin(), m_children.end(), [=](auto& ptr) { return ptr.get() == n; });
if (i != m_children.end())
{
YGNodeRemoveChild(y_node, n->y_node);
m_children.erase(i);
}
}
void Node::remove_all_children()
{
for (auto& n : m_children)
YGNodeRemoveChild(y_node, n->y_node);
m_children.clear();
}
void Node::move_child(Node* n, int index)
{
YGNodeRemoveChild(y_node, n->y_node);
YGNodeInsertChild(y_node, n->y_node, index);
}
void Node::move_child_offset(Node* n, int offset)
{
int count = YGNodeGetChildCount(y_node);
for (int i = 0; i < count; i++)
{
if (YGNodeGetChild(y_node, i) == n->y_node)
{
int new_index = glm::clamp<int>(i + offset, 0, count - 1);
YGNodeRemoveChild(y_node, n->y_node);
YGNodeInsertChild(y_node, n->y_node, new_index);
break;
}
}
}
int Node::get_child_index(Node* n)
{
int count = YGNodeGetChildCount(y_node);
for (int i = 0; i < count; i++)
{
if (YGNodeGetChild(y_node, i) == n->y_node)
{
return i;
}
}
return -1;
}
void Node::mouse_capture()
{
root()->current_mouse_capture = this; m_mouse_captured = true;
}
void Node::mouse_release()
{
root()->current_mouse_capture = nullptr; m_mouse_captured = false;
}
void Node::key_capture()
{
root()->current_key_capture = this; m_key_captured = true;
}
void Node::key_release()
{
root()->current_key_capture = nullptr; m_key_captured = false;
}
Node&& Node::operator=(Node&& o)
{
return std::forward<Node>(o);
}
Node::Node()
{
y_node = YGNodeNew();
}
Node::Node(Node&& o)
{
m_name = std::move(o.m_name);
m_nodeID_s = std::move(o.m_nodeID_s);
m_children = std::move(o.m_children);
for (auto& c : m_children)
c->parent = this;
m_nodeID = o.m_nodeID;
m_display = o.m_display;
parent = o.parent;
y_node = o.y_node;
m_pos = o.m_pos;
m_size = o.m_size;
m_clip = o.m_clip;
m_zoom = o.m_zoom;
m_mouse_ignore = o.m_mouse_ignore;
o.y_node = nullptr;
o.parent = nullptr;
}
Node::~Node()
{
m_children.clear();
if (y_node)
YGNodeFree(y_node);
}
void Node::SetWidth(float value)
{
YGNodeStyleSetWidth(y_node, value);
}
void Node::SetWidthP(float value)
{
YGNodeStyleSetWidthPercent(y_node, value);
}
void Node::SetHeight(float value)
{
YGNodeStyleSetHeight(y_node, value);
}
void Node::SetHeightP(float value)
{
YGNodeStyleSetHeightPercent(y_node, value);
}
void Node::SetSize(float w, float h)
{
SetWidth(w); SetHeight(h);
}
void Node::SetSize(glm::vec2 value)
{
SetWidth(value.x); SetHeight(value.y);
}
void Node::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 Node::SetPosition(const glm::vec2 pos)
{
SetPosition(pos.x, pos.y);
}
void Node::SetPosition(float l, float t)
{
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
}
void Node::SetPosition(float l, float t, float r, float b)
{
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(y_node, YGEdgeRight, r);
YGNodeStyleSetPosition(y_node, YGEdgeBottom, b);
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
}
void Node::SetFlexGrow(float value)
{
YGNodeStyleSetFlexGrow(y_node, value);
}
void Node::SetFlexShrink(float value)
{
YGNodeStyleSetFlexShrink(y_node, value);
}
void Node::SetFlexDir(YGFlexDirection value)
{
YGNodeStyleSetFlexDirection(y_node, value);
}
void Node::SetFlexWrap(YGWrap value)
{
YGNodeStyleSetFlexWrap(y_node, value);
}
void Node::SetJustify(YGJustify value)
{
YGNodeStyleSetJustifyContent(y_node, value);
}
void Node::SetAlign(YGAlign value)
{
YGNodeStyleSetAlignItems(y_node, value);
}
void Node::SetPositioning(YGPositionType value)
{
YGNodeStyleSetPositionType(y_node, value);
}
void Node::SetAspectRatio(float ar)
{
YGNodeStyleSetAspectRatio(y_node, ar);
}
glm::vec2 Node::GetPosition()
{
return{ YGNodeLayoutGetLeft(y_node), YGNodeLayoutGetTop(y_node) };
}
float Node::GetWidth()
{
return YGNodeLayoutGetWidth(y_node);
}
float Node::GetHeight()
{
return YGNodeLayoutGetHeight(y_node);
}
glm::vec2 Node::GetSize()
{
return{ GetWidth(), GetHeight() };
}
glm::vec4 Node::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 Node::restore_context()
{
for (auto& c : m_children)
c->restore_context();
}
void Node::clear_context()
{
for (auto& c : m_children)
c->clear_context();
}
void Node::update(float width, float height, float zoom)
{
m_zoom = zoom;
YGNodeStyleSetWidth(y_node, width / zoom);
YGNodeStyleSetHeight(y_node, height / zoom);
YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR);
m_proj = glm::ortho(0.f, width / zoom, height / zoom, 0.f, -1.f, 1.f);
update_internal({ 0, 0 }, m_proj);
}
void Node::update()
{
YGNodeCalculateLayout(y_node, YGUndefined, YGUndefined, YGDirectionLTR);
update_internal({ 0, 0 }, m_proj);
}
void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj)
{
float x = YGNodeLayoutGetLeft(y_node);
float y = YGNodeLayoutGetTop(y_node);
float w = YGNodeLayoutGetWidth(y_node);
float h = YGNodeLayoutGetHeight(y_node);
auto old_size = m_size;
m_pos = glm::floor(origin + glm::vec2(x, y));
m_size = glm::floor(glm::vec2(w, h));
if (parent)
{
// correct the padding clip
// should not clip the padded area
// useful to draw decorations
float pt = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeTop);
float pr = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeRight);
float pb = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeBottom);
float pl = 0;//YGNodeLayoutGetPadding(parent->y_node, YGEdgeLeft);
glm::vec2 off_p(pl, pt);
glm::vec2 off_s(pr, pb);
m_clip_uncut = glm::vec4(m_pos - off_p, m_size + off_p + off_s);
m_clip = rect_intersection(m_clip_uncut, parent->m_clip);
}
else
{
m_clip = glm::vec4(m_pos, m_size);
}
glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f));
glm::mat4 scale = glm::scale(glm::vec3(m_size, 1.f));
glm::mat4 prescale = glm::scale(glm::vec3(m_scale, 1.f));
glm::mat4 pos = glm::translate(glm::vec3(m_pos, 0));
m_mvp = proj * pos * scale * pivot * prescale;
m_proj = proj;
for (int i = 0; i < m_children.size(); i++)
{
if (m_children[i]->m_destroyed)
{
remove_child(m_children[i].get());
i--;
}
}
if (m_size != old_size)
handle_resize(old_size, m_size);
for (auto& c : m_children)
c->update_internal(m_pos, proj);
}
void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
switch (ka)
{
case kAttribute::id:
m_nodeID_s = attr->Value();
m_nodeID = const_hash(attr->Value());
break;
case 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 kAttribute::MinWidth:
YGNodeStyleSetMinWidth(y_node, attr->FloatValue());
break;
case kAttribute::MaxWidth:
YGNodeStyleSetMaxWidth(y_node, attr->FloatValue());
break;
case 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 kAttribute::MinHeight:
YGNodeStyleSetMinHeight(y_node, attr->FloatValue());
break;
case kAttribute::MaxHeight:
YGNodeStyleSetMaxHeight(y_node, attr->FloatValue());
break;
case kAttribute::Grow:
YGNodeStyleSetFlexGrow(y_node, attr->FloatValue());
break;
case kAttribute::Shrink:
YGNodeStyleSetFlexShrink(y_node, attr->FloatValue());
break;
case 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 kAttribute::FlexWrap:
YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap);
break;
case kAttribute::Justify:
{
YGJustify v = YGJustifyFlexStart;
if (strcmp("center", attr->Value()) == 0)
v = YGJustifyCenter;
else if (strcmp("flex-start", attr->Value()) == 0)
v = YGJustifyFlexStart;
else if (strcmp("flex-end", attr->Value()) == 0)
v = YGJustifyFlexEnd;
else if (strcmp("space-around", attr->Value()) == 0)
v = YGJustifySpaceAround;
else if (strcmp("space-between", attr->Value()) == 0)
v = YGJustifySpaceBetween;
YGNodeStyleSetJustifyContent(y_node, v);
break;
}
case kAttribute::Align:
{
YGAlign v = YGAlignStretch;
if (strcmp("stretch", attr->Value()) == 0)
v = YGAlignStretch;
else if (strcmp("flex-start", attr->Value()) == 0)
v = YGAlignFlexStart;
else if (strcmp("flex-end", attr->Value()) == 0)
v = YGAlignFlexEnd;
else if (strcmp("center", attr->Value()) == 0)
v = YGAlignCenter;
YGNodeStyleSetAlignItems(y_node, v);
break;
}
case kAttribute::Positioning:
{
YGPositionType v = YGPositionTypeRelative;
if (strcmp("relative", attr->Value()) == 0)
v = YGPositionTypeRelative;
else if (strcmp("absolute", attr->Value()) == 0)
v = YGPositionTypeAbsolute;
YGNodeStyleSetPositionType(y_node, v);
break;
}
case kAttribute::Position:
{
glm::vec4 v;
int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
if (n == 2)
{
YGNodeStyleSetPosition(y_node, YGEdgeLeft, v.x);
YGNodeStyleSetPosition(y_node, YGEdgeTop, v.y);
}
else
{
YGNodeStyleSetPadding(y_node, YGEdgeLeft, v.x);
YGNodeStyleSetPadding(y_node, YGEdgeTop, v.y);
YGNodeStyleSetPadding(y_node, YGEdgeRight, v.z);
YGNodeStyleSetPadding(y_node, YGEdgeBottom, v.w);
}
break;
}
case 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 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 kAttribute::FloodEvents:
m_flood_events = attr->IntValue() > 0;
break;
default:
break;
}
}
void Node::load_internal(const tinyxml2::XMLElement* x_node)
{
m_name = x_node->Name();
init();
auto attr = x_node->FirstAttribute();
while (attr)
{
parse_attributes((kAttribute)const_hash(attr->Name()), attr);
attr = attr->Next();
}
create();
auto x_child = x_node->FirstChildElement();
while (x_child)
{
kWidget child_id = (kWidget)const_hash(x_child->Name());
switch (child_id)
{
#define CASE(W,C) case W: { auto n = new C(); add_child(n); n->load_internal(x_child); break; }
CASE(kWidget::Node, Node);
CASE(kWidget::Border, NodeBorder);
CASE(kWidget::Image, NodeImage);
CASE(kWidget::ImageTexture, NodeImageTexture);
CASE(kWidget::Icon, NodeIcon);
CASE(kWidget::Text, NodeText);
CASE(kWidget::TextInput, NodeTextInput);
CASE(kWidget::Button, NodeButton);
CASE(kWidget::ButtonCustom, NodeButtonCustom);
CASE(kWidget::SliderH, NodeSliderH);
CASE(kWidget::SliderV, NodeSliderV);
CASE(kWidget::SliderHue, NodeSliderHue);
CASE(kWidget::PopupMenu, NodePopupMenu);
CASE(kWidget::Viewport, NodeViewport);
CASE(kWidget::CheckBox, NodeCheckBox);
CASE(kWidget::Layer, NodeLayer);
CASE(kWidget::PanelLayer, NodePanelLayer);
CASE(kWidget::PanelBrush, NodePanelBrush);
CASE(kWidget::PanelColor, NodePanelColor);
CASE(kWidget::PanelStroke, NodePanelStroke);
CASE(kWidget::ColorQuad, NodeColorQuad);
CASE(kWidget::StrokePreview, NodeStrokePreview);
CASE(kWidget::Canvas, NodeCanvas);
#undef CASE
case kWidget::Ref:
{
auto ids = x_child->Attribute("id");
auto id = const_hash(ids);
auto& ref = (*m_manager)[id]->m_children[0];
auto n = ref->clone();
n->m_nodeID_s = ids;
n->m_nodeID = id;
add_child(n);
break;
}
default:
{
LOG("instancing UNKNOWN node: %s", x_child->Name());
auto n = new Node();
add_child(n);
n->load_internal(x_child);
break;
}
}
x_child = x_child->NextSiblingElement();
}
loaded();
}
void Node::draw()
{
}
Node* Node::clone()
{
Node* n = clone_instantiate();
clone_copy(n);
clone_children(n);
clone_finalize(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;
dest->m_name = m_name;
dest->m_nodeID_s = m_nodeID_s;
dest->m_nodeID = m_nodeID;
dest->m_display = m_display;
dest->m_pos = m_pos;
dest->m_size = m_size;
dest->m_clip = m_clip;
dest->m_flood_events = m_flood_events;
}
void Node::clone_children(Node* dest) const
{
for (auto& c : m_children)
{
Node* cn = c->clone();
dest->m_children.emplace_back(cn);
cn->parent = dest;
cn->m_manager = dest->m_manager;
YGNodeInsertChild(dest->y_node, cn->y_node, YGNodeGetChildCount(dest->y_node));
}
}
void Node::clone_finalize(Node* dest) const
{
/* find controllers and stuff */
}

185
engine/node.h Normal file
View File

@@ -0,0 +1,185 @@
#pragma once
#include "event.h"
enum class kAttribute : uint16_t
{
id = const_hash("id"),
Width = const_hash("width"),
MinWidth = const_hash("min-width"),
MaxWidth = const_hash("max-width"),
Height = const_hash("height"),
MinHeight = const_hash("min-height"),
MaxHeight = const_hash("max-height"),
Divisions = const_hash("divisions"),
InnerRadius = const_hash("inner-radius"),
OuterRadius = const_hash("outer-radius"),
Grow = const_hash("grow"),
Shrink = const_hash("shrink"),
FlexDir = const_hash("dir"),
FlexWrap = const_hash("wrap"),
Padding = const_hash("pad"),
Margin = const_hash("margin"),
Color = const_hash("color"),
Thickness = const_hash("thickness"),
BorderColor = const_hash("border-color"),
Type = const_hash("type"),
Text = const_hash("text"),
FontFace = const_hash("font-face"),
FontSize = const_hash("font-size"),
Justify = const_hash("justify"),
Align = const_hash("align"),
Path = const_hash("path"),
Region = const_hash("region"),
Position = const_hash("position"),
Positioning = const_hash("positioning"),
FloodEvents = const_hash("flood-events"),
Icon = const_hash("icon"),
Selected = const_hash("selected"),
Template = const_hash("template"),
Value = const_hash("value"),
Range = const_hash("range"),
};
enum class kWidget : uint16_t
{
Node = const_hash("node"),
Border = const_hash("border"),
Shape = const_hash("shape"),
Text = const_hash("text"),
TextInput = const_hash("text-input"),
Image = const_hash("image"),
ImageTexture = const_hash("image-texture"),
Icon = const_hash("icon"),
Button = const_hash("button"),
ButtonCustom = const_hash("button-custom"),
SliderH = const_hash("slider-h"),
SliderV = const_hash("slider-v"),
SliderHue = const_hash("slider-hue"),
PopupMenu = const_hash("popup-menu"),
Viewport = const_hash("viewport"),
Ref = const_hash("ref"),
CheckBox = const_hash("checkbox"),
Layer = const_hash("layer"),
PanelLayer = const_hash("panel-layer"),
PanelBrush = const_hash("panel-brush"),
PanelColor = const_hash("panel-color"),
PanelStroke = const_hash("panel-stroke"),
ColorQuad = const_hash("color-quad"),
StrokePreview = const_hash("stroke-preview"),
Canvas = const_hash("canvas"),
};
class Node
{
friend class LayoutManager;
public:
Node* parent{ nullptr };
YGNodeRef y_node{ nullptr };
class LayoutManager* m_manager;
uint16_t m_nodeID;
std::string m_nodeID_s;
std::vector<std::shared_ptr<Node>> m_children;
Node* current_mouse_capture = nullptr;
Node* current_key_capture = nullptr;
bool m_mouse_captured = false;
bool m_key_captured = false;
glm::mat4 m_proj;
glm::mat4 m_mvp;
bool m_mouse_inside = false;
bool m_flood_events = false;
bool m_destroyed = false;
bool m_mouse_ignore = true;
float m_zoom = 1.f;
glm::vec2 m_scale{ 1.f };
glm::vec2 m_pos;
glm::vec2 m_size;
glm::vec4 m_clip;
glm::vec4 m_clip_uncut;
std::string m_name;
bool m_display = true;
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
Node&& operator=(Node&& o);
Node(Node&& o);
Node();
~Node();
void SetWidth(float value);
void SetWidthP(float value);
void SetHeight(float value);
void SetHeightP(float value);
void SetSize(glm::vec2 value);
void SetSize(float w, float h);
void SetPadding(float t, float r, float b, float l);
void SetPosition(float l, float t, float r, float b);
void SetPosition(float l, float t);
void SetPosition(const glm::vec2 pos);
void SetFlexGrow(float value);
void SetFlexShrink(float value);
void SetFlexDir(YGFlexDirection value);
void SetFlexWrap(YGWrap value);
void SetJustify(YGJustify value);
void SetAlign(YGAlign value);
void SetPositioning(YGPositionType value);
void SetAspectRatio(float ar);
glm::vec2 GetPosition();
float GetWidth();
float GetHeight();
glm::vec2 GetSize();
glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b);
virtual void restore_context();;
virtual void clear_context();
void update(float width, float height, float zoom);
void update();
void update_internal(const glm::vec2& origin, const glm::mat4& proj);
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr);
void load_internal(const tinyxml2::XMLElement* x_node);
virtual void draw();
Node* clone();
virtual Node* clone_instantiate() const;
virtual void clone_copy(Node* dest) const;
virtual void clone_children(Node* dest) const;
virtual void clone_finalize(Node* dest) const;;
void watch(std::function<void(Node*)> observer);
void destroy();
Node* root();
template<class T = Node> T* find(const char* ids)
{
uint16_t id = const_hash(ids);
if (id == m_nodeID)
return static_cast<T*>(this);
for (auto& c : m_children)
if (auto found = c->find(ids))
return static_cast<T*>(found);
return nullptr;
}
virtual kEventResult on_event(Event* e);
virtual kEventResult handle_event(Event* e);
virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size);;
virtual void create();
virtual void init();
virtual void loaded();
const Node* init_template(const char* id);
void add_child(Node* n);
void add_child(Node* n, int index);
void add_child(std::shared_ptr<Node> n);
void add_child(std::shared_ptr<Node> n, int index);
void remove_child(Node* n);
void remove_all_children();
void move_child(Node* n, int index);
void move_child_offset(Node* n, int offset);
int get_child_index(Node* n);
void mouse_capture();
void mouse_release();
void key_capture();
void key_release();
};

83
engine/node_border.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include "pch.h"
#include "log.h"
#include "node_border.h"
#include "shader.h"
ui::Plane NodeBorder::m_plane;
NodeBorder::NodeBorder()
{
m_mouse_ignore = false;
}
void NodeBorder::static_init()
{
m_plane.create<1>(1, 1);
}
Node* NodeBorder::clone_instantiate() const
{
return new NodeBorder();
}
void NodeBorder::clone_copy(Node* dest) const
{
Node::clone_copy(dest);
NodeBorder* n = static_cast<NodeBorder*>(dest);
n->m_color = m_color;
n->m_border_color = m_border_color;
n->m_thinkness = m_thinkness;
n->m_mouse_ignore = false;
}
void NodeBorder::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
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, pad.x, pad.x, 1);
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;
}
}
void NodeBorder::draw()
{
using namespace ui;
ui::ShaderManager::use(kShader::Color);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
if (m_color.a > 0.f)
{
m_color.a < 1.f ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
ui::ShaderManager::u_vec4(kShaderUniform::Col, m_color);
m_plane.draw_fill();
glDisable(GL_BLEND);
}
if (m_thinkness > 0 && m_border_color.a > 0.f)
{
glLineWidth(m_thinkness);
ui::ShaderManager::u_vec4(kShaderUniform::Col, m_border_color);
m_border_color.a < 1.f ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
m_plane.draw_stroke();
glDisable(GL_BLEND);
}
}

18
engine/node_border.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "node.h"
#include "shape.h"
class NodeBorder : public Node
{
public:
static ui::Plane m_plane;
glm::vec4 m_color{ 0, 0, 0, 1 };
glm::vec4 m_border_color{ 1, 1, 1, 1 };
float m_thinkness{ 0 };
NodeBorder();
static void static_init();
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
virtual void draw() override;
};

120
engine/node_button.cpp Normal file
View File

@@ -0,0 +1,120 @@
#include "pch.h"
#include "log.h"
#include "node_button.h"
Node* NodeButton::clone_instantiate() const
{
return new NodeButton();
}
void NodeButton::clone_children(Node* dest) const
{
Node::clone_children(dest);
NodeButton* n = static_cast<NodeButton*>(dest);
n->m_border = (NodeBorder*)n->m_children[0].get();
n->m_text = (NodeText*)n->m_border->m_children[0].get();
}
void NodeButton::clone_copy(Node* dest) const
{
Node::clone_copy(dest);
NodeButton* n = static_cast<NodeButton*>(dest);
//n->m_border = (NodeBorder*)m_border->clone();
//n->m_text = (NodeText*)m_text->clone();
n->color_normal = color_normal;
n->color_hover = color_hover;
n->color_down = color_down;
//n->on_click = on_click;
n->m_mouse_ignore = false;
}
void NodeButton::init()
{
m_border = new NodeBorder();
m_text = new NodeText();
add_child(m_border);
m_border->add_child(m_text);
m_border->init();
m_border->m_color = color_normal;
m_text->init();
m_text->m_font = "arial";
m_text->m_font_size = 11;
m_border->SetAlign(YGAlignCenter);
m_border->SetJustify(YGJustifyCenter);
m_border->m_mouse_ignore = false;
m_mouse_ignore = false;
}
void NodeButton::create()
{
m_border->create();
m_text->create();
m_border->m_mouse_ignore = false;
m_mouse_ignore = false;
}
void NodeButton::loaded()
{
m_border->m_thinkness = 1;
m_border->m_border_color = glm::vec4(0, 0, 0, 1);
m_border->m_color = color_normal;
m_border->m_mouse_ignore = false;
m_mouse_ignore = false;
}
void NodeButton::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
switch (ka)
{
case kAttribute::Padding:
case kAttribute::Width:
case kAttribute::Height:
case kAttribute::Color:
case kAttribute::Thickness:
case kAttribute::BorderColor:
m_border->parse_attributes(ka, attr);
break;
case kAttribute::Text:
case kAttribute::FontFace:
case kAttribute::FontSize:
m_text->parse_attributes(ka, attr);
break;
default:
Node::parse_attributes(ka, attr);
break;
}
// m_border->parse_attributes(ka, attr);
// m_text->parse_attributes(ka, attr);
}
void NodeButton::set_color(const glm::vec4& c)
{
color_normal = c;
m_border->m_color = color_normal;
}
kEventResult NodeButton::handle_event(Event* e)
{
Node::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseEnter:
m_border->m_color = color_hover;
break;
case kEventType::MouseLeave:
m_border->m_color = color_normal;
break;
case kEventType::MouseDownL:
m_border->m_color = color_down;
break;
case kEventType::MouseUpL:
m_border->m_color = color_normal;
if (m_mouse_inside && on_click != nullptr)
on_click(this);
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}

24
engine/node_button.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include "node.h"
#include "node_border.h"
#include "node_text.h"
class NodeButton : public Node
{
public:
NodeBorder* m_border;
NodeText* m_text;
glm::vec4 color_normal{ .1, .1, .1, 1 };
glm::vec4 color_hover{ .2, .2, .2, 1 };
glm::vec4 color_down{ .3, .3, .3, 1 };
std::function<void(Node* target)> on_click;
virtual Node* clone_instantiate() const override;
virtual void clone_children(Node* dest) const override;
virtual void clone_copy(Node* dest) const override;
virtual void init() override;
virtual void create() override;
virtual void loaded() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
void set_color(const glm::vec4& c);
virtual kEventResult handle_event(Event* e) override;
};

View File

@@ -0,0 +1,73 @@
#include "pch.h"
#include "log.h"
#include "node_button_custom.h"
Node* NodeButtonCustom::clone_instantiate() const
{
return new NodeButtonCustom();
}
void NodeButtonCustom::clone_copy(Node* dest) const
{
NodeBorder::clone_copy(dest);
NodeButtonCustom* n = static_cast<NodeButtonCustom*>(dest);
n->color_normal = color_normal;
n->color_hover = color_hover;
n->color_down = color_down;
n->m_mouse_ignore = false;
n->m_color = color_normal;
}
void NodeButtonCustom::loaded()
{
NodeBorder::loaded();
//m_thinkness = 1;
//m_border_color = glm::vec4(0, 0, 0, 1);
m_color = color_normal;
m_mouse_ignore = false;
}
void NodeButtonCustom::set_color(const glm::vec4& c)
{
color_normal = c;
m_color = color_normal;
}
kEventResult NodeButtonCustom::handle_event(Event* e)
{
NodeBorder::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseEnter:
m_color = color_hover;
break;
case kEventType::MouseLeave:
m_color = color_normal;
break;
case kEventType::MouseDownL:
m_color = color_down;
break;
case kEventType::MouseUpL:
m_color = m_mouse_inside ? color_hover : color_normal;
if (m_mouse_inside && on_click != nullptr)
on_click(this);
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodeButtonCustom::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
NodeBorder::parse_attributes(ka, attr);
switch (ka)
{
case kAttribute::Color:
color_normal = m_color;
break;
default:
break;
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "node_border.h"
class NodeButtonCustom : public NodeBorder
{
public:
glm::vec4 color_normal{ .2, .2, .2, 1 };
glm::vec4 color_hover{ .3, .3, .3, 1 };
glm::vec4 color_down{ .4, .4, .4, 1 };
std::function<void(Node* target)> on_click;
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void loaded() override;
void set_color(const glm::vec4& c);
virtual kEventResult handle_event(Event* e) override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
};

204
engine/node_canvas.cpp Normal file
View File

@@ -0,0 +1,204 @@
#include "pch.h"
#include "log.h"
#include "node_canvas.h"
Node* NodeCanvas::clone_instantiate() const
{
return new NodeCanvas();
}
void NodeCanvas::init()
{
m_mouse_ignore = false;
m_canvas = std::make_unique<ui::Canvas>();
m_canvas->create(1024, 1024);
m_sampler.create(GL_NEAREST);
m_face_plane.create<1>(2, 2);
m_line.create();
CanvasMode::node = this;
CanvasMode::canvas = m_canvas.get();
for (int i = 0; i < (int)ui::Canvas::kCanvasMode::COUNT; i++)
for (auto m : ui::Canvas::modes[i])
m->init();
}
void NodeCanvas::restore_context()
{
Node::restore_context();
m_canvas->create(1024, 1024);
m_sampler.create(GL_NEAREST);
m_face_plane.create<1>(2, 2);
m_canvas->snapshot_restore();
CanvasMode::node = this;
CanvasMode::canvas = m_canvas.get();
for (int i = 0; i < (int)ui::Canvas::kCanvasMode::COUNT; i++)
for (auto m : ui::Canvas::modes[i])
m->init();
}
void NodeCanvas::clear_context()
{
Node::clear_context();
m_canvas->snapshot_save(data_path);
m_canvas->clear_context();
// TODO: clear CanvasMode objects
}
void NodeCanvas::draw()
{
using namespace ui;
GLint vp[4];
GLfloat cc[4];
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
float zoom = root()->m_zoom;
auto box = m_clip * zoom;
glm::ivec4 c = (glm::ivec4)glm::vec4(box.x, (int)(vp[3] - box.y - box.w), box.z, box.w);
glViewport(c.x, c.y, c.z, c.w);
//m_canvas->m_cam_rot = m_pan * 0.003f;
glm::mat4 ortho_proj = glm::ortho(0.f, box.z, 0.f, box.w, -1000.f, 1000.f);
glm::mat4 proj = glm::perspective(glm::radians(m_canvas->m_cam_fov), box.z / box.w, 0.1f, 1000.f);
glm::mat4 camera = glm::eulerAngleXY(m_canvas->m_cam_rot.y, m_canvas->m_cam_rot.x) *
glm::translate(m_canvas->m_cam_pos);
m_canvas->m_mv = camera;
m_canvas->m_proj = proj;
m_canvas->m_box = box;
// auto plane_mvp = proj * camera * transform *
// glm::scale(glm::vec3(sz, 1));
m_sampler.bind(0);
auto blend = glIsEnabled(GL_BLEND);
glEnable(GL_BLEND);
//glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
for (int plane_index = 0; plane_index < 6; plane_index++)
{
auto plane_mvp = proj * camera * glm::scale(glm::vec3(m_canvas->m_order.size())) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1));
ui::ShaderManager::use(kShader::Checkerboard);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
m_face_plane.draw_fill();
ui::ShaderManager::use(kShader::TextureAlpha);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
for (auto layer_index : m_canvas->m_order)
{
int z = m_canvas->m_order.size() - layer_index;
auto plane_mvp_z = proj * camera * glm::scale(glm::vec3(z)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1));
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
if (!(m_canvas->m_state == ui::Canvas::kCanvasMode::Erase &&
m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index))
{
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
m_face_plane.draw_fill();
m_canvas->m_layers[layer_index].m_rtt[plane_index].unbindTexture();
}
if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
{
ui::ShaderManager::u_float(kShaderUniform::Alpha,
m_canvas->m_current_stroke->m_brush.m_tip_opacity * m_canvas->m_layers[layer_index].m_opacity);
m_canvas->m_tmp[plane_index].bindTexture();
m_face_plane.draw_fill();
m_canvas->m_tmp[plane_index].unbindTexture();
}
}
}
glDisable(GL_DEPTH_TEST);
for (auto& mode : *m_canvas->m_mode)
mode->on_Draw(ortho_proj, proj, camera);
// keep drawing the grids
if (m_canvas->m_state != ui::Canvas::kCanvasMode::Grid)
for (auto& mode : ui::Canvas::modes[(int)ui::Canvas::kCanvasMode::Grid])
mode->on_Draw(ortho_proj, proj, camera);
//ui::ShaderManager::use(kShader::Equirect);
//ui::ShaderManager::u_mat4(kShaderUniform::MVP, glm::scale(glm::vec3(.5, .5, 1)));
//ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
//glBindTexture(GL_TEXTURE_CUBE_MAP, m_canvas->cube_id);
//m_face_plane.draw_fill();
//glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
// ui::ShaderManager::use(kShader::Color);
// ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera);
// ui::ShaderManager::u_vec4(kShaderUniform::Col, { 1, 0, 0, 1 });
// static glm::vec4 AB[4]{ {-.75, 0, -1, 1},{ -.75, 0, 1, 1 } };
// m_line.update_vertices(AB);
// m_line.draw_stroke();
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
m_sampler.unbind();
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
}
void NodeCanvas::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
{
if (new_size.x > m_canvas->m_width)
{
// m_canvas->resize((int)new_size.x, (int)new_size.y);
// m_canvas->clear();
}
}
kEventResult NodeCanvas::handle_event(Event* e)
{
Node::handle_event(e);
MouseEvent* me = static_cast<MouseEvent*>(e);
KeyEvent* ke = static_cast<KeyEvent*>(e);
GestureEvent* ge = static_cast<GestureEvent*>(e);
auto loc = (me->m_pos - m_pos) * root()->m_zoom;
switch (e->m_type)
{
case kEventType::MouseDownL:
case kEventType::MouseUpL:
case kEventType::MouseDownR:
case kEventType::MouseUpR:
case kEventType::MouseMove:
case kEventType::MouseScroll:
case kEventType::MouseCancel:
for (auto& mode : *m_canvas->m_mode)
mode->on_MouseEvent(me, loc);
break;
case kEventType::KeyDown:
// if (ke->m_key == kKey::KeyE)
// m_canvas->m_state = ui::Canvas::kPenState::Erase;
// if (ke->m_key == kKey::KeySpacebar)
// m_canvas->m_alpha_lock = true;
// if (ke->m_key == kKey::AndroidVolumeUp)
// m_zoom_canvas *= 0.9f;
// if (ke->m_key == kKey::AndroidVolumeDown)
// m_zoom_canvas *= 1.1f;
if (ke->m_key == kKey::AndroidBack)
if (!ActionManager::empty())
ActionManager::undo();
break;
case kEventType::KeyUp:
// if (ke->m_key == kKey::KeyE)
// m_canvas->m_state = ui::Canvas::kPenState::Draw;
// if (ke->m_key == kKey::KeySpacebar)
// m_canvas->m_alpha_lock = false;
break;
case kEventType::GestureStart:
case kEventType::GestureMove:
for (auto& mode : *m_canvas->m_mode)
mode->on_GestureEvent(ge);
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}

21
engine/node_canvas.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include "node.h"
#include "canvas.h"
class NodeCanvas : public Node
{
public:
std::string data_path;
std::unique_ptr<ui::Canvas> m_canvas;
ui::Brush m_brush;
Sampler m_sampler;
ui::Plane m_face_plane;
ui::LineSegment m_line;
virtual Node* clone_instantiate() const override;
virtual void init() override;
virtual void restore_context() override;
virtual void clear_context() override;
virtual void draw() override;
virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override;
virtual kEventResult handle_event(Event* e) override;
};

75
engine/node_checkbox.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "pch.h"
#include "log.h"
#include "node_checkbox.h"
Node* NodeCheckBox::clone_instantiate() const
{
return new NodeCheckBox();
}
void NodeCheckBox::clone_children(Node* dest) const
{
Node::clone_children(dest);
NodeCheckBox* n = static_cast<NodeCheckBox*>(dest);
n->m_outer = (NodeBorder*)n->m_children[0].get();
n->m_inner = (NodeBorder*)n->m_outer->m_children[0].get();
n->m_mouse_ignore = false;
}
void NodeCheckBox::init()
{
m_outer = new NodeBorder();
m_inner = new NodeBorder();
add_child(m_outer);
m_outer->add_child(m_inner);
m_outer->init();
m_outer->m_color = { .3, .3, .3, 1 };
m_outer->SetAlign(YGAlignCenter);
m_outer->SetJustify(YGJustifyCenter);
m_outer->SetPadding(5, 5, 5, 5);
m_outer->SetWidthP(100);
m_outer->SetHeightP(100);
m_outer->m_mouse_ignore = false;
m_inner->init();
m_inner->SetWidthP(100);
m_inner->SetHeightP(100);
m_inner->m_border_color = glm::vec4(.8, .8, .8, 1);
m_inner->m_thinkness = 1;
m_inner->m_color = glm::vec4(.8, .8, .8, 1);
m_mouse_ignore = false;
}
void NodeCheckBox::create()
{
m_outer->create();
m_inner->create();
}
kEventResult NodeCheckBox::handle_event(Event* e)
{
Node::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseEnter:
break;
case kEventType::MouseLeave:
break;
case kEventType::MouseDownL:
break;
case kEventType::MouseUpL:
checked = !checked;
if (on_value_changed)
on_value_changed(this, checked);
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodeCheckBox::draw()
{
m_inner->m_color = checked ? glm::vec4(.4, .4, .4, 1) : glm::vec4(.8, .8, .8, 1);
Node::draw();
}

18
engine/node_checkbox.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "node.h"
#include "node_border.h"
class NodeCheckBox : public Node
{
public:
std::function<void(Node* target, bool checked)> on_value_changed;
NodeBorder* m_outer;
NodeBorder* m_inner;
bool checked = false;
virtual Node* clone_instantiate() const override;
virtual void clone_children(Node* dest) const override;
virtual void init() override;
virtual void create() override;
virtual kEventResult handle_event(Event* e) override;
virtual void draw() override;
};

View File

@@ -0,0 +1,85 @@
#include "pch.h"
#include "log.h"
#include "node_color_quad.h"
#include "shader.h"
Node* NodeColorQuad::clone_instantiate() const
{
return new NodeColorQuad();
}
void NodeColorQuad::clone_finalize(Node* dest) const
{
auto n = (NodeColorQuad*)dest;
n->m_picker = (NodeBorder*)n->m_children[0].get();
}
void NodeColorQuad::init()
{
m_picker = new NodeBorder;
m_picker->SetSize({ 20, 20 });
m_picker->SetPositioning(YGPositionTypeAbsolute);
m_picker->SetPosition(0, 0);
m_picker->m_thinkness = 1;
m_picker->m_color = glm::vec4(0);
add_child(m_picker);
}
void NodeColorQuad::set_value(float x, float y)
{
auto sz = GetSize();
auto pos = glm::clamp(glm::vec2(x, y) * sz, { 0, 0 }, sz);
m_picker->SetPosition(pos.x, pos.y);
m_value = pos / glm::max({ 1,1 }, sz); // avoid div0
if (on_value_changed)
on_value_changed(this, m_value);
}
kEventResult NodeColorQuad::handle_event(Event* e)
{
NodeBorder::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseDownL:
{
dragging = true;
mouse_capture();
auto sz = GetSize();
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) - m_picker->GetSize() * .5f;
m_picker->SetPosition(pos.x, pos.y);
m_value = pos / glm::max({ 1,1 }, sz); // avoid div0
if (on_value_changed)
on_value_changed(this, m_value);
}
break;
case kEventType::MouseUpL:
mouse_release();
dragging = false;
break;
case kEventType::MouseMove:
if (dragging)
{
auto sz = GetSize();
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) - m_picker->GetSize() * .5f;
m_picker->SetPosition(pos.x, pos.y);
m_value = pos / glm::max({ 1,1 }, sz); // avoid div0
if (on_value_changed)
on_value_changed(this, m_value);
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodeColorQuad::draw()
{
m_picker->m_border_color = m_value.y > .5f ? glm::vec4(1) : glm::vec4(0, 0, 0, 1);
using namespace ui;
ui::ShaderManager::use(kShader::ColorQuad);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
ui::ShaderManager::u_vec4(kShaderUniform::Col, m_color);
m_plane.draw_fill();
}

17
engine/node_color_quad.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include "node_border.h"
class NodeColorQuad : public NodeBorder
{
NodeBorder* m_picker;
bool dragging = false;
public:
glm::vec2 m_value;
std::function<void(Node* target, glm::vec2 value)> on_value_changed;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
void set_value(float x, float y);
virtual kEventResult handle_event(Event* e) override;
virtual void draw() override;
};

View File

@@ -0,0 +1,41 @@
#include "pch.h"
#include "log.h"
#include "node_dialog_open.h"
#include "canvas.h"
#include "node_image_texture.h"
Node* NodeDialogOpen::clone_instantiate() const
{
return new NodeDialogOpen();
}
void NodeDialogOpen::clone_finalize(Node* dest) const
{
NodeDialogOpen* n = static_cast<NodeDialogOpen*>(dest);
n->init_controls();
}
void NodeDialogOpen::init()
{
auto tpl = static_cast<const NodeBorder*>(init_template("dialog-open"));
m_color = tpl->m_color;
m_border_color = tpl->m_border_color;;
m_thinkness = tpl->m_thinkness;;
init_controls();
}
void NodeDialogOpen::init_controls()
{
btn_ok = find<NodeButton>("btn-ok");
btn_cancel = find<NodeButton>("btn-cancel");
btn_cancel->on_click = [this](Node*) {
destroy();
};
}
void NodeDialogOpen::loaded()
{
ui::Image thumb = ui::Canvas::I->thumbnail_read(data_path);
auto image_tex = find<NodeImageTexture>("thumb-tex");
image_tex->tex.create(thumb);
}

16
engine/node_dialog_open.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "node_border.h"
#include "node_button.h"
class NodeDialogOpen : public NodeBorder
{
public:
NodeButton* btn_cancel;
NodeButton* btn_ok;
std::string data_path;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
void init_controls();
virtual void loaded() override;
};

68
engine/node_icon.cpp Normal file
View File

@@ -0,0 +1,68 @@
#include "pch.h"
#include "log.h"
#include "node_icon.h"
#include "asset.h"
#include "texture.h"
std::map<std::string, glm::vec4> NodeIcon::m_icons;
void NodeIcon::static_init()
{
// spritesheet maker: https://draeton.github.io/stitches/
// icons: http://www.famfamfam.com/lab/icons/silk/
// regex css -> spritesheet.txt: \.([^{]+) {\s+width: (\d+)px;\s+height: (\d+)px;\s+.*: -(\d+)px -(\d+)px;\s+}\s+
// to: "\1",\2,\3,\4,\5\n
Asset file;
if (!(file.open("data/spritesheet.txt") && file.read_all()))
return;
char* data = (char*)file.m_data;
int size = file.m_len;
static char name[256];
int x, y, w, h;
char* s = strtok(data, "\n");
auto i = strlen(s) + 1;
while (i < size && sscanf(s, "%s %d %d %d %d", name, &w, &h, &x, &y) == 5)
{
m_icons[name] = glm::vec4(x, y, x + w, y + h);
s = strtok(nullptr, "\n");
i += strlen(s) + 1;
}
file.close();
TextureManager::load("data/spritesheet.png");
}
Node* NodeIcon::clone_instantiate() const
{
return new NodeIcon();
}
void NodeIcon::clone_copy(Node* dest) const
{
NodeImage::clone_copy(dest);
NodeIcon* n = static_cast<NodeIcon*>(dest);
n->m_icon_name = m_icon_name;
}
void NodeIcon::create()
{
m_region = m_icons[m_icon_name];
m_path = "data/spritesheet.png";
m_tex_id = const_hash(m_path.c_str());
m_use_atlas = true;
NodeImage::create();
auto tex_sz = TextureManager::get(m_tex_id).size();
YGNodeStyleSetAspectRatio(y_node, tex_sz.x / tex_sz.y);
}
void NodeIcon::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
NodeImage::parse_attributes(ka, attr);
switch (ka)
{
case kAttribute::Icon:
m_icon_name = attr->Value();
break;
default:
break;
}
}

14
engine/node_icon.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "node_image.h"
class NodeIcon : public NodeImage
{
static std::map<std::string, glm::vec4> m_icons;
std::string m_icon_name;
public:
static void static_init();
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void create() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
};

96
engine/node_image.cpp Normal file
View File

@@ -0,0 +1,96 @@
#include "pch.h"
#include "log.h"
#include "node_image.h"
#include "shader.h"
ui::Plane NodeImage::m_plane;
Sampler NodeImage::m_sampler;
void NodeImage::static_init()
{
m_plane.create<1>(1, 1);
m_sampler.create();
}
Node* NodeImage::clone_instantiate() const
{
return new NodeImage();
}
void NodeImage::clone_copy(Node* dest) const
{
Node::clone_copy(dest);
NodeImage* n = static_cast<NodeImage*>(dest);
n->m_use_atlas = m_use_atlas;
n->m_region = m_region;
n->m_off = m_off;
n->m_sz = m_sz;
n->m_path = m_path;
n->m_tex_id = m_tex_id;
}
void NodeImage::create()
{
if (!m_path.empty() && TextureManager::load(m_path.c_str()))
{
//LOG("load image node %s", m_path.c_str());
auto tex_sz = TextureManager::get(m_tex_id).size();
m_off = m_region.xy / tex_sz;
m_sz = (m_region.zw - m_region.xy) / tex_sz;
}
}
void NodeImage::restore_context()
{
Node::restore_context();
create();
}
void NodeImage::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
Node::parse_attributes(ka, attr);
switch (ka)
{
case kAttribute::Path:
m_path = attr->Value();
m_tex_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;
}
}
void NodeImage::draw()
{
using namespace ui;
TextureManager::get(m_tex_id).bind();
m_sampler.bind(0);
glEnable(GL_BLEND);
if (m_use_atlas)
{
ui::ShaderManager::use(kShader::Atlas);
ui::ShaderManager::u_vec2(kShaderUniform::Tof, m_off);
ui::ShaderManager::u_vec2(kShaderUniform::Tsz, m_sz);
}
else
{
ui::ShaderManager::use(kShader::Texture);
}
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
m_plane.draw_fill();
m_sampler.unbind();
TextureManager::get(m_tex_id).unbind();
glDisable(GL_BLEND);
}

24
engine/node_image.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include "node.h"
#include "shape.h"
#include "texture.h"
class NodeImage : public Node
{
public:
static ui::Plane m_plane;
static Sampler m_sampler;
bool m_use_atlas = false;
glm::vec4 m_region;
glm::vec2 m_off;
glm::vec2 m_sz;
std::string m_path;
uint16_t m_tex_id;
static void static_init();
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void create() override;
virtual void restore_context() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
virtual void draw() override;
};

View File

@@ -0,0 +1,32 @@
#include "pch.h"
#include "log.h"
#include "node_image_texture.h"
#include "shader.h"
#include "node_image.h"
Node* NodeImageTexture::clone_instantiate() const
{
return new NodeImageTexture();
}
void NodeImageTexture::clone_copy(Node* dest) const
{
Node::clone_copy(dest);
NodeImageTexture* n = static_cast<NodeImageTexture*>(dest);
n->tex = tex;
}
void NodeImageTexture::draw()
{
using namespace ui;
tex.bind();
NodeImage::m_sampler.bind(0);
glEnable(GL_BLEND);
ui::ShaderManager::use(kShader::Texture);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
NodeImage::m_plane.draw_fill();
NodeImage::m_sampler.unbind();
tex.unbind();
glDisable(GL_BLEND);
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "node.h"
#include "texture.h"
class NodeImageTexture : public Node
{
public:
Texture2D tex;
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
// TODO: maybe we can save the texture data and restore later
//virtual void restore_context() override
//{
// Node::restore_context();
// create();
//}
virtual void draw() override;
};

View File

@@ -0,0 +1,21 @@
#include "pch.h"
#include "log.h"
#include "node_message_box.h"
#include "layout.h"
Node* NodeMessageBox::clone_instantiate() const
{
return new NodeMessageBox();
}
void NodeMessageBox::init()
{
SetPosition(0, 0);
SetWidthP(100);
SetHeightP(100);
SetPositioning(YGPositionTypeAbsolute);
m_template = (*m_manager)[const_hash("message-box")]->m_children[0]->clone();
add_child(m_template);
btnOk = m_template->find<NodeButton>("btn-ok");
btnOk->on_click = [&](Node*) { destroy(); };
}

12
engine/node_message_box.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "node.h"
#include "node_button.h"
class NodeMessageBox : public Node
{
public:
Node* m_template;
NodeButton* btnOk;
virtual Node* clone_instantiate() const override;
virtual void init() override;
};

121
engine/node_panel_brush.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "pch.h"
#include "log.h"
#include "node_panel_brush.h"
Node* NodeButtonBrush::clone_instantiate() const
{
return new NodeButtonBrush();
}
void NodeButtonBrush::init()
{
init_template("tpl-brush-icon");
color_hover = glm::vec4(.7, .7, .7, 1);
color_normal = glm::vec4(.3, .3, .3, 1);
m_color = color_normal;
img = (NodeImage*)m_children[0].get();
}
void NodeButtonBrush::set_icon(const char* path)
{
img->m_path = path;
img->m_tex_id = const_hash(img->m_path.c_str());
img->create();
}
void NodeButtonBrush::draw()
{
m_color = m_mouse_inside ? color_hover : color_normal;
m_color = m_selected ? glm::vec4(.9, 0, 0, 1) : m_color;
NodeButtonCustom::draw();
}
Node* NodePanelBrush::clone_instantiate() const
{
return new NodePanelBrush();
}
void NodePanelBrush::init()
{
init_template("tpl-panel-brushes");
//m_layers_container = find<NodeBorder>("layers-container");
static auto icons = FindAllBrushes("data/Icons/");
if ((m_container = find<NodeBorder>("brushes")))
{
int count = 0;
for (auto& i : icons)
{
std::string path = "data/Icons/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->set_icon(path.c_str());
brush->m_brushID = count++;
m_brushes.push_back(brush);
brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
}
}
}
void NodePanelBrush::handle_click(Node* target)
{
if (target == m_current)
return;
if (m_current)
m_current->m_selected = false;
m_current = (NodeButtonBrush*)target;
m_current->m_selected = true;
if (on_brush_changed)
on_brush_changed(this, m_current->m_brushID);
}
std::vector<std::string> NodePanelBrush::FindAllBrushes(std::string folder)
{
std::vector<std::string> names;
std::string search_path = folder + "*.png";
#ifdef _WIN32
WIN32_FIND_DATAA fd;
HANDLE hFind = ::FindFirstFileA(search_path.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
// read all (real) files in current folder
// , delete '!' read other 2 default folder . and ..
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
names.push_back(fd.cFileName);
}
} while (::FindNextFileA(hFind, &fd));
::FindClose(hFind);
}
#elif __ANDROID__
//LOG("listing brushes");
AAssetDir* dir = AAssetManager_openDir(Asset::m_am, "data/Icons");
while (const char* name = AAssetDir_getNextFileName(dir))
{
//LOG("asset: %s", name);
names.push_back(name);
}
AAssetDir_close(dir);
#else
DIR *dp;
struct dirent *ep;
dp = opendir(folder.c_str());
if (dp != NULL)
{
while ((ep = readdir(dp)))
if (ep->d_type != DT_DIR)
names.push_back(ep->d_name);
closedir(dp);
}
else
LOG("Couldn't open the directory: %s", folder.c_str());
#endif
return names;
}
uint16_t NodePanelBrush::get_texture_id(int index) const
{
return m_brushes[index]->img->m_tex_id;
}

30
engine/node_panel_brush.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include "node.h"
#include "node_button_custom.h"
#include "node_image.h"
class NodeButtonBrush : public NodeButtonCustom
{
public:
int m_brushID;
bool m_selected = false;
NodeImage* img;
virtual Node* clone_instantiate() const override;
virtual void init() override;
void set_icon(const char* path);
virtual void draw() override;
};
class NodePanelBrush : public Node
{
std::vector<NodeButtonBrush*> m_brushes;
NodeButtonBrush* m_current = nullptr;
Node* m_container;
public:
std::function<void(Node* target, int id)> on_brush_changed;
virtual Node* clone_instantiate() const override;
virtual void init() override;
void handle_click(Node* target);
std::vector<std::string> FindAllBrushes(std::string folder);
uint16_t get_texture_id(int index) const;
};

View File

@@ -0,0 +1,42 @@
#include "pch.h"
#include "log.h"
#include "node_panel_color.h"
Node* NodePanelColor::clone_instantiate() const
{
return new NodePanelColor();
}
void NodePanelColor::clone_finalize(Node* dest) const
{
NodePanelColor* n = static_cast<NodePanelColor*>(dest);
n->init_controls();
}
void NodePanelColor::init()
{
init_template("tpl-panel-color");
init_controls();
}
void NodePanelColor::init_controls()
{
m_quad = find<NodeColorQuad>("quad");
m_hue = find<NodeSliderHue>("hue");
m_hue->on_hue_changed = [this](Node*, glm::vec4 hue_color) {
m_base_color = m_quad->m_color = hue_color;
auto x = glm::mix(m_base_color, glm::vec4(1, 1, 1, 1), m_cursor.x);
m_color = glm::mix(x, glm::vec4(0, 0, 0, 1), m_cursor.y);
if (on_color_changed)
on_color_changed(this, m_color);
};
m_quad->on_value_changed = [this](Node*, glm::vec2 pos)
{
auto x = glm::mix(m_base_color, glm::vec4(1, 1, 1, 1), pos.x);
m_color = glm::mix(x, glm::vec4(0, 0, 0, 1), pos.y);
m_cursor = pos;
if (on_color_changed)
on_color_changed(this, m_color);
};
m_hue->set_value(0);
}

19
engine/node_panel_color.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "node.h"
#include "node_color_quad.h"
#include "node_slider.h"
class NodePanelColor : public Node
{
public:
NodeColorQuad* m_quad;
NodeSliderHue* m_hue;
glm::vec4 m_base_color;
glm::vec4 m_color;
glm::vec2 m_cursor;
std::function<void(Node* target, glm::vec4 color)> on_color_changed;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
void init_controls();
};

221
engine/node_panel_layer.cpp Normal file
View File

@@ -0,0 +1,221 @@
#include "pch.h"
#include "log.h"
#include "node_panel_layer.h"
Node* NodeLayer::clone_instantiate() const
{
return new NodeLayer();
}
void NodeLayer::clone_children(Node* dest) const
{
NodeBorder::clone_children(dest);
NodeLayer* n = static_cast<NodeLayer*>(dest);
n->m_label = n->find<NodeText>("label");
n->m_visibility = n->find<NodeCheckBox>("cb");
}
void NodeLayer::clone_copy(Node* dest) const
{
NodeBorder::clone_copy(dest);
NodeLayer* n = (NodeLayer*)dest;
n->m_selected = m_selected;
n->m_label_text = m_label_text;
}
void NodeLayer::init()
{
const auto& m_template = (NodeBorder*)init_template("tpl-layer");
m_color = m_template->m_color;
m_border_color = m_template->m_border_color;
m_thinkness = m_template->m_thinkness;
m_label = find<NodeText>("label");
m_visibility = find<NodeCheckBox>("cb");
m_opacity = find<NodeSliderH>("sl-opacity");
}
void NodeLayer::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
NodeBorder::parse_attributes(ka, attr);
switch (ka)
{
case kAttribute::Text:
m_label_text = attr->Value();
break;
case kAttribute::Selected:
m_selected = attr->BoolValue();
default:
break;
}
}
void NodeLayer::loaded()
{
NodeBorder::loaded();
if (!m_label_text.empty())
m_label->set_text(m_label_text.c_str());
m_opacity->on_value_changed = [this](Node*, float value) {
if (on_opacity_changed)
on_opacity_changed(this, value);
};
m_visibility->on_value_changed = [this](Node*, bool checked) {
if (on_visibility_changed)
on_visibility_changed(this, checked);
};
}
kEventResult NodeLayer::handle_event(Event* e)
{
NodeBorder::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseEnter:
break;
case kEventType::MouseLeave:
break;
case kEventType::MouseDownL:
m_selected = true;
if (on_selected)
on_selected(this);
break;
case kEventType::MouseUpL:
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodeLayer::draw()
{
auto c = m_selected ? m_color_selected : m_color_normal;
m_thinkness = m_selected ? 1.f : 0.f;
m_color = m_mouse_inside ? m_color_hover : c;
NodeBorder::draw();
}
void NodeLayer::set_name(const char* s)
{
m_label_text = s;
m_label->set_text(s);
}
Node* NodePanelLayer::clone_instantiate() const
{
return new NodePanelLayer();
}
void NodePanelLayer::init()
{
LOG("NodePanelLayer::init");
init_template("tpl-panel-layers");
LOG("template initted");
m_layers_container = find<NodeBorder>("layers-container");
LOG("template container found");
// for (int i = 0; i < 1; i++)
// {
// LOG("add layer");
// add_layer();
// }
LOG("find components");
// m_current_layer = m_layers[0];
// m_layers[0]->m_selected = true;
btn_add = find<NodeButtonCustom>("btn-add");
btn_remove = find<NodeButtonCustom>("btn-remove");
btn_up = find<NodeButtonCustom>("btn-up");
btn_down = find<NodeButtonCustom>("btn-down");
LOG("attach events");
btn_add->on_click = [this](Node*) {
add_layer();
if (on_layer_add)
on_layer_add(this);
};
btn_remove->on_click = [this](Node*) {
if (m_layers.size() == 1)
return; // dont' delete the last layer
remove_layer(m_current_layer);
};
btn_up->on_click = [this](Node*) {
int old_idx = m_layers_container->get_child_index(m_current_layer);
m_layers_container->move_child_offset(m_current_layer, -1);
int new_idx = m_layers_container->get_child_index(m_current_layer);
if (on_layer_order && old_idx != new_idx)
{
on_layer_order(this, old_idx, new_idx);
}
};
btn_down->on_click = [this](Node*) {
int old_idx = m_layers_container->get_child_index(m_current_layer);
m_layers_container->move_child_offset(m_current_layer, +1);
int new_idx = m_layers_container->get_child_index(m_current_layer);
if (on_layer_order && old_idx != new_idx)
{
on_layer_order(this, old_idx, new_idx);
}
};
LOG("done init");
}
void NodePanelLayer::add_layer(const char* name)
{
NodeLayer* l = new NodeLayer;
m_layers_container->add_child(l);
l->init();
l->create();
l->loaded();
l->set_name(name);
l->on_selected = std::bind(&NodePanelLayer::handle_layer_selected, this, std::placeholders::_1);
l->on_opacity_changed = std::bind(&NodePanelLayer::handle_layer_opacity, this, std::placeholders::_1, std::placeholders::_2);
l->on_visibility_changed = std::bind(&NodePanelLayer::handle_layer_visibility, this, std::placeholders::_1, std::placeholders::_2);
m_layers.push_back(l);
}
void NodePanelLayer::add_layer()
{
static char s[64];
sprintf(s, "Layer-%d", id_counter++);
add_layer(s);
}
void NodePanelLayer::remove_layer(NodeLayer* layer)
{
auto it = std::find(m_layers.begin(), m_layers.end(), m_current_layer);
auto i = m_layers_container->get_child_index(m_current_layer);
m_layers_container->remove_child(m_current_layer);
m_layers.erase(it);
i = std::min<int>(i, (int)m_layers.size() - 1);
m_current_layer = m_layers[i];
m_current_layer->m_selected = true;
if (on_layer_delete)
on_layer_delete(this, (int)std::distance(m_layers.begin(), it));
if (on_layer_change)
on_layer_change(this, -1, i);
}
void NodePanelLayer::handle_layer_opacity(NodeLayer* target, float value)
{
if (on_layer_opacity_changed)
on_layer_opacity_changed(this, m_layers_container->get_child_index(target), value);
}
void NodePanelLayer::handle_layer_visibility(NodeLayer* target, bool visible)
{
if (on_layer_visibility_changed)
on_layer_visibility_changed(this, m_layers_container->get_child_index(target), visible);
}
void NodePanelLayer::handle_layer_selected(NodeLayer* target)
{
if (m_current_layer)
m_current_layer->m_selected = false;
m_current_layer = target;
m_current_layer->m_selected = true;
if (on_layer_change)
on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer));
}
void NodePanelLayer::clear()
{
m_layers_container->remove_all_children();
m_layers.clear();
}

59
engine/node_panel_layer.h Normal file
View File

@@ -0,0 +1,59 @@
#pragma once
#include "node_border.h"
#include "node_text.h"
#include "node_checkbox.h"
#include "node_slider.h"
#include "node_button_custom.h"
class NodeLayer : public NodeBorder
{
public:
std::function<void(NodeLayer* target)> on_selected;
std::function<void(NodeLayer* target, float opacity)> on_opacity_changed;
std::function<void(NodeLayer* target, bool visible)> on_visibility_changed;
bool m_selected = false;
glm::vec4 m_color_normal = glm::vec4(.4, .4, .4, 1);
glm::vec4 m_color_selected = glm::vec4(.3, .3, .3, 1);
glm::vec4 m_color_hover = glm::vec4(.5, .5, .5, 1);
std::string m_label_text;
NodeText* m_label;
NodeCheckBox* m_visibility;
NodeSliderH* m_opacity;
virtual Node* clone_instantiate() const override;
virtual void clone_children(Node* dest) const override;
virtual void clone_copy(Node* dest) const override;
virtual void init() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
virtual void loaded() override;
virtual kEventResult handle_event(Event* e) override;
virtual void draw() override;
void set_name(const char* s);
};
class NodePanelLayer : public Node
{
NodeButtonCustom* btn_add;
NodeButtonCustom* btn_remove;
NodeButtonCustom* btn_up;
NodeButtonCustom* btn_down;
int id_counter = 0;
public:
std::function<void(Node* target, int old_idx, int new_idx)> on_layer_change;
std::function<void(Node* target, int idx, float value)> on_layer_opacity_changed;
std::function<void(Node* target, int idx, bool visible)> on_layer_visibility_changed;
std::function<void(Node* target, int index)> on_layer_delete;
std::function<void(Node* target)> on_layer_add;
std::function<void(Node* target, int old_idx, int new_idx)> on_layer_order;
NodeLayer* m_current_layer = nullptr;
std::vector<NodeLayer*> m_layers;
NodeBorder* m_layers_container;
virtual Node* clone_instantiate() const override;
virtual void init() override;
void add_layer();
void add_layer(const char* name);
void remove_layer(NodeLayer* layer);
void handle_layer_opacity(NodeLayer* target, float value);
void handle_layer_visibility(NodeLayer* target, bool visible);
void handle_layer_selected(NodeLayer* target);
void clear();
};

View File

@@ -0,0 +1,52 @@
#include "pch.h"
#include "log.h"
#include "node_panel_stroke.h"
Node* NodePanelStroke::clone_instantiate() const
{
return new NodePanelStroke();
}
void NodePanelStroke::clone_finalize(Node* dest) const
{
NodePanelStroke* n = static_cast<NodePanelStroke*>(dest);
n->init_controls();
}
void NodePanelStroke::init()
{
init_template("tpl-panel-stroke");
init_controls();
}
void NodePanelStroke::init_controls()
{
m_canvas = find<NodeStrokePreview>("canvas");
init_slider(m_tip_size, "tip-size", &ui::Brush::m_tip_size);
init_slider(m_tip_spacing, "tip-spacing", &ui::Brush::m_tip_spacing);
init_slider(m_tip_flow, "tip-flow", &ui::Brush::m_tip_flow);
init_slider(m_tip_opacity, "tip-opacity", &ui::Brush::m_tip_opacity);
init_slider(m_tip_angle, "tip-angle", &ui::Brush::m_tip_angle);
init_slider(m_jitter_scale, "jitter-scale", &ui::Brush::m_jitter_scale);
init_slider(m_jitter_angle, "jitter-angle", &ui::Brush::m_jitter_angle);
init_slider(m_jitter_spread, "jitter-spread", &ui::Brush::m_jitter_spread);
init_slider(m_jitter_flow, "jitter-flow", &ui::Brush::m_jitter_flow);
//m_canvas->draw_stroke();
}
void NodePanelStroke::init_slider(NodeSliderH*& slider, const char* id, float ui::Brush::* prop)
{
slider = find<NodeSliderH>(id);
slider->on_value_changed = std::bind(&NodePanelStroke::handle_slide,
this, prop, std::placeholders::_1, std::placeholders::_2);
m_canvas->m_brush.*prop = slider->m_value.x;
}
void NodePanelStroke::handle_slide(float ui::Brush::* prop, Node* target, float value)
{
m_canvas->m_brush.*prop = value;
m_canvas->draw_stroke();
if (on_stroke_change)
on_stroke_change(this);
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include "node.h"
#include "node_stroke_preview.h"
#include "node_slider.h"
#include "brush.h"
class NodePanelStroke : public Node
{
public:
NodeStrokePreview* m_canvas;
NodeSliderH* m_tip_size;
NodeSliderH* m_tip_spacing;
NodeSliderH* m_tip_flow;
NodeSliderH* m_tip_opacity;
NodeSliderH* m_tip_angle;
NodeSliderH* m_jitter_scale;
NodeSliderH* m_jitter_angle;
NodeSliderH* m_jitter_spread;
NodeSliderH* m_jitter_flow;
std::function<void(Node* target)> on_stroke_change;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
void init_controls();
void init_slider(NodeSliderH*& slider, const char* id, float ui::Brush::* prop);
void handle_slide(float ui::Brush::* prop, Node* target, float value);
};

View File

@@ -0,0 +1,51 @@
#include "pch.h"
#include "log.h"
#include "node_popup_menu.h"
Node* NodePopupMenu::clone_instantiate() const
{
return new NodePopupMenu();
}
void NodePopupMenu::init()
{
m_flood_events = true;
SetPosition(0, 0);
SetWidth(100);
SetHeight(400);
SetPositioning(YGPositionTypeAbsolute);
m_mouse_ignore = false;
}
kEventResult NodePopupMenu::handle_event(Event* e)
{
switch (e->m_type)
{
case kEventType::MouseDownL:
break;
case kEventType::MouseUpL:
if (!m_mouse_inside)
{
mouse_release();
}
else
{
for (int i = 0; i < m_children.size(); i++)
{
if (m_children[i]->m_mouse_inside)
{
if (on_select)
on_select(this, i);
break;
}
}
mouse_release();
}
destroy();
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}

11
engine/node_popup_menu.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include "node.h"
class NodePopupMenu : public Node
{
public:
std::function<void(Node* target, int index)> on_select;
virtual Node* clone_instantiate() const override;
virtual void init() override;
virtual kEventResult handle_event(Event* e) override;
};

26
engine/node_settings.cpp Normal file
View File

@@ -0,0 +1,26 @@
#include "pch.h"
#include "log.h"
#include "node_settings.h"
#include "layout.h"
Node* NodeSettings::clone_instantiate() const
{
return new NodeSettings();
}
void NodeSettings::init()
{
SetPosition(0, 0);
SetWidthP(100);
SetHeightP(100);
SetPositioning(YGPositionTypeAbsolute);
m_template = (*m_manager)[const_hash("settings")]->m_children[0]->clone();
add_child(m_template);
btnOk = m_template->find<NodeButton>("btn-ok");
btnOk->on_click = [&](Node*) { destroy(); };
}
kEventResult NodeSettings::handle_event(Event* e)
{
return kEventResult::Consumed;
}

13
engine/node_settings.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include "node.h"
#include "node_button.h"
class NodeSettings : public Node
{
Node* m_template;
NodeButton* btnOk;
public:
virtual Node* clone_instantiate() const override;
virtual void init() override;
virtual kEventResult handle_event(Event* e) override;
};

146
engine/node_slider.cpp Normal file
View File

@@ -0,0 +1,146 @@
#include "pch.h"
#include "log.h"
#include "node_slider.h"
#include "shader.h"
Node* NodeSliderH::clone_instantiate() const
{
return new NodeSliderH();
}
void NodeSliderH::clone_copy(Node* dest) const
{
NodeBorder::clone_copy(dest);
NodeSliderH* n = static_cast<NodeSliderH*>(dest);
n->m_value = m_value;
}
void NodeSliderH::init()
{
SetPadding(1, 1, 1, 1);
SetWidthP(100);
SetHeightP(100);
m_color = glm::vec4(1);
}
void NodeSliderH::draw()
{
NodeBorder::draw();
using namespace ui;
auto sz = GetSize();
glm::vec2 cur_size = sz * (1.f - m_mask) + m_mask * glm::vec2(10);
glm::mat4 scale = glm::scale(glm::vec3(cur_size, 1.f));
glm::mat4 pos = glm::translate(glm::vec3(m_value * m_mask * sz + m_pos + sz * .5f * (1.f - m_mask), 0));
auto mvp = m_proj * pos * scale;
ui::ShaderManager::use(kShader::Color);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
ui::ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
m_plane.draw_fill();
}
void NodeSliderH::set_value(float value)
{
m_value = glm::vec2(value) * m_mask;
if (on_value_changed)
on_value_changed(this, glm::length(m_value));
}
float NodeSliderH::get_value()
{
return glm::length(m_value);
}
void NodeSliderH::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
NodeBorder::parse_attributes(ka, attr);
switch (ka)
{
case kAttribute::Value:
m_value = glm::vec2(attr->FloatValue());
break;
default:
break;
}
}
kEventResult NodeSliderH::handle_event(Event* e)
{
NodeBorder::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseDownL:
dragging = true;
mouse_capture();
{
auto sz = GetSize();
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) * m_mask;
m_value = pos / glm::max({ 1, 1 }, sz);
if (on_value_changed)
on_value_changed(this, glm::length(m_value));
}
break;
case kEventType::MouseUpL:
mouse_release();
dragging = false;
break;
case kEventType::MouseMove:
if (dragging)
{
auto sz = GetSize();
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz) * m_mask;
m_value = pos / glm::max({ 1, 1 }, sz);
if (on_value_changed)
on_value_changed(this, glm::length(m_value));
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
Node* NodeSliderHue::clone_instantiate() const
{
return new NodeSliderHue();
}
void NodeSliderHue::clone_finalize(Node* dest) const
{
NodeSliderV::clone_finalize(dest);
NodeSliderHue* n = static_cast<NodeSliderHue*>(dest);
n->init_controls();
}
void NodeSliderHue::init()
{
NodeSliderV::init();
init_controls();
}
void NodeSliderHue::init_controls()
{
on_value_changed = [this](Node*, float value) {
m_color = glm::vec4(convert_hsv2rgb({ value, 1, 1 }), 1);
if (on_hue_changed)
on_hue_changed(this, m_color);
};
}
glm::vec4 NodeSliderHue::get_hue()
{
return m_color;
}
void NodeSliderHue::draw()
{
using namespace ui;
ui::ShaderManager::use(kShader::ColorHue);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
//ui::ShaderManager::u_vec4(kShaderUniform::Col, m_color);
m_plane.draw_fill();
NodeBorder::m_color = glm::vec4(0);
NodeSliderH::draw();
}

39
engine/node_slider.h Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include "node_border.h"
class NodeSliderH : public NodeBorder
{
bool dragging = false;
public:
glm::vec2 m_mask{ 1, 0 };
glm::vec2 m_value;
std::function<void(Node* target, float value)> on_value_changed;
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void init() override;
virtual void draw() override;
void set_value(float value);
float get_value();
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
virtual kEventResult handle_event(Event* e) override;
};
class NodeSliderV : public NodeSliderH
{
public:
virtual Node* clone_instantiate() const override { return new NodeSliderV(); }
NodeSliderV() { m_mask = { 0, 1 }; }
};
class NodeSliderHue : public NodeSliderV
{
public:
glm::vec4 m_color;
std::function<void(Node* target, glm::vec4 color)> on_hue_changed;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
void init_controls();
glm::vec4 get_hue();
virtual void draw() override;
};

View File

@@ -0,0 +1,135 @@
#include "pch.h"
#include "log.h"
#include "node_stroke_preview.h"
#include "texture.h"
#include "shader.h"
#include "bezier.h"
Node* NodeStrokePreview::clone_instantiate() const
{
return new NodeStrokePreview();
}
void NodeStrokePreview::clone_copy(Node* dest) const
{
NodeBorder::clone_copy(dest);
}
void NodeStrokePreview::clone_children(Node* dest) const
{
// stop children cloning
}
void NodeStrokePreview::clone_finalize(Node* dest) const
{
NodeStrokePreview* n = (NodeStrokePreview*)dest;
n->init_controls();
}
void NodeStrokePreview::init_controls()
{
m_mesh.create();
m_sampler.create();
TextureManager::load("data/Icons/Round-Hard.png");
m_brush.m_tex_id = const_hash("data/Icons/Round-Hard.png");
}
void NodeStrokePreview::restore_context()
{
NodeBorder::restore_context();
init_controls();
if (m_size.x > 0 && m_size.y > 0)
m_rtt.create(m_size.x, m_size.y);
draw_stroke();
}
void NodeStrokePreview::clear_context()
{
NodeBorder::clear_context();
m_rtt.destroy();
}
void NodeStrokePreview::draw_stroke()
{
m_rtt.bindFramebuffer();
{
using namespace ui;
GLint vp[4];
GLfloat cc[4];
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight());
glEnable(GL_BLEND);
glm::mat4 proj = glm::ortho<float>(0, (float)m_rtt.getWidth(), 0, (float)m_rtt.getHeight(), -1, 1);
m_stroke.reset();
m_stroke.start(m_brush);
auto samples = m_stroke.compute_samples();
auto& tex = TextureManager::get(m_brush.m_tex_id);
tex.bind();
m_sampler.bind(0);
if (true)
{
m_mesh.shader.use();
m_mesh.shader.u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
m_mesh.shader.u_int(kShaderUniform::Tex, 0);
m_mesh.draw(samples, proj);
}
//else
//{
// ShaderManager::use("stroke");
// ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
// ShaderManager::u_int(kShaderUniform::Tex, 0);
// for (const auto& s : samples)
// {
// auto mvp = proj *
// glm::translate(glm::vec3(s.pos, 0)) *
// glm::scale(glm::vec3(s.size, s.size, 1)) *
// glm::eulerAngleZ(s.angle);
// ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
// ShaderManager::u_float(kShaderUniform::Alpha, s.flow);
// m_plane.draw_fill();
// }
//}
m_sampler.unbind();
tex.unbind();
glDisable(GL_BLEND);
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
}
m_rtt.unbindFramebuffer();
}
void NodeStrokePreview::draw()
{
using namespace ui;
ui::ShaderManager::use(kShader::Texture);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
m_rtt.bindTexture();
m_sampler.bind(0);
m_plane.draw_fill();
m_sampler.unbind();
m_rtt.unbindTexture();
}
void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
{
float pad = 30.f;
float w = new_size.x;
float h = new_size.y;
std::vector<glm::vec2> kp = { { pad, pad },{ pad, h - pad },{ w - pad, pad },{ w - pad, h - pad } };
m_stroke.start(m_brush);
for (int i = 0; i < 20; i++)
m_stroke.add_point(BezierCurve::Bezier2D(kp, i / 20.f), 1.f);
m_rtt.destroy();
m_rtt.create((int)new_size.x, (int)new_size.y);
draw_stroke();
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include "node_border.h"
#include "rtt.h"
#include "brush.h"
#include "texture.h"
class NodeStrokePreview : public NodeBorder
{
RTT m_rtt;
Sampler m_sampler;
ui::BrushMesh m_mesh;
public:
ui::Brush m_brush;
ui::Stroke m_stroke;
std::vector<glm::vec2> m_bez_points;
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void clone_children(Node* dest) const override;
virtual void clone_finalize(Node* dest) const override;
void init_controls();
virtual void restore_context() override;
virtual void clear_context() override;
void draw_stroke();
virtual void draw() override;
virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override;
};

88
engine/node_text.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "pch.h"
#include "log.h"
#include "node_text.h"
#include "shader.h"
Node* NodeText::clone_instantiate() const
{
return new NodeText();
}
void NodeText::clone_copy(Node* dest) const
{
Node::clone_copy(dest);
NodeText* n = static_cast<NodeText*>(dest);
n->m_text_mesh.create();
n->m_text_mesh.update(font_id, m_text.c_str());
n->m_text = m_text;
n->m_font = m_font;
n->m_color = m_color;
n->m_font_size = m_font_size;
n->font_id = font_id;
}
void NodeText::create()
{
char font[64];
sprintf(font, "%s-%d", m_font.c_str(), m_font_size);
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);
}
void NodeText::restore_context()
{
Node::restore_context();
create();
}
void NodeText::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
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_font_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;
}
}
void NodeText::set_text(const char* s)
{
m_text = s;
m_text_mesh.update(font_id, s);
SetSize(m_text_mesh.bb);
}
void NodeText::draw()
{
using namespace ui;
glm::mat4 pos = glm::translate(glm::vec3(glm::floor(m_pos), 0));
m_mvp = m_proj * pos;
ui::ShaderManager::use(kShader::Font);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
ui::ShaderManager::u_vec4(kShaderUniform::Col, m_color);
glEnable(GL_BLEND);
m_text_mesh.draw();
glDisable(GL_BLEND);
}

21
engine/node_text.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include "node.h"
#include "font.h"
class NodeText : public Node
{
public:
TextMesh m_text_mesh;
std::string m_text;
std::string m_font;
glm::vec4 m_color{ 1, 1, 1, 1 };
int m_font_size;
kFont font_id;
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void create() override;
virtual void restore_context() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
void set_text(const char* s);
virtual void draw() override;
};

View File

@@ -0,0 +1,58 @@
#include "pch.h"
#include "log.h"
#include "node_text_input.h"
Node* NodeTextInput::clone_instantiate() const
{
return new NodeTextInput();
}
void NodeTextInput::init()
{
init_controls();
}
void NodeTextInput::init_controls()
{
m_text = new NodeText;
add_child(m_text);
m_text->m_font = "arial";
m_text->m_font_size = 11;
m_text->m_text = "TextInput";
m_text->create();
}
kEventResult NodeTextInput::handle_event(Event* e)
{
KeyEvent* ke = (KeyEvent*)e;
switch (e->m_type)
{
case kEventType::MouseDownL:
break;
case kEventType::MouseUpL:
key_capture();
break;
case kEventType::KeyDown:
//switch (ke->m_key)
//{
//case VK_BACK:
// m_string.erase(m_string.end() - 1);
// m_text->set_text(m_string.c_str());
// break;
//default:
// break;
//}
break;
case kEventType::KeyChar:
if (ke->m_char >= 32 && ke->m_char < (32 + 96))
{
m_string += (char)ke->m_key;
m_text->set_text(m_string.c_str());
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}

14
engine/node_text_input.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "node_border.h"
#include "node_text.h"
class NodeTextInput : public NodeBorder
{
public:
NodeText* m_text;
std::string m_string;
virtual Node* clone_instantiate() const override;
virtual void init() override;
void init_controls();
virtual kEventResult handle_event(Event* e) override;
};

73
engine/node_viewport.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include "pch.h"
#include "log.h"
#include "node_viewport.h"
#include "shader.h"
void NodeViewport::draw()
{
using namespace ui;
glm::mat4 cam = glm::lookAt(glm::vec3(sinf(angle) * 10, 0, -10), glm::vec3(0, 0, 0), glm::vec3(0, -1, 0));
glm::mat4 proj = glm::perspective<float>(glm::radians(45.f), m_clip.z / m_clip.w, .1f, 100);
GLint vp[4];
GLfloat cc[4];
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
auto box = m_clip * root()->m_zoom;
glm::ivec4 c = (glm::ivec4)glm::vec4(box.x, (int)(vp[3] - box.y - box.w), box.z, box.w);
glViewport(c.x, c.y, c.z, c.w);
TextureManager::get(m_tex_id).bind();
m_sampler->bind(0);
glEnable(GL_BLEND);
ui::ShaderManager::use(kShader::Texture);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * cam);
m_faces->draw_fill();
m_sampler->unbind();
TextureManager::get(m_tex_id).unbind();
glDisable(GL_BLEND);
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
}
Node* NodeViewport::clone_instantiate() const
{
return new NodeViewport;
}
void NodeViewport::create()
{
m_faces = std::make_unique<ui::Plane>();
m_faces->create<1>(10, 10);
m_sampler = std::make_unique<Sampler>();
m_sampler->create();
TextureManager::load("data/uvs.jpg");
m_tex_id = const_hash("data/uvs.jpg");
}
kEventResult NodeViewport::handle_event(Event* e)
{
Node::handle_event(e);
switch (e->m_type)
{
case kEventType::MouseDownL:
dragging = true;
drag_end = drag_start = ((MouseEvent*)e)->m_pos;
angle_old = angle;
break;
case kEventType::MouseUpL:
dragging = false;
break;
case kEventType::MouseMove:
if (dragging)
{
drag_end = ((MouseEvent*)e)->m_pos;
angle = angle_old + (drag_end - drag_start).x * .01f;
}
break;
default:
break;
}
return kEventResult::Consumed;
}

23
engine/node_viewport.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
#include "node.h"
#include "shape.h"
#include "texture.h"
#include "event.h"
class NodeViewport : public Node
{
public:
std::unique_ptr<ui::Plane> m_faces;
std::unique_ptr<Sampler> m_sampler;
uint16_t m_tex_id;
glm::vec2 drag_start;
glm::vec2 drag_end;
bool dragging = false;
float angle = 0.0f;
float angle_old;
virtual void draw() override;
virtual Node* clone_instantiate() const override;
virtual void create() override;
virtual kEventResult handle_event(Event* e) override;
};

View File

@@ -1,5 +1,13 @@
#pragma once
enum class kShapeType : uint16_t
{
Quad = const_hash("rect"),
Poly = const_hash("poly"),
RoundRect = const_hash("round-rect"),
Slice9 = const_hash("slice9"),
};
namespace ui {
class Shape