diff --git a/engine/app.cpp b/engine/app.cpp index 50498ab..09ee0f7 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -159,15 +159,11 @@ void App::initShaders() static const char* shader_stroke_v = SHADER_VERSION "uniform mat4 mvp;\n" - "uniform vec2 tof;\n" - "uniform vec2 tsz;\n" "in vec4 pos;\n" "in vec2 uvs;\n" - "out vec2 uv1;\n" - "out vec2 uv2;\n" + "out vec2 uv;\n" "void main(){\n" - " uv1 = uvs;\n" - " uv2 = tof + tsz * uvs;\n" + " uv = uvs;\n" " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" "}\n"; static const char* shader_stroke_f = @@ -177,20 +173,15 @@ void App::initShaders() "uniform mediump vec4 col;\n" "uniform mediump vec2 resolution;\n" "uniform mediump float alpha;\n" - "in mediump vec2 uv1;\n" - "in mediump vec2 uv2;\n" + "in mediump vec2 uv;\n" "out mediump vec4 frag;\n" "void main(){\n" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" - " mediump float brush = ( 1.0 - texture(tex, uv1).r ) * alpha;\n" + " mediump float brush = ( 1.0 - texture(tex, uv).r ) * alpha;\n" " mediump vec4 bg = texture(tex_bg, uv2);\n" " mediump vec3 rgb = mix( bg.rgb, col.rgb, clamp( brush/(brush + bg.a), 0.0, 1.0 ) );\n" " mediump float a = bg.a + (1.0 - bg.a) * brush;\n" " frag = vec4(rgb, a);\n" - -// " mediump vec4 bg = texture(tex_bg, uv.xy);" -// " mediump float a = (1.0 - texture(tex, uv.xy).r) * alpha;" -// " frag = bg;// * vec4(col.rgb, a);\n" "}\n"; // STROKE LAYER BLEND @@ -199,25 +190,26 @@ void App::initShaders() "uniform mat4 mvp;" "in vec4 pos;" "in vec2 uvs;" - "out vec3 uv;" + "out vec2 uv;" "void main(){" - " uv = vec3(uvs, pos.w);" + " uv = uvs;" " gl_Position = mvp * vec4(pos.xyz, 1.0);" "}"; static const char* shader_stroke_layer_f = SHADER_VERSION - "uniform mediump sampler2D tex_fg;" // foreground - "uniform mediump sampler2D tex_bg;" // canvas - "uniform mediump float alpha;" // opacity - "in mediump vec3 uv;" - "out mediump vec4 frag;" - "void main(){" - " mediump vec4 c1 = texture2D(tex_fg, uv);" - " mediump vec4 c2 = texture2D(tex_bg, uv);" - " mediump float t = clamp(c1.a / (c1.a + c2.a), 0.0, 1.0));" - " mediump vec3 rgb = mix(c1.rgb, c2.rgb, t);" - " frag = vec4(rgb, c1.a + c2.a);" - "}"; + "uniform mediump sampler2D tex;\n" + "uniform mediump sampler2D tex_bg;\n" + "uniform mediump vec2 resolution;\n" + "uniform mediump float alpha;\n" + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " mediump vec4 fg = texture(tex, uv);\n" + " mediump vec4 bg = texture(tex_bg, uv);\n" + " mediump vec3 rgb = mix( bg.rgb, fg.rgb, clamp( fg.a/(fg.a + bg.a), 0.0, 1.0 ) );\n" + " mediump float a = bg.a + (1.0 - bg.a) * fg.a;\n" // this can be optimized as lerp/mix(1, fg.a, bg.a) + " frag = vec4(rgb, a);\n" + "}\n"; LOG("initializing shaders"); if (!ShaderManager::create(kShader::Texture, shader_v, shader_f)) diff --git a/engine/canvas.cpp b/engine/canvas.cpp index 4231a88..99c845b 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -25,7 +25,7 @@ void ui::Canvas::clear() void ui::Canvas::stroke_end() { m_current_stroke = nullptr; - //stroke_commit(); + stroke_commit(); m_show_tmp = false; } void ui::Canvas::stroke_draw() @@ -33,7 +33,7 @@ void ui::Canvas::stroke_draw() if (!(m_current_stroke && m_current_stroke->has_sample())) return; - m_fb.bindFramebuffer(); + m_tmp.bindFramebuffer(); GLint vp[4]; GLfloat cc[4]; @@ -48,9 +48,9 @@ void ui::Canvas::stroke_draw() auto& tex = TextureManager::get(m_brush.m_tex_id); tex.bind(); m_sampler.bind(0); - m_sampler_bg.bind(1); glActiveTexture(GL_TEXTURE1); m_tex.bind(); + m_sampler_bg.bind(1); if (m_use_instanced) { @@ -85,7 +85,7 @@ void ui::Canvas::stroke_draw() mvp * glm::vec4(glm::vec2(+.5f, +.5f), 0, 1.f), // C - top-right mvp * glm::vec4(glm::vec2(+.5f, -.5f), 0, 1.f), // D - bottom-right }; - //auto mvp_inv = glm::translate(glm::vec3(0, m_height, 0)) * glm::inverse(proj * glm::scale(glm::vec3(1, -1, 1))); + auto mvp_inv = glm::inverse(proj); glm::vec4 P2[4]{ mvp_inv * P[0], @@ -102,30 +102,17 @@ void ui::Canvas::stroke_draw() bb_max = glm::min({ m_width, m_height }, glm::max(bb_max, P2[i].xy())); } auto bb_sz = bb_max - bb_min; - // TODO: use floor and ceil to round to pixel - glm::vec2 pad(0); + glm::vec2 pad(1); glm::ivec2 tex_pos = glm::clamp(glm::floor(bb_min) - pad , { 0, 0 }, { m_width, m_height }); - glm::ivec2 tex_sz = glm::clamp(glm::floor(bb_sz ) + pad, { 0, 0 }, { m_width, m_height }); + glm::ivec2 tex_sz = glm::clamp(glm::ceil(bb_sz ) + pad*2.f, { 0, 0 }, { m_width, m_height }); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, tex_pos.x, tex_pos.y, tex_pos.x, tex_pos.y, tex_sz.x, tex_sz.y); +// glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 10, 10, 10, 10, 200, 200); -// glCopyTexSubImage2D(GL_TEXTURE_2D, 0, -// 0, 0, -// 0, 0, -// m_width, m_height); - - //glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - // (int)floor(bb_min.x), (int)floor(bb_min.y), - // (int)ceil(bb_sz.x), (int)ceil(bb_sz.y), 0); - -// auto tof = bb_min / glm::vec2(m_width, m_height); -// auto tsz = bb_sz / glm::vec2(m_width, m_height); ShaderManager::u_mat4(kShaderUniform::MVP, mvp); -// ShaderManager::u_vec2(kShaderUniform::Tof, tof); -// ShaderManager::u_vec2(kShaderUniform::Tsz, tsz); ShaderManager::u_float(kShaderUniform::Alpha, s.flow); //m_plane.update_vertices(P); m_plane.draw_fill(); @@ -139,30 +126,21 @@ void ui::Canvas::stroke_draw() tex.unbind(); glDisable(GL_BLEND); - m_fb.unbindFramebuffer(); - - -// m_fb.bindFramebuffer(); -// { -// m_tmp.bindTexture(); -// m_sampler.bind(0); -// ShaderManager::use(ui::kShader::Texture); -// ShaderManager::u_int(kShaderUniform::Tex, 0); -// ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); -// m_plane.draw_fill(); -// m_sampler.unbind(); -// m_tmp.unbindTexture(); -// } -// m_fb.unbindFramebuffer(); glViewport(vp[0], vp[1], vp[2], vp[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]); + m_tmp.unbindFramebuffer(); } void ui::Canvas::stroke_commit() { m_fb.bindFramebuffer(); + // copy to tmp2 for layer blending + m_tex2.bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + m_tex2.unbind(); + GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); @@ -170,18 +148,26 @@ void ui::Canvas::stroke_commit() glViewport(0, 0, m_width, m_height); GLboolean blend = glIsEnabled(GL_BLEND); - if (!blend) glEnable(GL_BLEND); + glDisable(GL_BLEND); m_tmp.bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_tex2.bind(); m_sampler.bind(0); - ShaderManager::use(ui::kShader::Texture); + m_sampler_bg.bind(1); + ShaderManager::use(ui::kShader::StrokeLayer); ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_int(kShaderUniform::TexBG, 1); + //ShaderManager::u_float(kShaderUniform::Alpha, 1); // TODO: if using opacity in commit, update blending to match the preview when rendering m_tmp in NodeCanvas ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); m_plane.draw_fill(); m_sampler.unbind(); + m_sampler_bg.unbind(); + m_tex2.unbind(); + glActiveTexture(GL_TEXTURE0); m_tmp.unbindTexture(); - if (!blend) glDisable(GL_BLEND); + blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND); glViewport(vp[0], vp[1], vp[2], vp[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]); @@ -200,15 +186,9 @@ void ui::Canvas::stroke_start(glm::vec2 point, float pressure, const ui::Brush& m_current_stroke = &m_strokes.back(); m_tmp.bindFramebuffer(); - m_tmp.clear({ 1, 1, 1, 0 }); + m_tmp.clear({ 0, 0, 0, 0 }); m_tmp.unbindFramebuffer(); m_show_tmp = true; - -// m_fb.bindFramebuffer(); -// m_tex.bind(); -// glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); -// m_tex.unbind(); -// m_fb.unbindFramebuffer(); } void ui::Canvas::layer_add(std::string name) { @@ -222,6 +202,7 @@ void ui::Canvas::resize(int width, int height) m_tmp.create(width, height); m_fb.create(width, height); m_tex.create(width, height); + m_tex2.create(width, height); } bool ui::Canvas::create(int width, int height) { @@ -230,8 +211,9 @@ bool ui::Canvas::create(int width, int height) m_tmp.create(width, height); m_fb.create(width, height); m_tex.create(width, height); - m_sampler.create(); - m_sampler_bg.create(); + m_tex2.create(width, height); // TODO: destroy before recreating + m_sampler.create(GL_LINEAR, GL_CLAMP_TO_EDGE); + m_sampler_bg.create(GL_NEAREST, GL_CLAMP_TO_EDGE); m_plane.create<1>(1, 1); m_mesh.create(); return true; diff --git a/engine/canvas.h b/engine/canvas.h index 7259cfb..1b3a69e 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -23,6 +23,7 @@ public: RTT m_tmp; RTT m_fb; Texture2D m_tex; + Texture2D m_tex2; Sampler m_sampler; Sampler m_sampler_bg; diff --git a/engine/layout.h b/engine/layout.h index 352e389..d3504d9 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -1851,6 +1851,7 @@ class NodeCanvas : public Node public: std::unique_ptr m_canvas; ui::Brush m_brush; + Sampler m_sampler; virtual Node* clone_instantiate() const override { return new NodeCanvas(); } virtual void init() override { @@ -1858,6 +1859,7 @@ public: m_canvas = std::make_unique(); m_canvas->create(512, 512); m_canvas->clear(); + m_sampler.create(); } virtual void draw() override { @@ -1884,12 +1886,12 @@ public: glm::scale(glm::vec3(sz * zoom, 1)) * glm::translate(glm::vec3(.5f, .5f, 0.f)); // pivot - m_canvas->m_sampler.bind(0); + m_sampler.bind(0); ui::ShaderManager::use(kShader::Texture); ui::ShaderManager::u_int(kShaderUniform::Tex, 0); ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp); - bool blend = glIsEnabled(GL_BLEND); + auto blend = glIsEnabled(GL_BLEND); glEnable(GL_BLEND); m_canvas->m_fb.bindTexture(); @@ -1906,7 +1908,7 @@ public: blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND); - m_canvas->m_sampler.unbind(); + m_sampler.unbind(); glViewport(vp[0], vp[1], vp[2], vp[3]);