From daaa7f9d4899302e80f058b12e759ce238b888d6 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 12 Nov 2017 03:02:40 +0000 Subject: [PATCH] add ComboBox node, add blend modes button in stroke panel, move brush shader code to ShaderManager and avoid the same shader being recompiled many times --- data/layout.xml | 7 ++++- engine.vcxproj | 2 ++ engine.vcxproj.filters | 6 ++++ engine/app_shaders.cpp | 43 +++++++++++++++++++++++--- engine/brush.cpp | 40 ++---------------------- engine/brush.h | 1 - engine/canvas.cpp | 6 ++-- engine/layout.h | 5 +++ engine/node.cpp | 5 ++- engine/node.h | 1 + engine/node_combobox.cpp | 56 ++++++++++++++++++++++++++++++++++ engine/node_combobox.h | 12 ++++++++ engine/node_stroke_preview.cpp | 14 ++++----- engine/pch.h | 1 + engine/shader.cpp | 7 +++++ engine/shader.h | 2 ++ 16 files changed, 154 insertions(+), 54 deletions(-) create mode 100644 engine/node_combobox.cpp create mode 100644 engine/node_combobox.h 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 +#include #include #include #include diff --git a/engine/shader.cpp b/engine/shader.cpp index e6073e1..4f33879 100644 --- a/engine/shader.cpp +++ b/engine/shader.cpp @@ -171,6 +171,13 @@ void ShaderManager::u_int(kShaderUniform id, int i) { m_current->u_int(id, i); } + +Shader* ui::ShaderManager::get(kShader id) +{ + auto it = m_shaders.find(id); + return (it == m_shaders.end()) ? nullptr : &it->second; +} + void ui::ShaderManager::u_float(kShaderUniform id, float f) { m_current->u_float(id, f); diff --git a/engine/shader.h b/engine/shader.h index 54288b3..7d849fd 100644 --- a/engine/shader.h +++ b/engine/shader.h @@ -41,6 +41,7 @@ enum class kShader : uint16_t StrokePreview = const_hash("stroke-preview"), Checkerboard= const_hash("checkerboard"), Equirect = const_hash("equirect"), + BrushStroke = const_hash("brush-stroke"), }; class Shader @@ -67,6 +68,7 @@ public: static bool create(kShader id, const char* vertex, const char* fragment); static void use(kShader id); static void use(const char* name); + static Shader* get(kShader id); static void u_vec4(kShaderUniform id, const glm::vec4& v); static void u_vec2(kShaderUniform id, const glm::vec2& v); static void u_mat4(kShaderUniform id, const glm::mat4& m);