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:
@@ -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">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]; }
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
56
engine/node_combobox.cpp
Normal 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
12
engine/node_combobox.h
Normal 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;
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <stack>
|
||||
#include <regex>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user