diff --git a/data/layout.xml b/data/layout.xml
index 702e841..7836204 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -146,6 +146,7 @@
+
@@ -155,7 +156,10 @@
-
+
+
+
+
@@ -293,6 +297,7 @@
+
diff --git a/engine.vcxproj b/engine.vcxproj
index e8f836f..fef1142 100644
--- a/engine.vcxproj
+++ b/engine.vcxproj
@@ -194,6 +194,7 @@
+
@@ -305,6 +306,7 @@
+
diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters
index accbd16..1c82067 100644
--- a/engine.vcxproj.filters
+++ b/engine.vcxproj.filters
@@ -234,6 +234,9 @@
Source Files
+
+ Source Files
+
@@ -413,6 +416,9 @@
Header Files\ui
+
+ Header Files\ui
+
diff --git a/engine/app_shaders.cpp b/engine/app_shaders.cpp
index 0c24424..92bd65c 100644
--- a/engine/app_shaders.cpp
+++ b/engine/app_shaders.cpp
@@ -100,9 +100,10 @@ void App::initShaders()
" sum += textureOffset(t, uv, ivec2( 1, 1));\n"
" return sum / vec4(9.0);\n"
"}\n"
- "vec3 blend_colorDodge(vec4 base, vec4 stroke, float alpha_tot) { return mix(stroke.rgb, mix(base.rgb, base.rgb / (1.0 - stroke.rgb), stroke.a / alpha_tot), base.a / alpha_tot); }\n"
- "vec3 blend_multiply(vec4 base, vec4 stroke, float alpha_tot) { return mix(stroke.rgb, mix(base.rgb, base.rgb * stroke.rgb, stroke.a / alpha_tot), base.a / alpha_tot); }\n"
- "vec3 blend_normal(vec4 base, vec4 stroke, float alpha_tot) { return mix(base.rgb, stroke.rgb, stroke.a / alpha_tot); }\n"
+ "vec3 blend_colorDodge(vec4 base, vec4 stroke, float alpha_tot) { return mix(stroke.rgb, mix(base.rgb, base.rgb/(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }\n"
+ "vec3 blend_multiply(vec4 base, vec4 stroke, float alpha_tot) { return mix(stroke.rgb, mix(base.rgb, base.rgb*stroke.rgb, stroke.a/alpha_tot), base.a/alpha_tot); }\n"
+ "vec3 blend_screen(vec4 base, vec4 stroke, float alpha_tot) { return mix(stroke.rgb, mix(base.rgb, 1.0-(1.0-base.rgb)*(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }\n"
+ "vec3 blend_normal(vec4 base, vec4 stroke, float alpha_tot) { return mix(base.rgb, stroke.rgb, stroke.a/alpha_tot); }\n"
"void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / vec2(2048) * 20.0;\n"
" mediump vec4 base = texture(tex, uv.xy);\n"
@@ -113,7 +114,7 @@ void App::initShaders()
" if (base.a == 0.0) { frag = stroke; return; }\n"
" mediump float contribution = (1.0 - base.a) * stroke.a;\n"
" mediump float alpha_tot = base.a + contribution;"
- " mediump vec3 rgb = blend_multiply(base, stroke, alpha_tot);\n"
+ " mediump vec3 rgb = blend_screen(base, stroke, alpha_tot);\n"
" frag = vec4(rgb, (lock ? base.a : alpha_tot));\n"
"}\n";
@@ -330,6 +331,38 @@ void App::initShaders()
" frag = texture(tex, dir);\n"
"}";
+ // STROKE - INSTANCED
+ static const char* shader_stroke_inst_v =
+ SHADER_VERSION
+ "in vec4 pos;"
+ "in vec2 uvs;"
+ "in mat4 a_mvp;"
+ "in float a_flow;"
+ "out vec3 uv;"
+ "out float alpha;"
+ "void main(){"
+ " uv = vec3(uvs, pos.w);"
+ " alpha = a_flow;"
+ " gl_Position = a_mvp * vec4(pos.xyz, 1.0);"
+ "}";
+ static const char* shader_stroke_inst_f =
+ SHADER_VERSION
+ "uniform mediump sampler2D tex;"
+ "uniform mediump sampler2D tex_stencil;\n"
+ "uniform mediump vec4 col;"
+ "uniform mediump vec2 resolution;\n"
+ "uniform mediump vec2 stencil_offset;\n"
+ "uniform mediump float stencil_alpha;\n"
+ "in mediump float alpha;"
+ "in mediump vec3 uv;"
+ "out mediump vec4 frag;"
+ "void main(){"
+ " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
+ " mediump float stencil = 1.0 - (texture(tex_stencil, (uv2+stencil_offset)).r * 0.9) * stencil_alpha;\n"
+ " mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha * stencil;"
+ " frag = vec4(col.rgb, a);"
+ "}";
+
LOG("initializing shaders");
if (!ShaderManager::create(kShader::Texture, shader_v, shader_f))
LOG("Failed to create shader Texture");
@@ -359,6 +392,8 @@ void App::initShaders()
LOG("Failed to create shader Checkerboard");
if (!ShaderManager::create(kShader::Equirect, shader_equirect_v, shader_equirect_f))
LOG("Failed to create shader Equirect");
+ if (!ShaderManager::create(kShader::BrushStroke, shader_stroke_inst_v, shader_stroke_inst_f))
+ LOG("Failed to create shader BrushStroke");
LOG("shaders initialized");
}
diff --git a/engine/brush.cpp b/engine/brush.cpp
index 3e83695..82f3005 100644
--- a/engine/brush.cpp
+++ b/engine/brush.cpp
@@ -90,44 +90,10 @@ bool ui::BrushMesh::create()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
- // STROKE - INSTANCED
- static const char* shader_stroke_inst_v =
- SHADER_VERSION
- "in vec4 pos;"
- "in vec2 uvs;"
- "in mat4 a_mvp;"
- "in float a_flow;"
- "out vec3 uv;"
- "out float alpha;"
- "void main(){"
- " uv = vec3(uvs, pos.w);"
- " alpha = a_flow;"
- " gl_Position = a_mvp * vec4(pos.xyz, 1.0);"
- "}";
- static const char* shader_stroke_inst_f =
- SHADER_VERSION
- "uniform mediump sampler2D tex;"
- "uniform mediump sampler2D tex_stencil;\n"
- "uniform mediump vec4 col;"
- "uniform mediump vec2 resolution;\n"
- "uniform mediump vec2 stencil_offset;\n"
- "uniform mediump float stencil_alpha;\n"
- "in mediump float alpha;"
- "in mediump vec3 uv;"
- "out mediump vec4 frag;"
- "void main(){"
- " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
- " mediump float stencil = 1.0 - (texture(tex_stencil, (uv2+stencil_offset)).r * 0.9) * stencil_alpha;\n"
- " mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha * stencil;"
- " frag = vec4(col.rgb, a);"
- "}";
+ auto shader = ShaderManager::get(kShader::BrushStroke);
-
- if (!shader.create(shader_stroke_inst_v, shader_stroke_inst_f))
- LOG("Failed to create shader BrushMesh Stroke");
-
- loc_flow = shader.GetAttribLocation("a_flow");
- loc_mvp = shader.GetAttribLocation("a_mvp");
+ loc_flow = shader->GetAttribLocation("a_flow");
+ loc_mvp = shader->GetAttribLocation("a_mvp");
#if USE_VBO
glGenVertexArrays(1, &vao);
diff --git a/engine/brush.h b/engine/brush.h
index d430329..4e391f2 100644
--- a/engine/brush.h
+++ b/engine/brush.h
@@ -39,7 +39,6 @@ struct StrokeSample
class BrushMesh
{
public:
- ui::Shader shader;
GLuint buffers[3]{ 0 };
GLuint vao{ 0 };
struct vertex_t { glm::vec4 pos; glm::vec2 uvs; };
diff --git a/engine/canvas.cpp b/engine/canvas.cpp
index 1b338c9..20e693a 100644
--- a/engine/canvas.cpp
+++ b/engine/canvas.cpp
@@ -230,9 +230,9 @@ void ui::Canvas::stroke_draw()
if (m_use_instanced)
{
glEnable(GL_BLEND);
- m_mesh.shader.use();
- m_mesh.shader.u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
- m_mesh.shader.u_int(kShaderUniform::Tex, 0);
+ ShaderManager::use(kShader::BrushStroke);
+ ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
+ ShaderManager::u_int(kShaderUniform::Tex, 0);
m_mesh.draw(samples, ortho_proj);
}
else
diff --git a/engine/layout.h b/engine/layout.h
index 04e9c1f..411180a 100644
--- a/engine/layout.h
+++ b/engine/layout.h
@@ -26,6 +26,11 @@ public:
auto i = m_layouts.find(id);
return i == m_layouts.end() ? nullptr : i->second.get();
}
+ class Node* get(uint16_t id)
+ {
+ auto i = m_layouts.find(id);
+ return i == m_layouts.end() ? nullptr : i->second.get();
+ }
void restore_context();
void clear_context();
//Node& operator[](const char* ids) { return m_layouts[const_hash(ids)]; }
diff --git a/engine/node.cpp b/engine/node.cpp
index d92d45b..efc1132 100644
--- a/engine/node.cpp
+++ b/engine/node.cpp
@@ -26,6 +26,7 @@
#include "node_scroll.h"
#include "node_dialog_browse.h"
#include "node_dialog_cloud.h"
+#include "node_combobox.h"
void Node::watch(std::function observer)
{
@@ -57,7 +58,7 @@ kEventResult Node::on_event(Event* e)
bool skip_children = false;
skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) &&
- (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children;
+ (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children; // <-- THIS IS WRONG "!m_capture_children" is correct, but it breaks everything if changed
if (!skip_children)
{
@@ -781,6 +782,7 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
CASE(kWidget::TextInput, NodeTextInput);
CASE(kWidget::Button, NodeButton);
CASE(kWidget::ButtonCustom, NodeButtonCustom);
+ CASE(kWidget::ComboBox, NodeComboBox);
CASE(kWidget::SliderH, NodeSliderH);
CASE(kWidget::SliderV, NodeSliderV);
CASE(kWidget::SliderHue, NodeSliderHue);
@@ -868,6 +870,7 @@ void Node::clone_children(Node* dest) const
dest->m_children.emplace_back(cn);
cn->parent = dest;
cn->m_manager = dest->m_manager;
+ cn->loaded();
YGNodeInsertChild(dest->y_node, cn->y_node, YGNodeGetChildCount(dest->y_node));
}
}
diff --git a/engine/node.h b/engine/node.h
index 93f271d..4270240 100644
--- a/engine/node.h
+++ b/engine/node.h
@@ -53,6 +53,7 @@ enum class kWidget : uint16_t
Icon = const_hash("icon"),
Button = const_hash("button"),
ButtonCustom = const_hash("button-custom"),
+ ComboBox = const_hash("combobox"),
SliderH = const_hash("slider-h"),
SliderV = const_hash("slider-v"),
SliderHue = const_hash("slider-hue"),
diff --git a/engine/node_combobox.cpp b/engine/node_combobox.cpp
new file mode 100644
index 0000000..ab0010c
--- /dev/null
+++ b/engine/node_combobox.cpp
@@ -0,0 +1,56 @@
+#include "pch.h"
+#include "log.h"
+#include "node_combobox.h"
+#include "node_popup_menu.h"
+
+Node* NodeComboBox::clone_instantiate() const
+{
+ return new NodeComboBox;
+}
+
+void NodeComboBox::loaded()
+{
+ NodeButton::loaded();
+ on_click = [this](Node* target) {
+ LOG("ComboBox");
+ NodePopupMenu* popup = new NodePopupMenu;
+ popup->init();
+ popup->create();
+ popup->loaded();
+ root()->add_child(popup);
+ for (int i = 0; i < labels.size(); i++)
+ {
+ NodeButton* btn = new NodeButton;
+ btn->init();
+ btn->create();
+ btn->loaded();
+ popup->add_child(btn);
+ btn->m_text->set_text(labels[i].c_str());
+ btn->m_border->SetWidthP(100.f);
+ btn->m_border->SetHeight(30.f);
+ btn->on_click = [this,popup](Node* target) {
+ int index = popup->get_child_index(target);
+ m_current_index = index;
+ m_text->set_text(labels[index].c_str());
+ popup->mouse_release();
+ popup->destroy();
+ };
+ }
+ glm::vec2 pos = m_pos + glm::vec2(0, m_size.y - (m_current_index+1) * 30.f);
+ popup->SetPositioning(YGPositionTypeAbsolute);
+ popup->SetPosition(pos.x, pos.y);
+ popup->SetSize(m_size.x, YGUndefined);
+ popup->SetFlexGrow(1.f);
+ popup->update();
+ root()->update();
+ popup->mouse_capture();
+ popup->m_mouse_ignore = false;
+ popup->m_flood_events = true;
+ popup->m_capture_children = false;
+ };
+}
+void NodeComboBox::clone_copy(Node* dest) const
+{
+ NodeButton::clone_copy(dest);
+ NodeComboBox* n = static_cast(dest);
+}
\ No newline at end of file
diff --git a/engine/node_combobox.h b/engine/node_combobox.h
new file mode 100644
index 0000000..c699e07
--- /dev/null
+++ b/engine/node_combobox.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "node_button.h"
+
+class NodeComboBox : public NodeButton
+{
+public:
+ std::array labels{ "Normal", "Multiply", "Screen", "Color Dodge" };
+ int m_current_index = 0;
+ virtual Node* clone_instantiate() const override;
+ virtual void clone_copy(Node* dest) const override;
+ virtual void loaded() override;
+};
diff --git a/engine/node_stroke_preview.cpp b/engine/node_stroke_preview.cpp
index 345e51f..bd08103 100644
--- a/engine/node_stroke_preview.cpp
+++ b/engine/node_stroke_preview.cpp
@@ -86,13 +86,13 @@ void NodeStrokePreview::draw_stroke()
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.shader.u_int(kShaderUniform::TexStencil, 1); // stencil
- m_mesh.shader.u_vec2(kShaderUniform::Resolution, { m_rtt.getWidth(), m_rtt.getHeight() });
- m_mesh.shader.u_vec2(kShaderUniform::StencilOffset, glm::vec2(0));
- m_mesh.shader.u_float(kShaderUniform::StencilAlpha, b.m_tip_stencil);
+ ShaderManager::use(kShader::BrushStroke);
+ ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
+ ShaderManager::u_int(kShaderUniform::Tex, 0);
+ ShaderManager::u_int(kShaderUniform::TexStencil, 1); // stencil
+ ShaderManager::u_vec2(kShaderUniform::Resolution, { m_rtt.getWidth(), m_rtt.getHeight() });
+ ShaderManager::u_vec2(kShaderUniform::StencilOffset, glm::vec2(0));
+ ShaderManager::u_float(kShaderUniform::StencilAlpha, b.m_tip_stencil);
m_mesh.draw(samples, proj);
}
//else
diff --git a/engine/pch.h b/engine/pch.h
index 0a61143..a780448 100644
--- a/engine/pch.h
+++ b/engine/pch.h
@@ -75,6 +75,7 @@
#ifdef __cplusplus
#include