diff --git a/data/layout.xml b/data/layout.xml index e645d53..7ee3710 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -801,6 +801,7 @@ --> + diff --git a/engine/app_shaders.cpp b/engine/app_shaders.cpp index 13ef202..fe8d64c 100644 --- a/engine/app_shaders.cpp +++ b/engine/app_shaders.cpp @@ -307,13 +307,14 @@ void App::initShaders() "uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_stencil;\n" - //"layout (binding=3, rgba8) uniform image2D tex_mix;\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 float mix_alpha;\n" "uniform mediump float wet;\n" "in mediump vec2 uv;\n" "in mediump float q;\n" @@ -343,6 +344,7 @@ void App::initShaders() #else " mediump vec4 bg = texture(tex_bg, uv2);\n" #endif + " mediump vec4 mbg = texture(tex_mix, uv/q);\n" " fg.a *= 1.0-rand(uv2+uv)*noise;\n" " if (fg.a == 0.0) discard;\n" " mediump float contribution = (1.0 - bg.a) * fg.a;\n" @@ -350,7 +352,7 @@ void App::initShaders() " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" " mediump vec4 frag_wet = vec4(rgb, max(bg.a, fg.a * 1.2));\n" " mediump vec4 frag_dry = vec4(rgb, alpha_tot);\n" - " frag = mix(frag_dry, frag_wet, wet);\n" + " frag = mix(mix(frag_dry, frag_wet, wet), mbg, mix_alpha);\n" "}\n"; static const char* shader_checkerboard_v = diff --git a/engine/brush.h b/engine/brush.h index 34bf44b..d849d4e 100644 --- a/engine/brush.h +++ b/engine/brush.h @@ -16,6 +16,7 @@ public: float m_tip_flow = 0; float m_tip_opacity = 0; float m_tip_angle = 0; + float m_tip_mix = 0; float m_tip_stencil = 0; float m_tip_wet = 0; float m_tip_noise = 0; diff --git a/engine/canvas.cpp b/engine/canvas.cpp index d4c228a..5bdcd3d 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -219,6 +219,46 @@ void ui::Canvas::stroke_cancel() m_current_stroke = nullptr; m_show_tmp = false; } +void ui::Canvas::stroke_draw_mix() +{ + m_mixer.bindFramebuffer(); + m_mixer.clear({ 0, 1, 1, 1 }); + + glViewport(m_vp.x, m_vp.y, m_vp.z, m_vp.w); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + + m_sampler_bg.bind(0); + 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) + continue; + + auto plane_mvp_z = m_proj * m_mv * + m_plane_transform[plane_index] * + glm::translate(glm::vec3(0, 0, -1)); + { + ui::ShaderManager::use(kShader::TextureAlpha); + ui::ShaderManager::u_int(kShaderUniform::Tex, 0); + ui::ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity); + ui::ShaderManager::u_int(kShaderUniform::Highlight, false); + ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); + + glActiveTexture(GL_TEXTURE0); + +// m_layers[layer_index].m_rtt[plane_index].bindTexture(); +// m_node->m_face_plane.draw_fill(); +// m_layers[layer_index].m_rtt[plane_index].unbindTexture(); + + m_tmp[plane_index].bindTexture(); + m_node->m_face_plane.draw_fill(); + m_tmp[plane_index].unbindTexture(); + } + } + m_sampler_bg.unbind(); + m_mixer.unbindFramebuffer(); +} void ui::Canvas::stroke_draw() { if (!(m_current_stroke && m_current_stroke->has_sample())) @@ -231,6 +271,8 @@ void ui::Canvas::stroke_draw() glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); + stroke_draw_mix(); + glViewport(0, 0, m_width, m_height); auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f); @@ -243,11 +285,13 @@ void ui::Canvas::stroke_draw() tex.bind(); m_sampler_brush.bind(0); m_sampler_bg.bind(1); - m_sampler_mask.bind(2); - m_sampler_stencil.bind(3); + m_sampler_stencil.bind(2); + m_sampler_mix.bind(3); - glActiveTexture(GL_TEXTURE3); + glActiveTexture(GL_TEXTURE2); stencil.bind(); + glActiveTexture(GL_TEXTURE3); + m_mixer.bindTexture(); for (int i = 0; i < 6; i++) { @@ -280,10 +324,12 @@ void ui::Canvas::stroke_draw() #ifndef __IOS__ ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg #endif - ShaderManager::u_int(kShaderUniform::TexStencil, 3); // stencil + ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil + ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); ShaderManager::u_vec2(kShaderUniform::StencilOffset, stencil_offset); ShaderManager::u_float(kShaderUniform::StencilAlpha, m_brush.m_tip_stencil); + ShaderManager::u_float(kShaderUniform::MixAlpha, m_brush.m_tip_mix); ShaderManager::u_float(kShaderUniform::Wet, m_brush.m_tip_wet); ShaderManager::u_float(kShaderUniform::Noise, m_brush.m_tip_noise); for (const auto& s : samples) @@ -360,11 +406,11 @@ void ui::Canvas::stroke_draw() } } - if (m_alpha_lock) - { - glActiveTexture(GL_TEXTURE2); - m_layers[m_current_layer_idx].m_rtt[i].unbindTexture(); - } +// if (m_alpha_lock) +// { +// glActiveTexture(GL_TEXTURE2); +// m_layers[m_current_layer_idx].m_rtt[i].unbindTexture(); +// } glActiveTexture(GL_TEXTURE1); m_tex[i].unbind(); @@ -374,10 +420,15 @@ void ui::Canvas::stroke_draw() glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE2); + stencil.unbind(); + glActiveTexture(GL_TEXTURE3); + m_mixer.unbindTexture(); + glActiveTexture(GL_TEXTURE0); m_sampler_brush.unbind(); m_sampler_bg.unbind(); - m_sampler_mask.unbind(); + m_sampler_stencil.unbind(); tex.unbind(); glViewport(vp[0], vp[1], vp[2], vp[3]); @@ -803,6 +854,7 @@ bool ui::Canvas::create(int width, int height) m_sampler_bg.create(GL_NEAREST); m_sampler_mask.create(GL_LINEAR); m_sampler_stencil.create(GL_LINEAR, GL_REPEAT); + m_sampler_mix.create(GL_LINEAR, GL_REPEAT); m_plane.create<1>(1, 1); m_plane_brush.create<1>(1, 1); m_mesh.create(); diff --git a/engine/canvas.h b/engine/canvas.h index 6453194..bd3b67e 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -54,11 +54,13 @@ public: bool m_dirty_stroke = false; static Canvas* I; + NodeCanvas* m_node = nullptr; bool m_alpha_lock = false; bool m_touch_lock = true; glm::mat4 m_mv{ 1 }; glm::mat4 m_proj{ 1 }; glm::vec4 m_box{ 0 }; + glm::vec4 m_vp{ 0 }; glm::vec2 m_pan{ 0 }; int m_width = 0; int m_height = 0; @@ -73,6 +75,7 @@ public: Layer m_smask; // selection mask bool m_smask_active = false; RTT m_tmp[6]; + RTT m_mixer; Texture2D m_brush_mix; Texture2D m_tex[6]; Texture2D m_tex2[6]; @@ -88,6 +91,7 @@ public: Sampler m_sampler_bg; Sampler m_sampler_mask; Sampler m_sampler_stencil; + Sampler m_sampler_mix; glm::vec2 m_cam_rot{ 0 }; glm::vec3 m_cam_pos{ 0 }; float m_cam_fov = 85; @@ -124,6 +128,7 @@ public: void layer_merge(int source_idx, int dest_idx); void stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush); void stroke_update(glm::vec2 point, float pressure); + void stroke_draw_mix(); void stroke_draw(); void stroke_end(); void stroke_cancel(); @@ -152,7 +157,6 @@ public: void inject_xmp(std::string jpg_path); ui::Image thumbnail_generate(int w, int h); ui::Image thumbnail_read(std::string data_path); - void preview_generate(); void draw_objects(std::function); void draw_objects(std::function, Layer& layer); bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, diff --git a/engine/node_canvas.cpp b/engine/node_canvas.cpp index e71fd03..931b3d0 100644 --- a/engine/node_canvas.cpp +++ b/engine/node_canvas.cpp @@ -2,6 +2,7 @@ #include "app.h" #include "log.h" #include "node_canvas.h" +#include "node_image_texture.h" Node* NodeCanvas::clone_instantiate() const { @@ -14,6 +15,7 @@ void NodeCanvas::init() m_canvas = std::make_unique(); m_canvas->create(CANVAS_RES, CANVAS_RES); m_canvas->m_unsaved = false; + m_canvas->m_node = this; m_sampler.create(GL_NEAREST); m_sampler_linear.create(GL_LINEAR); m_sampler_stencil.create(GL_LINEAR, GL_REPEAT); @@ -73,6 +75,7 @@ void NodeCanvas::draw() m_canvas->m_mv = camera; m_canvas->m_proj = proj; m_canvas->m_box = box; + m_canvas->m_vp = c; // auto plane_mvp = proj * camera * transform * // glm::scale(glm::vec3(sz, 1)); @@ -267,6 +270,9 @@ void NodeCanvas::handle_resize(glm::vec2 old_size, glm::vec2 new_size) { if (new_size.x > m_canvas->m_width) { + m_canvas->m_mixer.create((int)new_size.x, (int)new_size.y); + if (auto img = root()->find("tex-debug")) + img->tex.assign(m_canvas->m_mixer.getTextureID()); // m_canvas->resize((int)new_size.x, (int)new_size.y); // m_canvas->clear(); } diff --git a/engine/node_panel_stroke.cpp b/engine/node_panel_stroke.cpp index 9ce4148..ddb4265 100644 --- a/engine/node_panel_stroke.cpp +++ b/engine/node_panel_stroke.cpp @@ -58,6 +58,7 @@ void NodePanelStroke::init_controls() init_slider(m_tip_flow, "tip-flow", &ui::Brush::m_tip_flow); init_slider(m_tip_opacity, "tip-opacity", &ui::Brush::m_tip_opacity); init_slider(m_tip_angle, "tip-angle", &ui::Brush::m_tip_angle); + init_slider(m_tip_mix, "tip-mix", &ui::Brush::m_tip_mix); init_slider(m_tip_stencil, "tip-stencil", &ui::Brush::m_tip_stencil); init_slider(m_tip_wet, "tip-wet", &ui::Brush::m_tip_wet); init_slider(m_tip_noise, "tip-noise", &ui::Brush::m_tip_noise); diff --git a/engine/node_panel_stroke.h b/engine/node_panel_stroke.h index 9dac511..e6cbcec 100644 --- a/engine/node_panel_stroke.h +++ b/engine/node_panel_stroke.h @@ -16,6 +16,7 @@ public: NodeSliderH* m_tip_flow; NodeSliderH* m_tip_opacity; NodeSliderH* m_tip_angle; + NodeSliderH* m_tip_mix; NodeSliderH* m_tip_stencil; NodeSliderH* m_tip_wet; NodeSliderH* m_tip_noise; diff --git a/engine/shader.h b/engine/shader.h index 9a1e297..d86b3e5 100644 --- a/engine/shader.h +++ b/engine/shader.h @@ -9,11 +9,13 @@ enum class kShaderUniform : uint16_t Tex = const_hash("tex"), TexFG = const_hash("tex_fg"), TexBG = const_hash("tex_bg"), + TexMix = const_hash("tex_mix"), TexMask = const_hash("tex_mask"), TexStroke = const_hash("tex_stroke"), - TexStencil= const_hash("tex_stencil"), + TexStencil = const_hash("tex_stencil"), StencilOffset = const_hash("stencil_offset"), StencilAlpha = const_hash("stencil_alpha"), + MixAlpha = const_hash("mix_alpha"), Wet = const_hash("wet"), Lock = const_hash("lock"), Col = const_hash("col"),