diff --git a/data/layout.xml b/data/layout.xml index 5b7dfd8..09a6fa2 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -24,7 +24,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -134,7 +134,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -199,7 +199,7 @@ - + @@ -235,7 +235,7 @@ - + @@ -275,28 +275,82 @@ - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -310,9 +364,9 @@ - + - + @@ -397,7 +451,7 @@ - + @@ -429,7 +483,7 @@ - + @@ -459,7 +513,7 @@ - + @@ -522,14 +576,14 @@ - + - + @@ -550,7 +604,7 @@ - + diff --git a/src/abr.cpp b/src/abr.cpp index 6d429e9..004911f 100644 --- a/src/abr.cpp +++ b/src/abr.cpp @@ -139,7 +139,7 @@ std::vector> ABR::compute_brushes(const std::string& path //b->m_jitter_val = i.m_jitter_val; //b->m_blend_mode = i.m_blend_mode; //b->m_name.resize(i.m_name_len); - //b->m_stencil_path.resize(i.m_stencil_path_len); + //b->m_texture_path.resize(i.m_stencil_path_len); auto tip_uid = wstr2str(samp->value("sampledData")); LOG("tip uid %d %s", tip_uid.size(), tip_uid.c_str()); b->m_brush_path = path + "/brushes/" + tip_uid + ".png"; @@ -147,9 +147,9 @@ std::vector> ABR::compute_brushes(const std::string& path if (auto patt = p->get("Txtr")) { auto patt_uid = wstr2str(patt->value("Idnt")); - b->m_stencil_path = path + "/patterns/" + patt_uid + ".png"; + b->m_pattern_path = path + "/patterns/" + patt_uid + ".png"; //b->m_brush_thumb_path = path + "/patterns/thumbs/" + patt_uid + ".png"; - b->m_tip_stencil = p->value("textureDepth") * 0.01f; + b->m_pattern_opacity = p->value("textureDepth") * 0.01f; } ret.push_back(b); } diff --git a/src/app_layout.cpp b/src/app_layout.cpp index ba3f942..6e74ba7 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -129,11 +129,11 @@ void App::init_sidebar() Canvas::I->m_current_brush->m_tip_color = color; }; stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) { - Canvas::I->m_current_brush->load_texture(path, thumb); + Canvas::I->m_current_brush->load_tip(path, thumb); stroke->m_preview->draw_stroke(); }; - stroke->on_texture_changed = [this](Node*target, const std::string& path, const std::string& thumb) { - Canvas::I->m_current_brush->load_stencil(path, thumb); + stroke->on_pattern_changed = [this](Node*target, const std::string& path, const std::string& thumb) { + Canvas::I->m_current_brush->load_pattern(path, thumb); stroke->m_preview->draw_stroke(); }; stroke->on_dual_changed = [this](Node*target, const std::string& path, const std::string& thumb) { diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp index 033776c..2d66fd9 100644 --- a/src/app_shaders.cpp +++ b/src/app_shaders.cpp @@ -219,9 +219,10 @@ void App::initShaders() "uniform sampler2D tex_stroke;\n" "uniform sampler2D tex_mask;\n" "uniform sampler2D tex_dual;\n" - //"uniform sampler2D tex_stencil;\n" + "uniform sampler2D tex_pattern;\n" "uniform mediump float alpha;\n" "uniform mediump float stroke_alpha;\n" + "uniform mediump float pattern_alpha;\n" "uniform mediump int blend_mode;\n" "uniform mediump int dual_blend_mode;\n" "uniform mediump vec2 resolution;\n" @@ -229,6 +230,7 @@ void App::initShaders() "uniform bool mask;\n" "uniform bool fragUV2;\n" "uniform bool use_dual;\n" + "uniform bool use_pattern;\n" "in mediump vec2 uv;\n" "out mediump vec4 frag;\n" SHADER_FUNCTION_BLUR @@ -238,6 +240,9 @@ 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" + " if (use_pattern){\n" + " stroke.a *= 1.0 - texture(tex_pattern, uv2 * 5.0).r * pattern_alpha;\n" + " }\n" " if (use_dual){\n" " mediump vec4 dual = texture(tex_dual, uv);\n" //" stroke.a = stroke.a * dual.a;\n" @@ -385,16 +390,17 @@ void App::initShaders() SHADER_EXT_FB_FETCH "uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex_bg;\n" - "uniform mediump sampler2D tex_stencil;\n" + "uniform mediump sampler2D tex_pattern;\n" "uniform mediump sampler2D tex_mix;\n" "uniform mediump vec4 col;\n" "uniform mediump vec2 resolution;\n" "uniform mediump float alpha;\n" "uniform mediump float noise;\n" - "uniform mediump vec2 stencil_offset;\n" - "uniform mediump float stencil_alpha;\n" + "uniform mediump vec2 pattern_offset;\n" + "uniform mediump float pattern_alpha;\n" "uniform mediump float mix_alpha;\n" "uniform mediump float wet;\n" + "uniform bool use_pattern;\n" "in mediump vec2 uv;\n" "in mediump vec2 uv_2;\n" "in mediump float q;\n" @@ -406,9 +412,9 @@ void App::initShaders() SHADER_FUNCTION_RAND "void main() {\n" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" - " mediump float stencil = 1.0 - (texture(tex_stencil, (uv2+stencil_offset) * 5.0).r) * stencil_alpha;\n" + " mediump float pattern = use_pattern ? 1.0 - (texture(tex_pattern, (uv2+pattern_offset) * 5.0).r) * pattern_alpha : 1.0;\n" " mediump float brush_alpha = ( 1.0 - texture(tex, uv/q).r ) * alpha;\n" - " mediump vec4 fg = vec4(col.rgb, brush_alpha * stencil);\n" + " mediump vec4 fg = vec4(col.rgb, brush_alpha * pattern);\n" "#if defined(GL_EXT_shader_framebuffer_fetch)\n" " mediump vec4 bg = frag;\n" "#elif defined(GL_ARM_shader_framebuffer_fetch)\n" @@ -503,18 +509,18 @@ void App::initShaders() static const char* shader_stroke_inst_f = SHADER_VERSION "uniform mediump sampler2D tex;\n" - "uniform mediump sampler2D tex_stencil;\n" + "uniform mediump sampler2D tex_pattern;\n" "uniform mediump vec4 col;\n" "uniform mediump vec2 resolution;\n" - "uniform mediump vec2 stencil_offset;\n" - "uniform mediump float stencil_alpha;\n" + "uniform mediump vec2 pattern_offset;\n" + "uniform mediump float pattern_alpha;\n" "in mediump float alpha;\n" "in mediump vec3 uv;\n" "out mediump vec4 frag;\n" "void main() {\n" " 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;\n" + " mediump float pattern = 1.0 - (texture(tex_pattern, (uv2+pattern_offset)).r * 0.9) * pattern_alpha;\n" + " mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha * pattern;\n" " frag = vec4(col.rgb, a);\n" "}\n"; diff --git a/src/app_vr.cpp b/src/app_vr.cpp index f6de2f7..5bd8024 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -85,18 +85,22 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat } else if (canvas->m_canvas->m_show_tmp && canvas->m_canvas->m_current_layer_idx == layer_index) { + const auto& b = canvas->m_canvas->m_current_stroke->m_brush; sampler.bind(0); ShaderManager::use(kShader::CompDraw); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); 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::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush->m_tip_opacity); + ShaderManager::u_int(kShaderUniform::TexPattern, 3); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity); + ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_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); + ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); + ShaderManager::u_int(kShaderUniform::UseDual, false); + ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && !b->m_pattern_eachsample); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); canvas->m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture(); @@ -105,13 +109,9 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat glActiveTexture(GL_TEXTURE2); canvas->m_canvas->m_smask.m_rtt[plane_index].bindTexture(); glActiveTexture(GL_TEXTURE3); - if (canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture) - canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture->bind(); - else - glBindTexture(GL_TEXTURE_2D, 0); + if (b->m_pattern_texture) + b->m_pattern_texture->bind(); m_face_plane.draw_fill(); - if (canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture) - canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture->unbind(); glActiveTexture(GL_TEXTURE2); canvas->m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); glActiveTexture(GL_TEXTURE1); diff --git a/src/brush.cpp b/src/brush.cpp index 3787447..7a2db27 100644 --- a/src/brush.cpp +++ b/src/brush.cpp @@ -291,7 +291,7 @@ void Stroke::start(const std::shared_ptr& brush) prng.seed(0); } -bool Brush::load_texture(const std::string& path, const std::string& thumb) +bool Brush::load_tip(const std::string& path, const std::string& thumb) { m_tip_texture = std::make_shared(); if (!m_tip_texture->load(path)) @@ -315,15 +315,15 @@ bool Brush::load_dual(const std::string& path, const std::string& thumb) return true; } -bool Brush::load_stencil(const std::string& path, const std::string& thumb) +bool Brush::load_pattern(const std::string& path, const std::string& thumb) { - m_stencil_texture = std::make_shared(); - if (!m_stencil_texture->load(path)) + m_pattern_texture = std::make_shared(); + if (!m_pattern_texture->load(path)) return false; - m_stencil_texture->create_mipmaps(); - m_stencil_texture->auto_destroy = true; - m_stencil_path = path; - m_stencil_thumb_path = thumb; + m_pattern_texture->create_mipmaps(); + m_pattern_texture->auto_destroy = true; + m_pattern_path = path; + m_texture_thumb_path = thumb; return true; } @@ -354,19 +354,19 @@ bool Brush::load() m_dual_texture->create_mipmaps(); m_dual_texture->auto_destroy = true; } - if (!m_stencil_path.empty()) + if (!m_pattern_path.empty()) { - m_stencil_texture = std::make_shared(); - if (!m_stencil_texture->load(m_stencil_path)) + m_pattern_texture = std::make_shared(); + if (!m_pattern_texture->load(m_pattern_path)) { - LOG("failed to load %s", m_stencil_path.c_str()); + LOG("failed to load %s", m_pattern_path.c_str()); m_tip_texture = nullptr; m_dual_texture = nullptr; - m_stencil_texture = nullptr; + m_pattern_texture = nullptr; return false; } - m_stencil_texture->create_mipmaps(); - m_stencil_texture->auto_destroy = true; + m_pattern_texture->create_mipmaps(); + m_pattern_texture->auto_destroy = true; } return true; } diff --git a/src/brush.h b/src/brush.h index c8844e5..b10099b 100644 --- a/src/brush.h +++ b/src/brush.h @@ -18,9 +18,9 @@ public: std::string m_dual_path; std::string m_dual_thumb_path; - std::shared_ptr m_stencil_texture; - std::string m_stencil_path; - std::string m_stencil_thumb_path; + std::shared_ptr m_pattern_texture; + std::string m_pattern_path; + std::string m_texture_thumb_path; glm::vec4 m_tip_color{0, 0, 0, 1}; float m_tip_size = .25f; @@ -30,7 +30,7 @@ public: float m_tip_angle = 0; float m_tip_angle_delay = 0; float m_tip_mix = 0; - float m_tip_stencil = 0; + float m_pattern_opacity = 1.f; float m_tip_wet = 0; float m_tip_noise = 0; float m_tip_hue = 0; @@ -51,7 +51,7 @@ public: bool m_tip_invert = false; bool m_tip_flipx = false; bool m_tip_flipy = false; - bool m_tex_enabled = false; + bool m_pattern_enabled = false; bool m_dual_enabled = false; int m_dual_blend_mode = 0; bool m_dual_randflip = false; @@ -69,9 +69,18 @@ public: float m_dual_opacity = 1.f; float m_dual_rotate = .25f; - bool load_texture(const std::string& path, const std::string& thumb); + int m_pattern_blend_mode = 0; + bool m_pattern_eachsample = false; + bool m_pattern_invert = false; + bool m_pattern_flipx = false; + bool m_pattern_flipy = false; + float m_pattern_scale = .25f; + float m_pattern_brightness = 0.5f; + float m_pattern_contrast = 0.5f; + + bool load_tip(const std::string& path, const std::string& thumb); bool load_dual(const std::string& path, const std::string& thumb); - bool load_stencil(const std::string& path, const std::string& thumb); + bool load_pattern(const std::string& path, const std::string& thumb); bool load(); }; diff --git a/src/canvas.cpp b/src/canvas.cpp index 2da9638..2fad26c 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -240,20 +240,23 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) m_sampler.bind(0); m_sampler.bind(1); m_sampler.bind(2); + const auto& b = m_current_stroke->m_brush; ShaderManager::use(kShader::CompDraw); ShaderManager::u_int(kShaderUniform::Tex, 0); //ShaderManager::u_int(kShaderUniform::TexA, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexMask, 2); //ShaderManager::u_vec2(kShaderUniform::Resolution, m_size); - //ShaderManager::u_int(kShaderUniform::TexStencil, 3); - ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush->m_tip_opacity); + ShaderManager::u_int(kShaderUniform::TexPattern, 3); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity); + ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity); ShaderManager::u_float(kShaderUniform::Alpha, 1); ShaderManager::u_int(kShaderUniform::Lock, false/*m_layers[layer_index].m_alpha_locked*/); ShaderManager::u_int(kShaderUniform::Mask, false/*m_smask_active*/); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); ShaderManager::u_int(kShaderUniform::UseDual, false); - ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush->m_blend_mode); + ShaderManager::u_int(kShaderUniform::UsePattern, false); + ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); m_layers[layer_index].m_rtt[plane_index].bindTexture(); @@ -486,12 +489,13 @@ void Canvas::stroke_draw() ShaderManager::u_int(kShaderUniform::Tex, 0); // brush if (!ShaderManager::ext_framebuffer_fetch) ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg - ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil + ShaderManager::u_int(kShaderUniform::TexPattern, 2); // pattern ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer //ShaderManager::u_int(kShaderUniform::TexMixA, 4); // mixer ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); - ShaderManager::u_vec2(kShaderUniform::StencilOffset, stencil_offset); - ShaderManager::u_float(kShaderUniform::StencilAlpha, brush->m_tip_stencil); + ShaderManager::u_vec2(kShaderUniform::PatternOffset, stencil_offset); + ShaderManager::u_float(kShaderUniform::PatternAlpha, brush->m_pattern_opacity); + ShaderManager::u_int(kShaderUniform::UsePattern, brush->m_pattern_enabled && brush->m_pattern_eachsample); ShaderManager::u_float(kShaderUniform::MixAlpha, brush->m_tip_mix); ShaderManager::u_float(kShaderUniform::Wet, brush->m_tip_wet); ShaderManager::u_float(kShaderUniform::Noise, brush->m_tip_noise); @@ -502,10 +506,8 @@ void Canvas::stroke_draw() glActiveTexture(GL_TEXTURE0); brush->m_tip_texture->bind(); glActiveTexture(GL_TEXTURE2); - if (brush->m_stencil_texture) - brush->m_stencil_texture->bind(); - else - glBindTexture(GL_TEXTURE_2D, 0); + if (brush->m_pattern_texture) + brush->m_pattern_texture->bind(); glActiveTexture(GL_TEXTURE3); m_mixer.bindTexture(); auto frames = stroke_draw_compute(*m_current_stroke); @@ -533,23 +535,19 @@ void Canvas::stroke_draw() } glActiveTexture(GL_TEXTURE3); m_mixer.unbindTexture(); - glActiveTexture(GL_TEXTURE2); - if (brush->m_stencil_texture) - brush->m_stencil_texture->unbind(); glActiveTexture(GL_TEXTURE0); brush->m_tip_texture->unbind(); // DRAW DUAL BRUSH + ShaderManager::u_int(kShaderUniform::UsePattern, false); + ShaderManager::u_float(kShaderUniform::MixAlpha, 0); + ShaderManager::u_float(kShaderUniform::Wet, 0); + ShaderManager::u_float(kShaderUniform::Noise, 0); if (brush->m_dual_enabled) { glActiveTexture(GL_TEXTURE0); dual_brush->m_tip_texture->bind(); - glActiveTexture(GL_TEXTURE2); - if (dual_brush->m_stencil_texture) - dual_brush->m_stencil_texture->bind(); - else - glBindTexture(GL_TEXTURE_2D, 0); auto frames_dual = stroke_draw_compute(*m_dual_stroke); for (auto& f : frames_dual) { @@ -570,9 +568,6 @@ void Canvas::stroke_draw() m_dirty_box[i] = glm::clamp(box_union(m_dirty_box[i], rect), glm::vec4(0), glm::vec4(m_width)); } } - glActiveTexture(GL_TEXTURE2); - if (dual_brush->m_stencil_texture) - dual_brush->m_stencil_texture->unbind(); glActiveTexture(GL_TEXTURE0); dual_brush->m_tip_texture->unbind(); } @@ -719,6 +714,8 @@ void Canvas::stroke_commit() glViewport(0, 0, m_width, m_height); glDisable(GL_BLEND); + const auto& b = m_current_stroke->m_brush; + for (int i = 0; i < 6; i++) { //m_dirty_box[i] = glm::vec4(0, 0, m_width, m_height); // reset bounding box @@ -755,7 +752,8 @@ void Canvas::stroke_commit() m_sampler.bind(0); m_sampler_bg.bind(1); m_sampler_mask.bind(2); - m_sampler_stencil.bind(3); + m_sampler.bind(3); + m_sampler_stencil.bind(4); if (m_current_mode == kCanvasMode::Erase) { ShaderManager::use(kShader::CompErase); @@ -764,7 +762,7 @@ void Canvas::stroke_commit() ShaderManager::u_int(kShaderUniform::TexMask, 2); ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); - ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush->m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity); ShaderManager::u_float(kShaderUniform::Alpha, 1); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); @@ -787,16 +785,19 @@ void Canvas::stroke_commit() ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexMask, 2); + ShaderManager::u_int(kShaderUniform::TexDual, 3); + ShaderManager::u_int(kShaderUniform::TexPattern, 4); //ShaderManager::u_vec2(kShaderUniform::Resolution, m_size); - ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush->m_tip_opacity); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity); + ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_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); + ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - ShaderManager::u_int(kShaderUniform::TexDual, 3); - ShaderManager::u_int(kShaderUniform::UseDual, m_current_stroke->m_brush->m_dual_enabled); - ShaderManager::u_int(kShaderUniform::DualBlendMode, m_current_stroke->m_brush->m_dual_blend_mode); + ShaderManager::u_int(kShaderUniform::UseDual, b->m_dual_enabled); + ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && !b->m_pattern_eachsample); + ShaderManager::u_int(kShaderUniform::DualBlendMode, b->m_dual_blend_mode); glActiveTexture(GL_TEXTURE0); m_tex2[i].bind(); @@ -805,10 +806,14 @@ void Canvas::stroke_commit() glActiveTexture(GL_TEXTURE2); m_smask.m_rtt[i].bindTexture(); glActiveTexture(GL_TEXTURE3); - m_current_stroke->m_brush->m_dual_enabled ? - m_tmp_dual[i].bindTexture() : glBindTexture(GL_TEXTURE_2D, 0); + if (b->m_dual_enabled) + m_tmp_dual[i].bindTexture(); + glActiveTexture(GL_TEXTURE4); + if (b->m_pattern_texture) + b->m_pattern_texture->bind(); m_plane.draw_fill(); - if (m_current_stroke->m_brush->m_dual_enabled) + glActiveTexture(GL_TEXTURE3); + if (b->m_dual_enabled) m_tmp_dual[i].unbindTexture(); glActiveTexture(GL_TEXTURE2); m_smask.m_rtt[i].unbindTexture(); @@ -822,7 +827,7 @@ void Canvas::stroke_commit() // ShaderManager::use(kShader::StrokeLayer); // ShaderManager::u_int(kShaderUniform::TexBG, 1); // ShaderManager::u_int(kShaderUniform::Lock, m_layers[m_current_layer_idx].m_alpha_locked); -// ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->brush->m_tip_opacity); +// ShaderManager::u_float(kShaderUniform::Alpha, b->m_tip_opacity); // // ShaderManager::u_int(kShaderUniform::Tex, 0); // ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); @@ -996,11 +1001,13 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index //ShaderManager::u_vec2(kShaderUniform::Resolution, m_size); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1); + ShaderManager::u_float(kShaderUniform::PatternAlpha, 0); ShaderManager::u_float(kShaderUniform::Alpha, m_layers[source_idx].m_opacity); ShaderManager::u_int(kShaderUniform::Lock, false); ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[source_idx].m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); ShaderManager::u_int(kShaderUniform::UseDual, false); + ShaderManager::u_int(kShaderUniform::UsePattern,false); glActiveTexture(GL_TEXTURE0); m_tex2[i].bind(); diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 669b874..c5db5ac 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -1161,6 +1161,7 @@ void CanvasModeTransform::leave() ShaderManager::u_vec2(kShaderUniform::Resolution, Canvas::I->m_size); ShaderManager::u_int(kShaderUniform::BlendMode, 0); ShaderManager::u_int(kShaderUniform::UseDual, false); + ShaderManager::u_int(kShaderUniform::UsePattern, false); Canvas::I->m_sampler_bg.bind(1); Canvas::I->m_sampler_bg.bind(0); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 19b55b0..bb18163 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -88,7 +88,8 @@ void NodeCanvas::draw() m_sampler.bind(0); m_sampler.bind(1); m_sampler.bind(2); - m_sampler_stencil.bind(3); + m_sampler.bind(3); + m_sampler_stencil.bind(4); auto blend = glIsEnabled(GL_BLEND); auto depth = glIsEnabled(GL_DEPTH_TEST); @@ -146,6 +147,8 @@ void NodeCanvas::draw() use_blend ? glDisable(GL_BLEND) : glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); + const auto& b = m_canvas->m_current_stroke->m_brush; + for (size_t i = 0; i < m_canvas->m_order.size(); i++) { auto layer_index = m_canvas->m_order[i]; @@ -177,8 +180,8 @@ void NodeCanvas::draw() ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexMask, 2); - ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_canvas->m_box) / zoom); - ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush->m_tip_opacity); + //ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_canvas->m_box) / zoom); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->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); @@ -204,18 +207,20 @@ void NodeCanvas::draw() ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); 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::StrokeAlpha, m_canvas->m_current_stroke->m_brush->m_tip_opacity); + ShaderManager::u_int(kShaderUniform::TexDual, 3); + //ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_canvas->m_box) / zoom); + ShaderManager::u_int(kShaderUniform::TexPattern, 4); + ShaderManager::u_float(kShaderUniform::StrokeAlpha, b->m_tip_opacity); + ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_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); - ShaderManager::u_int(kShaderUniform::BlendMode, m_canvas->m_current_stroke->m_brush->m_blend_mode); + ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); - ShaderManager::u_int(kShaderUniform::TexDual, 3); - ShaderManager::u_int(kShaderUniform::UseDual, m_canvas->m_current_stroke->m_brush->m_dual_enabled); - ShaderManager::u_int(kShaderUniform::DualBlendMode, m_canvas->m_current_stroke->m_brush->m_dual_blend_mode); + ShaderManager::u_int(kShaderUniform::UseDual, b->m_dual_enabled); + ShaderManager::u_int(kShaderUniform::DualBlendMode, b->m_dual_blend_mode); + ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && !b->m_pattern_eachsample); glActiveTexture(GL_TEXTURE0); m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture(); @@ -224,11 +229,14 @@ void NodeCanvas::draw() glActiveTexture(GL_TEXTURE2); m_canvas->m_smask.m_rtt[plane_index].bindTexture(); glActiveTexture(GL_TEXTURE3); - m_canvas->m_current_stroke->m_brush->m_dual_enabled ? - m_canvas->m_tmp_dual[plane_index].bindTexture() : - glBindTexture(GL_TEXTURE_2D, 0); + if (b->m_dual_enabled) + m_canvas->m_tmp_dual[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE4); + if (b->m_pattern_texture) + b->m_pattern_texture->bind(); m_face_plane.draw_fill(); - if (m_canvas->m_current_stroke->m_brush->m_dual_enabled) + glActiveTexture(GL_TEXTURE3); + if (b->m_dual_enabled) m_canvas->m_tmp_dual[plane_index].unbindTexture(); glActiveTexture(GL_TEXTURE2); m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index e2e089b..812e104 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -545,38 +545,38 @@ bool NodePanelBrushPreset::save() i.m_brush_thumb_path_len = b->m_brush->m_brush_thumb_path.size(); i.m_dual_path_len = b->m_brush->m_brush_path.size(); i.m_dual_thumb_path_len = b->m_brush->m_brush_thumb_path.size(); - i.m_stencil_path_len = b->m_brush->m_stencil_path.size(); - i.m_stencil_thumb_path_len = b->m_brush->m_stencil_thumb_path.size(); - i.m_tip_color = b->m_brush->m_tip_color; - i.m_tip_size = b->m_brush->m_tip_size; - i.m_tip_spacing = b->m_brush->m_tip_spacing; - i.m_tip_flow = b->m_brush->m_tip_flow; - i.m_tip_opacity = b->m_brush->m_tip_opacity; - i.m_tip_angle = b->m_brush->m_tip_angle; - i.m_tip_angle_delay = b->m_brush->m_tip_angle_delay; - i.m_tip_mix = b->m_brush->m_tip_mix; - i.m_tip_stencil = b->m_brush->m_tip_stencil; - i.m_tip_wet = b->m_brush->m_tip_wet; - i.m_tip_noise = b->m_brush->m_tip_noise; - i.m_tip_hue = b->m_brush->m_tip_hue; - i.m_tip_sat = b->m_brush->m_tip_sat; - i.m_tip_val = b->m_brush->m_tip_val; - i.m_tip_angle_follow = b->m_brush->m_tip_angle_follow; - i.m_tip_flow_pressure = b->m_brush->m_tip_flow_pressure; - i.m_tip_size_pressure = b->m_brush->m_tip_size_pressure; - i.m_jitter_scale = b->m_brush->m_jitter_scale; - i.m_jitter_angle = b->m_brush->m_jitter_angle; - i.m_jitter_spread = b->m_brush->m_jitter_spread; - i.m_jitter_flow = b->m_brush->m_jitter_flow; - i.m_jitter_hue = b->m_brush->m_jitter_hue; - i.m_jitter_sat = b->m_brush->m_jitter_sat; - i.m_jitter_val = b->m_brush->m_jitter_val; - i.m_blend_mode = b->m_brush->m_blend_mode; + i.m_stencil_path_len = b->m_brush->m_pattern_path.size(); + i.m_stencil_thumb_path_len = b->m_brush->m_texture_thumb_path.size(); + i.m_tip_color = b->m_brush->m_tip_color; + i.m_tip_size = b->m_brush->m_tip_size; + i.m_tip_spacing = b->m_brush->m_tip_spacing; + i.m_tip_flow = b->m_brush->m_tip_flow; + i.m_tip_opacity = b->m_brush->m_tip_opacity; + i.m_tip_angle = b->m_brush->m_tip_angle; + i.m_tip_angle_delay = b->m_brush->m_tip_angle_delay; + i.m_tip_mix = b->m_brush->m_tip_mix; + i.m_pattern_opacity = b->m_brush->m_pattern_opacity; + i.m_tip_wet = b->m_brush->m_tip_wet; + i.m_tip_noise = b->m_brush->m_tip_noise; + i.m_tip_hue = b->m_brush->m_tip_hue; + i.m_tip_sat = b->m_brush->m_tip_sat; + i.m_tip_val = b->m_brush->m_tip_val; + i.m_tip_angle_follow = b->m_brush->m_tip_angle_follow; + i.m_tip_flow_pressure = b->m_brush->m_tip_flow_pressure; + i.m_tip_size_pressure = b->m_brush->m_tip_size_pressure; + i.m_jitter_scale = b->m_brush->m_jitter_scale; + i.m_jitter_angle = b->m_brush->m_jitter_angle; + i.m_jitter_spread = b->m_brush->m_jitter_spread; + i.m_jitter_flow = b->m_brush->m_jitter_flow; + i.m_jitter_hue = b->m_brush->m_jitter_hue; + i.m_jitter_sat = b->m_brush->m_jitter_sat; + i.m_jitter_val = b->m_brush->m_jitter_val; + i.m_blend_mode = b->m_brush->m_blend_mode; i.m_tip_invert = b->m_brush->m_tip_invert; i.m_tip_flipx = b->m_brush->m_tip_flipx; i.m_tip_flipy = b->m_brush->m_tip_flipy; - i.m_tex_enabled = b->m_brush->m_tex_enabled; + i.m_pattern_enabled = b->m_brush->m_pattern_enabled; i.m_dual_enabled = b->m_brush->m_dual_enabled; i.m_dual_blend_mode = b->m_brush->m_dual_blend_mode; i.m_dual_randflip = b->m_brush->m_dual_randflip; @@ -594,14 +594,22 @@ bool NodePanelBrushPreset::save() i.m_dual_opacity = b->m_brush->m_dual_opacity; i.m_dual_rotate = b->m_brush->m_dual_rotate; + i.m_pattern_eachsample = b->m_brush->m_pattern_eachsample; + i.m_pattern_invert = b->m_brush->m_pattern_invert; + i.m_pattern_flipx = b->m_brush->m_pattern_flipx; + i.m_pattern_flipy = b->m_brush->m_pattern_flipy; + i.m_pattern_scale = b->m_brush->m_pattern_scale; + i.m_pattern_brightness = b->m_brush->m_pattern_brightness; + i.m_pattern_contrast = b->m_brush->m_pattern_contrast; + fwrite(&i, sizeof(i), 1, fp); fwrite(b->m_brush->m_name.c_str(), 1, b->m_brush->m_name.size(), fp); fwrite(b->m_brush->m_brush_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp); fwrite(b->m_brush->m_brush_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp); fwrite(b->m_brush->m_dual_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp); fwrite(b->m_brush->m_dual_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp); - fwrite(b->m_brush->m_stencil_path.c_str(), 1, b->m_brush->m_stencil_path.size(), fp); - fwrite(b->m_brush->m_stencil_thumb_path.c_str(), 1, b->m_brush->m_stencil_thumb_path.size(), fp); + fwrite(b->m_brush->m_pattern_path.c_str(), 1, b->m_brush->m_pattern_path.size(), fp); + fwrite(b->m_brush->m_texture_thumb_path.c_str(), 1, b->m_brush->m_texture_thumb_path.size(), fp); } fclose(fp); return true; @@ -634,36 +642,36 @@ bool NodePanelBrushPreset::restore() item_t i; fread(&i, sizeof(i), 1, fp); auto b = std::make_shared(); - b->m_tip_color = i.m_tip_color; - b->m_tip_size = i.m_tip_size; - b->m_tip_spacing = i.m_tip_spacing; - b->m_tip_flow = i.m_tip_flow; - b->m_tip_opacity = i.m_tip_opacity; - b->m_tip_angle = i.m_tip_angle; - b->m_tip_angle_delay = i.m_tip_angle_delay; - b->m_tip_mix = i.m_tip_mix; - b->m_tip_stencil = i.m_tip_stencil; - b->m_tip_wet = i.m_tip_wet; - b->m_tip_noise = i.m_tip_noise; - b->m_tip_hue = i.m_tip_hue; - b->m_tip_sat = i.m_tip_sat; - b->m_tip_val = i.m_tip_val; - b->m_tip_angle_follow = i.m_tip_angle_follow; - b->m_tip_flow_pressure = i.m_tip_flow_pressure; - b->m_tip_size_pressure = i.m_tip_size_pressure; - b->m_jitter_scale = i.m_jitter_scale; - b->m_jitter_angle = i.m_jitter_angle; - b->m_jitter_spread = i.m_jitter_spread; - b->m_jitter_flow = i.m_jitter_flow; - b->m_jitter_hue = i.m_jitter_hue; - b->m_jitter_sat = i.m_jitter_sat; - b->m_jitter_val = i.m_jitter_val; - b->m_blend_mode = i.m_blend_mode; + b->m_tip_color = i.m_tip_color; + b->m_tip_size = i.m_tip_size; + b->m_tip_spacing = i.m_tip_spacing; + b->m_tip_flow = i.m_tip_flow; + b->m_tip_opacity = i.m_tip_opacity; + b->m_tip_angle = i.m_tip_angle; + b->m_tip_angle_delay = i.m_tip_angle_delay; + b->m_tip_mix = i.m_tip_mix; + b->m_pattern_opacity = i.m_pattern_opacity; + b->m_tip_wet = i.m_tip_wet; + b->m_tip_noise = i.m_tip_noise; + b->m_tip_hue = i.m_tip_hue; + b->m_tip_sat = i.m_tip_sat; + b->m_tip_val = i.m_tip_val; + b->m_tip_angle_follow = i.m_tip_angle_follow; + b->m_tip_flow_pressure = i.m_tip_flow_pressure; + b->m_tip_size_pressure = i.m_tip_size_pressure; + b->m_jitter_scale = i.m_jitter_scale; + b->m_jitter_angle = i.m_jitter_angle; + b->m_jitter_spread = i.m_jitter_spread; + b->m_jitter_flow = i.m_jitter_flow; + b->m_jitter_hue = i.m_jitter_hue; + b->m_jitter_sat = i.m_jitter_sat; + b->m_jitter_val = i.m_jitter_val; + b->m_blend_mode = i.m_blend_mode; b->m_tip_invert = i.m_tip_invert; b->m_tip_flipx = i.m_tip_flipx; b->m_tip_flipy = i.m_tip_flipy; - b->m_tex_enabled = i.m_tex_enabled; + b->m_pattern_enabled = i.m_pattern_enabled; b->m_dual_enabled = i.m_dual_enabled; b->m_dual_blend_mode = i.m_dual_blend_mode; b->m_dual_randflip = i.m_dual_randflip; @@ -679,25 +687,33 @@ bool NodePanelBrushPreset::restore() b->m_dual_opacity = i.m_dual_opacity; b->m_dual_rotate = i.m_dual_rotate; + b->m_pattern_eachsample = i.m_pattern_eachsample; + b->m_pattern_invert = i.m_pattern_invert; + b->m_pattern_flipx = i.m_pattern_flipx; + b->m_pattern_flipy = i.m_pattern_flipy; + b->m_pattern_scale = i.m_pattern_scale; + b->m_pattern_brightness = i.m_pattern_brightness; + b->m_pattern_contrast = i.m_pattern_contrast; + b->m_name.resize(i.m_name_len); b->m_brush_path.resize(i.m_brush_path_len); b->m_brush_thumb_path.resize(i.m_brush_thumb_path_len); b->m_dual_path.resize(i.m_brush_path_len); b->m_dual_thumb_path.resize(i.m_brush_thumb_path_len); - b->m_stencil_path.resize(i.m_stencil_path_len); - b->m_stencil_thumb_path.resize(i.m_stencil_thumb_path_len); + b->m_pattern_path.resize(i.m_stencil_path_len); + b->m_texture_thumb_path.resize(i.m_stencil_thumb_path_len); fread((char*)b->m_name.c_str(), 1, b->m_name.size(), fp); fread((char*)b->m_brush_path.c_str(), 1, b->m_brush_path.size(), fp); fread((char*)b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp); fread((char*)b->m_dual_path.c_str(), 1, b->m_brush_path.size(), fp); fread((char*)b->m_dual_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp); - fread((char*)b->m_stencil_path.c_str(), 1, b->m_stencil_path.size(), fp); - fread((char*)b->m_stencil_thumb_path.c_str(), 1, b->m_stencil_thumb_path.size(), fp); + fread((char*)b->m_pattern_path.c_str(), 1, b->m_pattern_path.size(), fp); + fread((char*)b->m_texture_thumb_path.c_str(), 1, b->m_texture_thumb_path.size(), fp); - if (b->load_texture(b->m_brush_path, b->m_brush_thumb_path)) + if (b->load_tip(b->m_brush_path, b->m_brush_thumb_path)) { - if (!b->m_stencil_path.empty()) - b->load_stencil(b->m_stencil_path, b->m_stencil_thumb_path); + if (!b->m_pattern_path.empty()) + b->load_pattern(b->m_pattern_path, b->m_texture_thumb_path); NodeBrushPresetItem* brush = new NodeBrushPresetItem; m_container->add_child(brush); diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h index d175a4b..85e9184 100644 --- a/src/node_panel_brush.h +++ b/src/node_panel_brush.h @@ -111,7 +111,7 @@ class NodePanelBrushPreset : public Node float m_tip_angle = 0; float m_tip_angle_delay = 0; float m_tip_mix = 0; - float m_tip_stencil = 0; + float m_pattern_opacity = 0; float m_tip_wet = 0; float m_tip_noise = 0; float m_tip_hue = 0; @@ -132,7 +132,7 @@ class NodePanelBrushPreset : public Node bool m_tip_invert = false; bool m_tip_flipx = false; bool m_tip_flipy = false; - bool m_tex_enabled = false; + bool m_pattern_enabled = false; bool m_dual_enabled = false; int m_dual_blend_mode = 0; bool m_dual_randflip = false; @@ -149,6 +149,14 @@ class NodePanelBrushPreset : public Node float m_dual_flow = .75f; float m_dual_opacity = 1.f; float m_dual_rotate = .25f; + + bool m_pattern_eachsample = false; + bool m_pattern_invert = false; + bool m_pattern_flipx = false; + bool m_pattern_flipy = false; + float m_pattern_scale = .25f; + float m_pattern_brightness = 0.5f; + float m_pattern_contrast = 0.5f; }; public: std::function& brush)> on_brush_changed; diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp index a1b97a0..961809a 100644 --- a/src/node_panel_stroke.cpp +++ b/src/node_panel_stroke.cpp @@ -31,7 +31,7 @@ void NodePanelStroke::update_controls() m_tip_opacity->m_value.x = b->m_tip_opacity; m_tip_angle->m_value.x = b->m_tip_angle; m_tip_angle_delay->m_value.x = b->m_tip_angle_delay; - m_tip_stencil->m_value.x = b->m_tip_stencil; + m_pattern_opacity->m_value.x = b->m_pattern_opacity; m_tip_wet->m_value.x = b->m_tip_wet; m_tip_noise->m_value.x = b->m_tip_noise; m_jitter_scale->m_value.x = b->m_jitter_scale; @@ -48,7 +48,7 @@ void NodePanelStroke::update_controls() m_tip_invert->checked = b->m_tip_invert; m_tip_flipx->checked = b->m_tip_flipx; m_tip_flipy->checked = b->m_tip_flipy; - m_tex_enabled->checked = b->m_tex_enabled; + m_pattern_enabled->checked = b->m_pattern_enabled; m_dual_enabled->checked = b->m_dual_enabled; m_dual_scatter_axis->checked = b->m_dual_scatter_axis; m_dual_invert->checked = b->m_dual_invert; @@ -66,8 +66,17 @@ void NodePanelStroke::update_controls() m_dual_opacity->m_value.x = b->m_dual_opacity; m_dual_rotate->m_value.x = b->m_dual_rotate; + m_pattern_eachsample->checked = b->m_pattern_eachsample; + m_pattern_invert->checked = b->m_pattern_invert; + m_pattern_flipx->checked = b->m_pattern_flipx; + m_pattern_flipy->checked = b->m_pattern_flipy; + m_pattern_scale->m_value.x = b->m_pattern_scale; + m_pattern_brightness->m_value.x = b->m_pattern_brightness; + m_pattern_contrast->m_value.x = b->m_pattern_contrast; + m_blend_mode->set_index(b->m_blend_mode); m_dual_blend_mode->set_index(b->m_dual_blend_mode); + m_pattern_blend_mode->set_index(b->m_pattern_blend_mode); m_preview->m_brush = b; m_preview->draw_stroke(); @@ -87,17 +96,17 @@ void NodePanelStroke::init_controls() m_brush_popup->m_flood_events = true; m_brush_popup->m_capture_children = false; - m_texture_popup = std::make_shared(); - m_texture_popup->m_manager = m_manager; - m_texture_popup->m_dir_name = "textures"; - m_texture_popup->init(); - m_texture_popup->create(); - m_texture_popup->loaded(); - m_texture_popup->SetPositioning(YGPositionTypeAbsolute); - m_texture_popup->SetSize(300, 400); - m_texture_popup->m_mouse_ignore = false; - m_texture_popup->m_flood_events = true; - m_texture_popup->m_capture_children = false; + m_pattern_popup = std::make_shared(); + m_pattern_popup->m_manager = m_manager; + m_pattern_popup->m_dir_name = "textures"; + m_pattern_popup->init(); + m_pattern_popup->create(); + m_pattern_popup->loaded(); + m_pattern_popup->SetPositioning(YGPositionTypeAbsolute); + m_pattern_popup->SetSize(300, 400); + m_pattern_popup->m_mouse_ignore = false; + m_pattern_popup->m_flood_events = true; + m_pattern_popup->m_capture_children = false; m_presets_popup = std::make_shared(); m_presets_popup->m_manager = m_manager; @@ -114,8 +123,9 @@ void NodePanelStroke::init_controls() // init main brush auto b = std::make_shared(); - b->load_texture(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx)); + b->load_tip(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx)); b->load_dual(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx)); + b->load_pattern(m_pattern_popup->get_texture_path(0), m_pattern_popup->get_thumb_path(0)); b->m_tip_size = .1f; b->m_tip_flow = .5f; b->m_tip_spacing = .1f; @@ -237,37 +247,37 @@ void NodePanelStroke::init_controls() }; - // TEXTURE IMAGE + // PATTERN IMAGE - m_texture_thumb = find("texture-change-thumb"); - m_texture_thumb->set_image(m_texture_popup->get_thumb_path(0)); - m_texture_button = find("texture-change"); - m_texture_button->on_click = [this](Node*) { + m_pattern_thumb = find("pattern-change-thumb"); + m_pattern_thumb->set_image(m_pattern_popup->get_thumb_path(0)); + m_pattern_button = find("pattern-change"); + m_pattern_button->on_click = [this](Node*) { auto screen = root()->m_size; - glm::vec2 pos = m_texture_button->m_pos + glm::vec2(m_texture_button->m_size.x, 0); - root()->add_child(m_texture_popup); + glm::vec2 pos = m_pattern_button->m_pos + glm::vec2(m_pattern_button->m_size.x, 0); + root()->add_child(m_pattern_popup); auto tick = root()->add_child(); tick->SetPositioning(YGPositionTypeAbsolute); tick->SetSize(16, 32); - tick->SetPosition(pos.x, pos.y + (m_texture_button->m_size.y - 32) * 0.5f); + tick->SetPosition(pos.x, pos.y + (m_pattern_button->m_size.y - 32) * 0.5f); tick->set_image("data/ui/popup-tick.png"); root()->update(); - if ((pos.y + m_texture_popup->m_size.y) > screen.y) - pos.y = screen.y - m_texture_popup->m_size.y; + if ((pos.y + m_pattern_popup->m_size.y) > screen.y) + pos.y = screen.y - m_pattern_popup->m_size.y; if (pos.y < 0) pos.y = 0; - m_texture_popup->SetPosition(pos.x + 16, pos.y); - m_texture_popup->mouse_capture(); + m_pattern_popup->SetPosition(pos.x + 16, pos.y); + m_pattern_popup->mouse_capture(); root()->update(); - m_texture_popup->on_popup_close = [this, tick](Node*) { + m_pattern_popup->on_popup_close = [this, tick](Node*) { tick->destroy(); }; - m_texture_popup->on_brush_changed = [this](Node*, int index) { - if (on_texture_changed) - on_texture_changed(this, m_texture_popup->get_texture_path(index), m_texture_popup->get_thumb_path(index)); - m_texture_thumb->set_image(m_texture_popup->get_thumb_path(index)); + m_pattern_popup->on_brush_changed = [this](Node*, int index) { + if (on_pattern_changed) + on_pattern_changed(this, m_pattern_popup->get_texture_path(index), m_pattern_popup->get_thumb_path(index)); + m_pattern_thumb->set_image(m_pattern_popup->get_thumb_path(index)); }; }; @@ -288,7 +298,7 @@ void NodePanelStroke::init_controls() init_slider(m_tip_angle, "tip-angle", &Brush::m_tip_angle); init_slider(m_tip_angle_delay, "tip-angle-delay", &Brush::m_tip_angle_delay); init_slider(m_tip_mix, "tip-mix", &Brush::m_tip_mix); - init_slider(m_tip_stencil, "tip-stencil", &Brush::m_tip_stencil); + init_slider(m_pattern_opacity, "pattern-opacity", &Brush::m_pattern_opacity); init_slider(m_tip_wet, "tip-wet", &Brush::m_tip_wet); init_slider(m_tip_noise, "tip-noise", &Brush::m_tip_noise); init_slider(m_tip_hue, "tip-hue", &Brush::m_tip_hue); @@ -309,7 +319,7 @@ void NodePanelStroke::init_controls() init_checkbox(m_tip_invert, "tip-invert", &Brush::m_tip_invert); init_checkbox(m_tip_flipx, "tip-flipx", &Brush::m_tip_flipx); init_checkbox(m_tip_flipy, "tip-flipy", &Brush::m_tip_flipy); - init_checkbox(m_tex_enabled, "tex-enabled", &Brush::m_tex_enabled); + init_checkbox(m_pattern_enabled, "pattern-enabled", &Brush::m_pattern_enabled); init_checkbox(m_dual_enabled, "dual-enabled", &Brush::m_dual_enabled); init_checkbox(m_dual_scatter_axis, "dual-scatter-axis", &Brush::m_dual_scatter_axis); init_checkbox(m_dual_invert, "dual-invert", &Brush::m_dual_invert); @@ -318,6 +328,11 @@ void NodePanelStroke::init_controls() init_checkbox(m_dual_randflip, "dual-randflip", &Brush::m_dual_randflip); init_checkbox(m_tip_randflipx, "tip-randflipx", &Brush::m_tip_randflipx); init_checkbox(m_tip_randflipy, "tip-randflipy", &Brush::m_tip_randflipy); + init_checkbox(m_pattern_eachsample, "pattern-eachsample", &Brush::m_pattern_eachsample); + + init_checkbox(m_pattern_invert, "pattern-invert", &Brush::m_pattern_invert); + init_checkbox(m_pattern_flipx, "pattern-flipx", &Brush::m_pattern_flipx); + init_checkbox(m_pattern_flipy, "pattern-flipy", &Brush::m_pattern_flipy); init_slider(m_dual_size, "dual-size", &Brush::m_dual_size); init_slider(m_dual_spacing, "dual-spacing", &Brush::m_dual_spacing); @@ -326,6 +341,9 @@ void NodePanelStroke::init_controls() init_slider(m_dual_opacity, "dual-opacity", &Brush::m_dual_opacity); init_slider(m_dual_flow, "dual-flow", &Brush::m_dual_flow); init_slider(m_dual_rotate, "dual-rotate", &Brush::m_dual_rotate); + init_slider(m_pattern_scale, "pattern-scale", &Brush::m_pattern_scale); + init_slider(m_pattern_brightness, "pattern-brightness", &Brush::m_pattern_brightness); + init_slider(m_pattern_contrast, "pattern-contrast", &Brush::m_pattern_contrast); auto curve_cubic = [](float v) { return glm::pow(v, 3.f); }; auto curve_quad = [](float v) { return glm::pow(v, 2.f); }; @@ -353,6 +371,14 @@ void NodePanelStroke::init_controls() on_stroke_change(this); }; + m_pattern_blend_mode = find("pattern-blend-mode"); + m_pattern_blend_mode->on_select = [this](Node*, int index) { + Canvas::I->m_current_brush->m_pattern_blend_mode = index; + m_preview->draw_stroke(); + if (on_stroke_change) + on_stroke_change(this); + }; + m_preview->m_brush = Canvas::I->m_current_brush; m_preview->draw_stroke(); @@ -363,8 +389,8 @@ void NodePanelStroke::init_controls() App::I.async_start(); if (TextureManager::load(path.c_str())) { - if (on_texture_changed) - on_texture_changed(this, path, ""); + if (on_pattern_changed) + on_pattern_changed(this, path, ""); } App::I.async_redraw(); App::I.async_end(); diff --git a/src/node_panel_stroke.h b/src/node_panel_stroke.h index 436d041..3a5a7eb 100644 --- a/src/node_panel_stroke.h +++ b/src/node_panel_stroke.h @@ -21,7 +21,7 @@ public: NodeSliderH* m_tip_angle; NodeSliderH* m_tip_angle_delay; NodeSliderH* m_tip_mix; - NodeSliderH* m_tip_stencil; + NodeSliderH* m_pattern_opacity; NodeSliderH* m_tip_wet; NodeSliderH* m_tip_noise; NodeSliderH* m_tip_hue; @@ -39,10 +39,10 @@ public: NodeCheckBox* m_tip_size_pressure; NodeButtonCustom* m_brush_button; NodeButtonCustom* m_dual_brush_button; - NodeButtonCustom* m_texture_button; + NodeButtonCustom* m_pattern_button; NodeImage* m_brush_thumb; NodeImage* m_dual_brush_thumb; - NodeImage* m_texture_thumb; + NodeImage* m_pattern_thumb; NodeImage* m_preset_thumb; NodeButtonCustom* m_preset_button; NodeStrokePreview* m_preset_preview; @@ -50,7 +50,7 @@ public: NodeCheckBox* m_tip_invert; NodeCheckBox* m_tip_flipx; NodeCheckBox* m_tip_flipy; - NodeCheckBox* m_tex_enabled; + NodeCheckBox* m_pattern_enabled; NodeCheckBox* m_dual_enabled; NodeCheckBox* m_dual_scatter_axis; NodeCheckBox* m_dual_invert; @@ -67,15 +67,26 @@ public: NodeSliderH* m_dual_opacity; NodeSliderH* m_dual_rotate; NodeComboBox* m_dual_blend_mode; + NodeComboBox* m_pattern_blend_mode; NodeButtonCustom* m_tip_aspect_reset; + NodeCheckBox* m_pattern_eachsample; + NodeCheckBox* m_pattern_invert; + NodeCheckBox* m_pattern_flipx; + NodeCheckBox* m_pattern_flipy; + NodeSliderH* m_pattern_scale; + NodeSliderH* m_pattern_brightness; + NodeSliderH* m_pattern_contrast; + + std::shared_ptr m_brush_popup; - std::shared_ptr m_texture_popup; + std::shared_ptr m_pattern_popup; std::shared_ptr m_presets_popup; std::function on_stroke_change; - std::function on_texture_changed; + std::function on_pattern_changed; std::function on_brush_changed; std::function on_dual_changed; + //std::function on_texture_changed; std::map> m_curves; virtual Node* clone_instantiate() const override; diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index 78785f5..b7ad314 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -84,8 +84,8 @@ void NodeStrokePreview::draw_stroke() m_sampler_brush.bind(0); glActiveTexture(GL_TEXTURE1); - if (b->m_stencil_texture) - b->m_stencil_texture->bind(); + if (b->m_pattern_texture && b->m_pattern_enabled) + b->m_pattern_texture->bind(); else glBindTexture(GL_TEXTURE_2D, 0); m_sampler.bind(1); @@ -95,10 +95,10 @@ void NodeStrokePreview::draw_stroke() 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_int(kShaderUniform::TexPattern, 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); + ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(0)); + ShaderManager::u_float(kShaderUniform::PatternAlpha, b->m_pattern_opacity); m_mesh.draw(samples, proj); } //else diff --git a/src/shader.h b/src/shader.h index 6780a60..796dede 100644 --- a/src/shader.h +++ b/src/shader.h @@ -13,9 +13,9 @@ enum class kShaderUniform : uint16_t TexMask = const_hash("tex_mask"), TexDual = const_hash("tex_dual"), TexStroke = const_hash("tex_stroke"), - TexStencil = const_hash("tex_stencil"), - StencilOffset = const_hash("stencil_offset"), - StencilAlpha = const_hash("stencil_alpha"), + TexPattern = const_hash("tex_pattern"), + PatternOffset = const_hash("pattern_offset"), + PatternAlpha = const_hash("pattern_alpha"), MixAlpha = const_hash("mix_alpha"), StrokeAlpha = const_hash("stroke_alpha"), Wet = const_hash("wet"), @@ -33,6 +33,7 @@ enum class kShaderUniform : uint16_t Direction = const_hash("dir"), UseFragCoordUV2 = const_hash("fragUV2"), UseDual = const_hash("use_dual"), + UsePattern = const_hash("use_pattern"), LightDir = const_hash("light_dir"), Mode = const_hash("mode"), Ambient = const_hash("ambient"),