Improved mask also work on erase. Improved shaders for layer opacity, now when drawing doesn't change opacity. Improved layers panel layout to be similar to PS. Added layer blending option and visibility. Added custom icons to checkboxes and fixed the combobox items.
This commit is contained in:
@@ -35,15 +35,14 @@
|
||||
|
||||
<!--layer template-->
|
||||
<layout id="tpl-layer">
|
||||
<border height="30" border-color="1" thickness="1" color=".4" dir="row" margin="1 0 1 0">
|
||||
<node width="30" pad="1">
|
||||
<checkbox id="cb"></checkbox>
|
||||
</node>
|
||||
<node width="1" grow="1" justify="center" pad="5">
|
||||
<text id="label" text="Layer0" font-face="arial" font-size="11"/>
|
||||
</node>
|
||||
<node color=".4" width="100" pad="5">
|
||||
<slider-h id="sl-opacity" value="1"/>
|
||||
<border height="30" border-color="1" thickness="1" color=".4" dir="col" margin="1 0 1 0">
|
||||
<node dir="row" height="30">
|
||||
<node width="30" pad="1">
|
||||
<checkbox id="cb" icon="data/ui/check-layer-visibility.png"></checkbox>
|
||||
</node>
|
||||
<node width="1" grow="1" justify="center" pad="5">
|
||||
<text id="label" font-face="arial" font-size="11"/>
|
||||
</node>
|
||||
</node>
|
||||
</border>
|
||||
</layout>
|
||||
@@ -54,6 +53,17 @@
|
||||
<border height="30" color=".5" align="center" justify="center" margin="0 0 0 0">
|
||||
<text text="Layers" font-face="arial" font-size="11" color="1 1 1 1"/>
|
||||
</border>
|
||||
|
||||
<border height="35" color=".5" dir="row" align="center" flood-events="1" pad="0 0 5 0">
|
||||
<checkbox id="alpha-lock" icon="data/ui/check-lock-transparency.png" width="30" margin="0 5 0 5"></checkbox>
|
||||
<combobox id="blend-mode" width="100" height="30" margin="0 5 0 0" combo-list="Normal,-,Multiply,Screen,-,Color Dodge,Overlay" default="0"/>
|
||||
<slider-h id="opacity" value="1" grow="1" width="1" margin="0 5 0 0"/>
|
||||
</border>
|
||||
|
||||
<border id="layers-container" pad="5" color=".4" dir="col" flood-events="1">
|
||||
<!--layers list-->
|
||||
</border>
|
||||
|
||||
<border height="40" color=".5" dir="row" align="center" flood-events="1">
|
||||
<button-custom id="btn-add" thickness="1" color="0 0" border-color=".0" shrink="1" margin="0 2 0 5">
|
||||
<icon width="30" icon="add"/>
|
||||
@@ -69,9 +79,6 @@
|
||||
<icon width="30" icon="bin_closed"/>
|
||||
</button-custom>
|
||||
</border>
|
||||
<border id="layers-container" pad="5" color=".4" dir="col" flood-events="1">
|
||||
<!--layers list-->
|
||||
</border>
|
||||
</node>
|
||||
</layout>
|
||||
|
||||
@@ -1116,7 +1123,7 @@ Here's a list of what's available in this release.
|
||||
<!--Brushes-->
|
||||
<!--<panel-brush id="panel-brush"/>-->
|
||||
<!--Layers-->
|
||||
<!--<panel-layer id="panel-layer"/>-->
|
||||
<panel-layer id="panel-layer"/>
|
||||
<!--Colors-->
|
||||
<!--<panel-color id="panel-color"/>-->
|
||||
<!--Grids-->
|
||||
|
||||
BIN
data/ui/check-layer-visibility.png
Normal file
BIN
data/ui/check-layer-visibility.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
BIN
data/ui/check-lock-transparency.png
Normal file
BIN
data/ui/check-lock-transparency.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 892 B |
BIN
data/ui/check-test.png
Normal file
BIN
data/ui/check-test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
extra/ui/checkbox-icons.psd
Normal file
BIN
extra/ui/checkbox-icons.psd
Normal file
Binary file not shown.
@@ -44,10 +44,7 @@ void App::open_document(std::string path)
|
||||
async_start();
|
||||
title_update();
|
||||
for (auto& i : canvas->m_canvas->m_order)
|
||||
{
|
||||
auto* l = layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
|
||||
l->m_opacity->m_value.x = canvas->m_canvas->m_layers[i].m_opacity;
|
||||
}
|
||||
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
|
||||
async_end();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -88,6 +88,26 @@ void App::init_toolbar_main()
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> std::shared_ptr<T> find_or_create_panel(NodeScroll* panels)
|
||||
{
|
||||
std::shared_ptr<T> ret;
|
||||
auto node_find = std::find_if(panels->m_children.begin(), panels->m_children.end(),
|
||||
[](const std::shared_ptr<Node>&p) { return (bool)std::dynamic_pointer_cast<T>(p); });
|
||||
if (node_find != panels->m_children.end())
|
||||
{
|
||||
ret = std::static_pointer_cast<T>(*node_find);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = std::make_shared<T>();
|
||||
ret->m_manager = panels->m_manager;
|
||||
ret->init();
|
||||
ret->create();
|
||||
ret->loaded();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void App::init_sidebar()
|
||||
{
|
||||
sidebar = layout[main_id]->find<NodeBorder>("sidebar");
|
||||
@@ -99,50 +119,12 @@ void App::init_sidebar()
|
||||
//color = layout[main_id]->find<NodePanelColor>("panel-color");
|
||||
//stroke = layout[main_id]->find<NodePanelStroke>("panel-stroke");
|
||||
|
||||
brushes = std::make_shared<NodePanelBrush>();
|
||||
brushes->m_manager = &layout;
|
||||
brushes->init();
|
||||
brushes->create();
|
||||
brushes->loaded();
|
||||
|
||||
layers = std::make_shared<NodePanelLayer>();
|
||||
layers->m_manager = &layout;
|
||||
layers->init();
|
||||
layers->create();
|
||||
layers->loaded();
|
||||
|
||||
color = std::make_shared<NodePanelColor>();
|
||||
color->m_manager = &layout;
|
||||
color->init();
|
||||
color->create();
|
||||
color->loaded();
|
||||
|
||||
stroke = std::make_shared<NodePanelStroke>();
|
||||
stroke->m_manager = &layout;
|
||||
stroke->init();
|
||||
stroke->create();
|
||||
stroke->loaded();
|
||||
|
||||
auto grid_find = std::find_if(panels->m_children.begin(), panels->m_children.end(),
|
||||
[](const std::shared_ptr<Node>&p) { return (bool)std::dynamic_pointer_cast<NodePanelGrid>(p); });
|
||||
if (grid_find != panels->m_children.end())
|
||||
{
|
||||
grid = std::static_pointer_cast<NodePanelGrid>(*grid_find);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid = std::make_shared<NodePanelGrid>();
|
||||
grid->m_manager = &layout;
|
||||
grid->init();
|
||||
grid->create();
|
||||
grid->loaded();
|
||||
}
|
||||
|
||||
presets = std::make_shared<NodePanelBrushPreset>();
|
||||
presets->m_manager = &layout;
|
||||
presets->init();
|
||||
presets->create();
|
||||
presets->loaded();
|
||||
brushes = find_or_create_panel<NodePanelBrush>(panels);
|
||||
layers = find_or_create_panel<NodePanelLayer>(panels);
|
||||
color = find_or_create_panel<NodePanelColor>(panels);
|
||||
stroke = find_or_create_panel<NodePanelStroke>(panels);
|
||||
grid = find_or_create_panel<NodePanelGrid>(panels);
|
||||
presets = find_or_create_panel<NodePanelBrushPreset>(panels);
|
||||
|
||||
// if (canvas)
|
||||
// {
|
||||
@@ -175,6 +157,8 @@ void App::init_sidebar()
|
||||
|
||||
layers->on_layer_add = [this](Node*) {
|
||||
canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str());
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_change = [this](Node*, int old_idx, int new_idx) {
|
||||
@@ -183,18 +167,38 @@ void App::init_sidebar()
|
||||
|
||||
layers->on_layer_order = [this](Node*, int old_idx, int new_idx) {
|
||||
canvas->m_canvas->layer_order(old_idx, new_idx);
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_delete = [this](Node*, int idx) {
|
||||
canvas->m_canvas->layer_remove(idx);
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_opacity_changed = [this](Node*, int idx, float value) {
|
||||
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_opacity = value;
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) {
|
||||
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_alpha_locked = visible;
|
||||
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_visible = visible;
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) {
|
||||
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_alpha_locked = locked;
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) {
|
||||
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_blend_mode = mode;
|
||||
canvas->m_canvas->m_unsaved = true;
|
||||
title_update();
|
||||
};
|
||||
|
||||
layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) {
|
||||
|
||||
@@ -77,17 +77,32 @@ void App::initShaders()
|
||||
SHADER_VERSION
|
||||
"uniform sampler2D tex;\n"
|
||||
"uniform sampler2D tex_stroke;\n"
|
||||
"uniform sampler2D tex_mask;\n"
|
||||
"uniform mediump float alpha;\n"
|
||||
"uniform mediump float stroke_alpha;\n"
|
||||
"uniform mediump vec2 resolution;\n"
|
||||
"uniform bool fragUV2;\n"
|
||||
"uniform bool mask;\n"
|
||||
"in mediump vec2 uv;\n"
|
||||
"out mediump vec4 frag;\n"
|
||||
"mediump vec4 blur(sampler2D t, mediump vec2 uv){\n"
|
||||
" mediump vec4 sum = texture(t, uv);\n"
|
||||
" sum += textureOffset(t, uv, ivec2(-1, -1));\n"
|
||||
" sum += textureOffset(t, uv, ivec2(-1, 0));\n"
|
||||
" sum += textureOffset(t, uv, ivec2(-1, 1));\n"
|
||||
" sum += textureOffset(t, uv, ivec2( 0, -1));\n"
|
||||
" sum += textureOffset(t, uv, ivec2( 0, 1));\n"
|
||||
" sum += textureOffset(t, uv, ivec2( 1, -1));\n"
|
||||
" sum += textureOffset(t, uv, ivec2( 1, 0));\n"
|
||||
" sum += textureOffset(t, uv, ivec2( 1, 1));\n"
|
||||
" return sum / vec4(9.0);\n"
|
||||
"}\n"
|
||||
"void main(){\n"
|
||||
" mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n"
|
||||
" mediump vec4 base = texture(tex, uv2);\n"
|
||||
" mediump vec4 stroke = texture(tex_stroke, uv);\n"
|
||||
" mediump float a = base.a - (stroke.a * alpha);\n"
|
||||
" frag = vec4(base.rgb, clamp(a, 0.0, 1.0));\n"
|
||||
" stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n"
|
||||
" frag = vec4(base.rgb, clamp((base.a - stroke.a) * alpha, 0.0, 1.0));\n"
|
||||
"}\n";
|
||||
// TEXTURE COMP DRAW
|
||||
static const char* shader_comp_draw_f =
|
||||
@@ -97,6 +112,7 @@ void App::initShaders()
|
||||
"uniform sampler2D tex_mask;\n"
|
||||
"uniform sampler2D tex_stencil;\n"
|
||||
"uniform mediump float alpha;\n"
|
||||
"uniform mediump float stroke_alpha;\n"
|
||||
"uniform mediump int blend_mode;\n"
|
||||
"uniform mediump vec2 resolution;\n"
|
||||
"uniform bool lock;\n"
|
||||
@@ -141,13 +157,12 @@ void App::initShaders()
|
||||
" mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n"
|
||||
" mediump vec4 base = texture(tex, uv2);\n"
|
||||
" mediump vec4 stroke = texture(tex_stroke, uv);\n"
|
||||
" stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv2).r : stroke.a * alpha;\n"
|
||||
|
||||
" if (!lock && base.a == 0.0) { frag = stroke; return; }\n"
|
||||
" stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n"
|
||||
" if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n"
|
||||
" mediump float contribution = (1.0 - base.a) * stroke.a;\n"
|
||||
" mediump float alpha_tot = base.a + contribution;"
|
||||
" mediump vec3 rgb = blend(base, stroke, alpha_tot, blend_mode);\n"
|
||||
" frag = vec4(rgb, (lock ? base.a : alpha_tot));\n"
|
||||
" frag = vec4(rgb, (lock ? base.a : alpha_tot) * alpha);\n"
|
||||
"}\n";
|
||||
|
||||
// TEXTURE ATLAS
|
||||
|
||||
@@ -46,7 +46,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
|
||||
auto layer_index = canvas->m_canvas->m_order[i];
|
||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||
{
|
||||
if (canvas->m_canvas->m_layers[layer_index].m_opacity == .0f)
|
||||
if (!canvas->m_canvas->m_layers[layer_index].m_visible || canvas->m_canvas->m_layers[layer_index].m_opacity == .0f)
|
||||
continue;
|
||||
|
||||
int z = (int)(canvas->m_canvas->m_order.size() - i);
|
||||
@@ -62,10 +62,11 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
|
||||
ShaderManager::use(kShader::CompErase);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
||||
//ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity);
|
||||
//ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
|
||||
//ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
canvas->m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
|
||||
@@ -90,7 +91,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_vec2(kShaderUniform::Resolution, canvas->m_canvas->m_size);
|
||||
//ShaderManager::u_int(kShaderUniform::TexStencil, 3);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity);
|
||||
ShaderManager::u_int(kShaderUniform::Lock, canvas->m_canvas->m_layers[layer_index].m_alpha_locked);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, canvas->m_canvas->m_current_stroke->m_brush.m_blend_mode);
|
||||
|
||||
@@ -91,6 +91,8 @@ void Canvas::pick_update(int plane)
|
||||
m_sampler.bind(0);
|
||||
for (auto layer_index : m_order)
|
||||
{
|
||||
if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f)
|
||||
continue;
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity);
|
||||
m_layers[layer_index].m_rtt[i].bindTexture();
|
||||
m_plane.draw_fill();
|
||||
@@ -242,7 +244,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
||||
auto layer_index = m_current_layer_idx;
|
||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||
{
|
||||
if (m_layers[layer_index].m_opacity == .0f)
|
||||
if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == .0f)
|
||||
continue;
|
||||
|
||||
glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)m_mixer.getWidth() / m_mixer.getHeight(), 0.1f, 1000.f);
|
||||
@@ -293,7 +295,8 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
//ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
|
||||
//ShaderManager::u_int(kShaderUniform::TexStencil, 3);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, 1);
|
||||
ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index].m_alpha_locked);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
@@ -804,9 +807,11 @@ void Canvas::stroke_commit()
|
||||
ShaderManager::use(kShader::CompErase);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
||||
//ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, 1);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
@@ -831,7 +836,8 @@ void Canvas::stroke_commit()
|
||||
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
//ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, 1);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush.m_blend_mode);
|
||||
@@ -1009,6 +1015,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index
|
||||
ShaderManager::u_int(kShaderUniform::TexStroke, 1); // source
|
||||
//ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[source_idx].m_opacity);
|
||||
ShaderManager::u_int(kShaderUniform::Lock, false);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, 0); // TODO: defaulted to normal, change to layer blend mode when implemented
|
||||
@@ -1284,6 +1291,8 @@ void Canvas::export_equirectangular_thread(std::string file_path)
|
||||
m_sampler_mask.bind(0);
|
||||
for (auto layer_index : m_order)
|
||||
{
|
||||
if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f)
|
||||
continue;
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity);
|
||||
m_layers[layer_index].m_rtt[i].bindTexture();
|
||||
m_plane.draw_fill();
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
bool m_alpha_locked = false;
|
||||
float m_opacity = 1.f;
|
||||
bool m_hightlight = false;
|
||||
bool m_blend_mode = 0;
|
||||
std::string m_name;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
|
||||
@@ -1112,6 +1112,7 @@ void CanvasModeTransform::leave()
|
||||
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, 1);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1);
|
||||
ShaderManager::u_int(kShaderUniform::Lock, false);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, false);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, true);
|
||||
|
||||
@@ -137,7 +137,7 @@ void NodeCanvas::draw()
|
||||
auto layer_index = m_canvas->m_order[i];
|
||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||
{
|
||||
if (m_canvas->m_layers[layer_index].m_opacity == .0f)
|
||||
if (!m_canvas->m_layers[layer_index].m_visible || m_canvas->m_layers[layer_index].m_opacity == .0f)
|
||||
continue;
|
||||
|
||||
int z = (int)(m_canvas->m_order.size() - i);
|
||||
@@ -153,11 +153,12 @@ void NodeCanvas::draw()
|
||||
ShaderManager::use(kShader::CompErase);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
|
||||
//ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
//ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
|
||||
//ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
|
||||
@@ -182,7 +183,8 @@ void NodeCanvas::draw()
|
||||
ShaderManager::u_int(kShaderUniform::TexMask, 2);
|
||||
//ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_canvas->m_box) / zoom);
|
||||
//ShaderManager::u_int(kShaderUniform::TexStencil, 3);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
|
||||
ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
#include "node_checkbox.h"
|
||||
#include "texture.h"
|
||||
|
||||
Node* NodeCheckBox::clone_instantiate() const
|
||||
{
|
||||
@@ -13,7 +14,9 @@ void NodeCheckBox::clone_children(Node* dest) const
|
||||
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_icon = n->m_inner->m_children.empty() ? nullptr : (NodeImage*)n->m_inner->m_children[0].get();
|
||||
n->m_mouse_ignore = false;
|
||||
n->m_icon_path = m_icon_path;
|
||||
}
|
||||
|
||||
void NodeCheckBox::init()
|
||||
@@ -43,6 +46,8 @@ void NodeCheckBox::create()
|
||||
{
|
||||
m_outer->create();
|
||||
m_inner->create();
|
||||
if (!m_icon_path.empty())
|
||||
set_icon(m_icon_path);
|
||||
}
|
||||
|
||||
kEventResult NodeCheckBox::handle_event(Event* e)
|
||||
@@ -58,6 +63,7 @@ kEventResult NodeCheckBox::handle_event(Event* e)
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
checked = !checked;
|
||||
update_icon();
|
||||
if (on_value_changed)
|
||||
on_value_changed(this, checked);
|
||||
break;
|
||||
@@ -73,3 +79,42 @@ void NodeCheckBox::draw()
|
||||
m_inner->m_color = checked ? glm::vec4(.4, .4, .4, 1) : glm::vec4(.8, .8, .8, 1);
|
||||
Node::draw();
|
||||
}
|
||||
|
||||
void NodeCheckBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
|
||||
{
|
||||
switch (ka)
|
||||
{
|
||||
case kAttribute::Icon:
|
||||
m_icon_path = attr->Value();
|
||||
break;
|
||||
default:
|
||||
Node::parse_attributes(ka, attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeCheckBox::set_icon(const std::string& icon_path)
|
||||
{
|
||||
if (icon_path.empty() || !TextureManager::load(icon_path.c_str()))
|
||||
{
|
||||
if (m_icon)
|
||||
m_icon->destroy();
|
||||
m_icon = nullptr;
|
||||
return;
|
||||
}
|
||||
m_icon_path = icon_path;
|
||||
update_icon();
|
||||
}
|
||||
|
||||
void NodeCheckBox::update_icon()
|
||||
{
|
||||
auto& t = TextureManager::get(const_hash(m_icon_path.c_str()));
|
||||
if (!m_icon)
|
||||
m_icon = m_inner->add_child<NodeImage>();
|
||||
auto region = checked ? glm::vec4(.5f, 0, 1, 1) : glm::vec4(0, 0, .5f, 1);
|
||||
m_icon->m_region = region * glm::vec4(t.size(), t.size());
|
||||
m_icon->m_use_atlas = true;
|
||||
m_icon->set_image(m_icon_path);
|
||||
m_icon->SetWidthP(100);
|
||||
m_icon->SetHeightP(100);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "node.h"
|
||||
#include "node_border.h"
|
||||
#include "node_image.h"
|
||||
|
||||
class NodeCheckBox : public Node
|
||||
{
|
||||
@@ -8,6 +9,8 @@ public:
|
||||
std::function<void(Node* target, bool checked)> on_value_changed;
|
||||
NodeBorder* m_outer;
|
||||
NodeBorder* m_inner;
|
||||
NodeImage* m_icon;
|
||||
std::string m_icon_path;
|
||||
bool checked = false;
|
||||
virtual Node* clone_instantiate() const override;
|
||||
virtual void clone_children(Node* dest) const override;
|
||||
@@ -15,4 +18,8 @@ public:
|
||||
virtual void create() override;
|
||||
virtual kEventResult handle_event(Event* e) override;
|
||||
virtual void draw() override;
|
||||
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
|
||||
void set_icon(const std::string& icon_path);
|
||||
void set_value(bool checked) { this->checked = checked; update_icon(); }
|
||||
void update_icon();
|
||||
};
|
||||
|
||||
@@ -13,7 +13,9 @@ void NodeComboBox::clone_copy(Node* dest) const
|
||||
NodeButton::clone_copy(dest);
|
||||
NodeComboBox* n = static_cast<NodeComboBox*>(dest);
|
||||
n->m_data = m_data;
|
||||
n->m_items = m_items;
|
||||
n->m_current_index = m_current_index;
|
||||
n->m_selected_child_index = m_selected_child_index;
|
||||
}
|
||||
|
||||
void NodeComboBox::loaded()
|
||||
@@ -85,6 +87,9 @@ void NodeComboBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute*
|
||||
case kAttribute::ComboList:
|
||||
{
|
||||
m_data = split(attr->Value(), ',');
|
||||
m_items.clear();
|
||||
for (auto& i : m_data)
|
||||
if (i != "-") m_items.push_back(i);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Default:
|
||||
@@ -94,3 +99,12 @@ void NodeComboBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute*
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeComboBox::set_index(int index)
|
||||
{
|
||||
m_current_index = index;
|
||||
m_selected_child_index = index;
|
||||
m_text->set_text(m_items[index].c_str());
|
||||
//if (on_select)
|
||||
// on_select(this, index);
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ public:
|
||||
virtual void clone_copy(Node* dest) const override;
|
||||
virtual void loaded() override;
|
||||
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
|
||||
void set_index(int index);
|
||||
};
|
||||
|
||||
@@ -105,3 +105,19 @@ void NodeImage::draw()
|
||||
TextureManager::get(m_tex_id).unbind();
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
bool NodeImage::set_image(const std::string& path)
|
||||
{
|
||||
m_path = path;
|
||||
m_tex_id = const_hash(path.c_str());
|
||||
if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps))
|
||||
{
|
||||
auto tex_sz = TextureManager::get(m_tex_id).size();
|
||||
m_off = xy(m_region) / tex_sz;
|
||||
m_sz = (zw(m_region) - xy(m_region)) / tex_sz;
|
||||
if (m_autosize)
|
||||
SetAspectRatio(tex_sz.x / tex_sz.y);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -24,4 +24,5 @@ public:
|
||||
virtual void restore_context() override;
|
||||
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
|
||||
virtual void draw() override;
|
||||
bool set_image(const std::string& path);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
#include "node_panel_layer.h"
|
||||
#include "canvas.h"
|
||||
#include "node_combobox.h"
|
||||
|
||||
Node* NodeLayer::clone_instantiate() const
|
||||
{
|
||||
@@ -31,7 +33,6 @@ void NodeLayer::init()
|
||||
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)
|
||||
@@ -54,10 +55,6 @@ 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);
|
||||
@@ -159,6 +156,18 @@ void NodePanelLayer::init()
|
||||
on_layer_order(this, old_idx, new_idx);
|
||||
}
|
||||
};
|
||||
m_opacity = find<NodeSliderH>("opacity");
|
||||
m_opacity->on_value_changed = [this](Node*, float value) {
|
||||
handle_layer_opacity(m_current_layer, value);
|
||||
};
|
||||
m_alpha_lock = find<NodeCheckBox>("alpha-lock");
|
||||
m_alpha_lock->on_value_changed = [this](Node*, bool locked) {
|
||||
handle_layer_alpha_lock(m_current_layer, locked);
|
||||
};
|
||||
m_blend_mode = find<NodeComboBox>("blend-mode");
|
||||
m_blend_mode->on_select = [this](Node*, int index) {
|
||||
handle_layer_blend_mode(m_current_layer, index);
|
||||
};
|
||||
LOG("done init");
|
||||
}
|
||||
|
||||
@@ -170,8 +179,8 @@ NodeLayer* NodePanelLayer::add_layer(const char* name)
|
||||
l->create();
|
||||
l->loaded();
|
||||
l->set_name(name);
|
||||
l->m_visibility->set_value(true);
|
||||
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);
|
||||
l->on_highlight = std::bind(&NodePanelLayer::handle_layer_highlight, this, std::placeholders::_1, std::placeholders::_2);
|
||||
if (m_current_layer)
|
||||
@@ -179,6 +188,7 @@ NodeLayer* NodePanelLayer::add_layer(const char* name)
|
||||
m_current_layer = l;
|
||||
m_current_layer->m_selected = true;
|
||||
m_layers.push_back(l);
|
||||
update_attributes();
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -208,6 +218,7 @@ void NodePanelLayer::remove_layer(NodeLayer* layer)
|
||||
on_layer_delete(this, old_idx);
|
||||
if (on_layer_change)
|
||||
on_layer_change(this, -1, i);
|
||||
update_attributes();
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_opacity(NodeLayer* target, float value)
|
||||
@@ -228,6 +239,18 @@ void NodePanelLayer::handle_layer_visibility(NodeLayer* target, bool visible)
|
||||
on_layer_visibility_changed(this, m_layers_container->get_child_index(target), visible);
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_alpha_lock(NodeLayer* target, bool locked)
|
||||
{
|
||||
if (on_layer_alpha_lock_changed)
|
||||
on_layer_alpha_lock_changed(this, m_layers_container->get_child_index(target), locked);
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_blend_mode(NodeLayer* target, int mode)
|
||||
{
|
||||
if (on_layer_blend_mode_changed)
|
||||
on_layer_blend_mode_changed(this, m_layers_container->get_child_index(target), mode);
|
||||
}
|
||||
|
||||
void NodePanelLayer::handle_layer_selected(NodeLayer* target)
|
||||
{
|
||||
if (m_current_layer)
|
||||
@@ -236,6 +259,7 @@ void NodePanelLayer::handle_layer_selected(NodeLayer* 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));
|
||||
update_attributes();
|
||||
}
|
||||
|
||||
void NodePanelLayer::clear()
|
||||
@@ -244,3 +268,11 @@ void NodePanelLayer::clear()
|
||||
m_layers.clear();
|
||||
m_current_layer = nullptr;
|
||||
}
|
||||
|
||||
void NodePanelLayer::update_attributes()
|
||||
{
|
||||
auto& l = Canvas::I->m_layers[Canvas::I->m_current_layer_idx];
|
||||
m_opacity->set_value(l.m_opacity);
|
||||
m_alpha_lock->set_value(l.m_alpha_locked);
|
||||
m_blend_mode->set_index(l.m_blend_mode);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
#include "node_checkbox.h"
|
||||
#include "node_slider.h"
|
||||
#include "node_button_custom.h"
|
||||
#include "node_combobox.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;
|
||||
std::function<void(NodeLayer* target, bool highlight)> on_highlight;
|
||||
bool m_selected = false;
|
||||
@@ -19,7 +19,6 @@ public:
|
||||
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;
|
||||
@@ -42,13 +41,18 @@ 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 idx, bool locked)> on_layer_alpha_lock_changed;
|
||||
std::function<void(Node* target, int idx, bool highlight)> on_layer_highlight_changed;
|
||||
std::function<void(Node* target, int idx, int mode)> on_layer_blend_mode_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;
|
||||
NodeSliderH* m_opacity;
|
||||
NodeCheckBox* m_alpha_lock;
|
||||
NodeComboBox* m_blend_mode;
|
||||
virtual Node* clone_instantiate() const override;
|
||||
virtual void init() override;
|
||||
void add_layer();
|
||||
@@ -57,7 +61,10 @@ public:
|
||||
void remove_layer(NodeLayer* layer);
|
||||
void handle_layer_opacity(NodeLayer* target, float value);
|
||||
void handle_layer_visibility(NodeLayer* target, bool visible);
|
||||
void handle_layer_alpha_lock(NodeLayer* target, bool locked);
|
||||
void handle_layer_highlight(NodeLayer* target, bool highlight);
|
||||
void handle_layer_blend_mode(NodeLayer* target, int mode);
|
||||
void handle_layer_selected(NodeLayer* target);
|
||||
void clear();
|
||||
void update_attributes();
|
||||
};
|
||||
|
||||
@@ -42,8 +42,8 @@ void NodeSliderH::draw()
|
||||
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));
|
||||
//if (on_value_changed)
|
||||
// on_value_changed(this, glm::length(m_value));
|
||||
}
|
||||
|
||||
float NodeSliderH::get_value()
|
||||
|
||||
@@ -16,6 +16,7 @@ enum class kShaderUniform : uint16_t
|
||||
StencilOffset = const_hash("stencil_offset"),
|
||||
StencilAlpha = const_hash("stencil_alpha"),
|
||||
MixAlpha = const_hash("mix_alpha"),
|
||||
StrokeAlpha = const_hash("stroke_alpha"),
|
||||
Wet = const_hash("wet"),
|
||||
Lock = const_hash("lock"),
|
||||
Col = const_hash("col"),
|
||||
|
||||
Reference in New Issue
Block a user