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

This commit is contained in:
2017-11-12 03:02:40 +00:00
parent fa4e67617b
commit daaa7f9d48
16 changed files with 154 additions and 54 deletions

View File

@@ -146,6 +146,7 @@
<border color=".2" height="20" justify="center" align="center"><text text="Tip Settings" font-face="arial" font-size="11"/></border>
<node dir="row">
<node width="30%" dir="col">
<node height="30" justify="center"><text text="Blend" font-face="arial" font-size="11"/></node>
<node height="20" justify="center"><text text="Size" font-face="arial" font-size="11"/></node>
<node height="20" justify="center"><text text="Flow" font-face="arial" font-size="11"/></node>
<node height="20" justify="center"><text text="Opacity" font-face="arial" font-size="11"/></node>
@@ -155,7 +156,10 @@
<node height="20" justify="center"><text text="Stencil" font-face="arial" font-size="11"/></node>
<node height="20" justify="center"><text text="Wet" font-face="arial" font-size="11"/></node>
</node>
<border dir="col" align="center" grow="1" width="1">
<border dir="col" align="center" grow="1" width="1" flood-events="1">
<node height="30" pad="1" width="100%" dir="row">
<combobox id="btn-ok" text="Normal" width="100%" height="30"/>
</node>
<node height="20" pad="1" width="100%" dir="row">
<slider-h id="tip-size" width="1" grow="1" value=".25"/>
<node width="20" pad="0" margin="0 0 0 2">
@@ -293,6 +297,7 @@
<text id="title" text="File Name" margin="5 0 0 0" font-face="arial" font-size="11"/>
</border>
</layout>
<layout id="dialog-cloud">
<border id="background" positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center">
<border id="form" thickness="1" border-color=".2" pad="3" width="90%" height="90%" dir="col">

View File

@@ -194,6 +194,7 @@
<ClCompile Include="engine\node_canvas.cpp" />
<ClCompile Include="engine\node_checkbox.cpp" />
<ClCompile Include="engine\node_color_quad.cpp" />
<ClCompile Include="engine\node_combobox.cpp" />
<ClCompile Include="engine\node_dialog_browse.cpp" />
<ClCompile Include="engine\node_dialog_cloud.cpp" />
<ClCompile Include="engine\node_dialog_layer_rename.cpp" />
@@ -305,6 +306,7 @@
<ClInclude Include="engine\node_canvas.h" />
<ClInclude Include="engine\node_checkbox.h" />
<ClInclude Include="engine\node_color_quad.h" />
<ClInclude Include="engine\node_combobox.h" />
<ClInclude Include="engine\node_dialog_browse.h" />
<ClInclude Include="engine\node_dialog_cloud.h" />
<ClInclude Include="engine\node_dialog_layer_rename.h" />

View File

@@ -234,6 +234,9 @@
<ClCompile Include="engine\app_cloud.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="engine\node_combobox.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="engine\app.h">
@@ -413,6 +416,9 @@
<ClInclude Include="engine\node_dialog_cloud.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
<ClInclude Include="engine\node_combobox.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PanoPainter.rc">

View File

@@ -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");
}

View File

@@ -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);

View File

@@ -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; };

View File

@@ -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

View File

@@ -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)]; }

View File

@@ -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<void(Node*)> 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));
}
}

View File

@@ -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"),

56
engine/node_combobox.cpp Normal file
View File

@@ -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<NodeComboBox*>(dest);
}

12
engine/node_combobox.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "node_button.h"
class NodeComboBox : public NodeButton
{
public:
std::array<std::string, 4> 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;
};

View File

@@ -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

View File

@@ -75,6 +75,7 @@
#ifdef __cplusplus
#include <map>
#include <array>
#include <cmath>
#include <stack>
#include <regex>

View File

@@ -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);

View File

@@ -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);