refactor layout.h into single file per Node* classes
This commit is contained in:
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "layout.h"
|
||||
#include "canvas.h"
|
||||
#include "shader.h"
|
||||
#include "node_canvas.h"
|
||||
|
||||
NodeCanvas* CanvasMode::node;
|
||||
ui::Canvas* CanvasMode::canvas;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
2136
engine/layout.h
2136
engine/layout.h
File diff suppressed because it is too large
Load Diff
804
engine/node.cpp
Normal file
804
engine/node.cpp
Normal 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
185
engine/node.h
Normal 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
83
engine/node_border.cpp
Normal 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
18
engine/node_border.h
Normal 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
120
engine/node_button.cpp
Normal 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
24
engine/node_button.h
Normal 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;
|
||||
};
|
||||
73
engine/node_button_custom.cpp
Normal file
73
engine/node_button_custom.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
17
engine/node_button_custom.h
Normal file
17
engine/node_button_custom.h
Normal 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
204
engine/node_canvas.cpp
Normal 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
21
engine/node_canvas.h
Normal 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
75
engine/node_checkbox.cpp
Normal 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
18
engine/node_checkbox.h
Normal 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;
|
||||
};
|
||||
85
engine/node_color_quad.cpp
Normal file
85
engine/node_color_quad.cpp
Normal 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
17
engine/node_color_quad.h
Normal 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;
|
||||
};
|
||||
41
engine/node_dialog_open.cpp
Normal file
41
engine/node_dialog_open.cpp
Normal 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
16
engine/node_dialog_open.h
Normal 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
68
engine/node_icon.cpp
Normal 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
14
engine/node_icon.h
Normal 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
96
engine/node_image.cpp
Normal 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
24
engine/node_image.h
Normal 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;
|
||||
};
|
||||
32
engine/node_image_texture.cpp
Normal file
32
engine/node_image_texture.cpp
Normal 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);
|
||||
}
|
||||
18
engine/node_image_texture.h
Normal file
18
engine/node_image_texture.h
Normal 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;
|
||||
};
|
||||
21
engine/node_message_box.cpp
Normal file
21
engine/node_message_box.cpp
Normal 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
12
engine/node_message_box.h
Normal 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
121
engine/node_panel_brush.cpp
Normal 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
30
engine/node_panel_brush.h
Normal 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;
|
||||
};
|
||||
42
engine/node_panel_color.cpp
Normal file
42
engine/node_panel_color.cpp
Normal 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
19
engine/node_panel_color.h
Normal 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
221
engine/node_panel_layer.cpp
Normal 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
59
engine/node_panel_layer.h
Normal 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();
|
||||
};
|
||||
52
engine/node_panel_stroke.cpp
Normal file
52
engine/node_panel_stroke.cpp
Normal 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);
|
||||
}
|
||||
27
engine/node_panel_stroke.h
Normal file
27
engine/node_panel_stroke.h
Normal 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);
|
||||
};
|
||||
51
engine/node_popup_menu.cpp
Normal file
51
engine/node_popup_menu.cpp
Normal 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
11
engine/node_popup_menu.h
Normal 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
26
engine/node_settings.cpp
Normal 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
13
engine/node_settings.h
Normal 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
146
engine/node_slider.cpp
Normal 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
39
engine/node_slider.h
Normal 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;
|
||||
};
|
||||
135
engine/node_stroke_preview.cpp
Normal file
135
engine/node_stroke_preview.cpp
Normal 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();
|
||||
}
|
||||
26
engine/node_stroke_preview.h
Normal file
26
engine/node_stroke_preview.h
Normal 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
88
engine/node_text.cpp
Normal 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
21
engine/node_text.h
Normal 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;
|
||||
};
|
||||
58
engine/node_text_input.cpp
Normal file
58
engine/node_text_input.cpp
Normal 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
14
engine/node_text_input.h
Normal 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
73
engine/node_viewport.cpp
Normal 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
23
engine/node_viewport.h
Normal 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;
|
||||
};
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user