From 85d9c057f8f3be450f11817112470d868df937ee Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 21 Jul 2019 00:27:34 +0200 Subject: [PATCH] fix color bleeding --- PanoPainter.vcxproj | 3 +- PanoPainter.vcxproj.filters | 9 +- data/shaders/comp-draw.glsl | 13 +- data/shaders/stroke-dilate.glsl | 42 +++++ data/shaders/stroke-pad.glsl | 37 ++++ data/shaders/stroke.glsl | 11 +- data/shaders/texture-alpha-sep.glsl | 34 ---- data/shaders/texture-blend.glsl | 3 +- src/app_shaders.cpp | 6 +- src/app_vr.cpp | 10 +- src/canvas.cpp | 251 +++++++++++++++------------- src/canvas.h | 2 - src/canvas_modes.cpp | 4 +- src/node_canvas.cpp | 50 ++---- src/shader.h | 4 +- 15 files changed, 258 insertions(+), 221 deletions(-) create mode 100644 data/shaders/stroke-dilate.glsl create mode 100644 data/shaders/stroke-pad.glsl delete mode 100644 data/shaders/texture-alpha-sep.glsl diff --git a/PanoPainter.vcxproj b/PanoPainter.vcxproj index d138649..667d395 100644 --- a/PanoPainter.vcxproj +++ b/PanoPainter.vcxproj @@ -550,10 +550,11 @@ + + - diff --git a/PanoPainter.vcxproj.filters b/PanoPainter.vcxproj.filters index a2c7f91..5e0ede5 100644 --- a/PanoPainter.vcxproj.filters +++ b/PanoPainter.vcxproj.filters @@ -679,9 +679,6 @@ shaders - - shaders - shaders @@ -718,6 +715,12 @@ shaders + + shaders + + + shaders + diff --git a/data/shaders/comp-draw.glsl b/data/shaders/comp-draw.glsl index e13d2c6..d9c34ef 100644 --- a/data/shaders/comp-draw.glsl +++ b/data/shaders/comp-draw.glsl @@ -52,12 +52,15 @@ void main() highp vec2 uv_base = use_fragcoord ? (gl_FragCoord.st / resolution) : uv; highp vec4 base = texture(tex, uv_base); highp vec4 stroke = texture(tex_stroke, uv); + + if (base.a == 0.0) + base.rgb = stroke.rgb; - if (stroke.a == 0.0) - { - frag = base * vec4(1.0, 1.0, 1.0, alpha); - return; - } + // if (stroke.a == 0.0) + // { + // frag = base * vec4(1.0, 1.0, 1.0, alpha); + // return; + // } if (use_pattern) { diff --git a/data/shaders/stroke-dilate.glsl b/data/shaders/stroke-dilate.glsl new file mode 100644 index 0000000..4ea702a --- /dev/null +++ b/data/shaders/stroke-dilate.glsl @@ -0,0 +1,42 @@ +[[vertex]] + +uniform mat4 mvp; + +in vec4 pos; +in vec2 uvs; +out vec2 uv; + +void main() +{ + gl_Position = mvp * vec4(pos.xy, 0.0, 1.0); + uv = uvs; +} + +[[fragment]] + +uniform sampler2D tex_bg; + +in highp vec2 uv; +out highp vec4 frag; + +void main() +{ + highp vec4 bg = texture(tex_bg, uv); + if (bg.a == 0.0) + { + highp vec4 sum = vec4(0.0); + for (int y = -1; y <= 1; y++) + { + for (int x = -1; x <= 1; x++) + { + highp vec4 c = textureOffset(tex_bg, uv, ivec2(x, y)); + sum += vec4(c.rgb * c.a, c.a); + } + } + frag = sum.a > 0.0 ? vec4(sum.rgb / sum.a, 0.0) : bg; + } + else + { + frag = bg; + } +} diff --git a/data/shaders/stroke-pad.glsl b/data/shaders/stroke-pad.glsl new file mode 100644 index 0000000..6a5a13c --- /dev/null +++ b/data/shaders/stroke-pad.glsl @@ -0,0 +1,37 @@ +[[vertex]] + +in vec4 pos; +out vec2 uv; + +void main() +{ + gl_Position = pos; + uv = pos.xy * 0.5 + 0.5; +} + +[[fragment]] + +#include "include/ext-fb-fetch.glsl" + +uniform sampler2D tex_bg; +uniform mediump vec4 col; + +in highp vec2 uv; +#if defined(GL_EXT_shader_framebuffer_fetch) + inout highp vec4 frag; +#else + out highp vec4 frag; +#endif + +void main() +{ + // sample from the background +#if defined(GL_EXT_shader_framebuffer_fetch) + highp vec4 bg = frag; +#elif defined(GL_ARM_shader_framebuffer_fetch) + highp vec4 bg = gl_LastFragColorARM; +#else + highp vec4 bg = texture(tex_bg, uv); +#endif + frag = bg.a == 0.0 ? vec4(col.rgb, 0.0) : bg; +} diff --git a/data/shaders/stroke.glsl b/data/shaders/stroke.glsl index 6d8ac8c..d9c6a29 100644 --- a/data/shaders/stroke.glsl +++ b/data/shaders/stroke.glsl @@ -61,8 +61,8 @@ void main() highp vec4 fg = vec4(col.rgb, brush_alpha); // early discard - if (fg.a == 0.0) - discard; + // if (fg.a == 0.0) + // discard; if (use_pattern) { @@ -86,11 +86,14 @@ void main() highp vec4 bg = texture(tex_bg, uv2); #endif + if (bg.a == 0.0) + bg.rgb = col.rgb; + fg.a *= 1.0-rand(uv2+uv)*noise; // no need to go further - if (fg.a <= 0.0) - discard; + // if (fg.a <= 0.0) + // discard; if (mix_alpha > 0.0) { diff --git a/data/shaders/texture-alpha-sep.glsl b/data/shaders/texture-alpha-sep.glsl deleted file mode 100644 index 285e90d..0000000 --- a/data/shaders/texture-alpha-sep.glsl +++ /dev/null @@ -1,34 +0,0 @@ -[[vertex]] - -uniform mat4 mvp; - -in vec4 pos; -in vec2 uvs; -out vec2 uv; - -void main() -{ - uv = uvs; - gl_Position = mvp * vec4(pos.xyz, 1.0); -} - -[[fragment]] - -uniform sampler2D tex; -uniform sampler2D tex_alpha; -uniform sampler2D tex_bg; -uniform highp float alpha; -uniform bool highlight; - -in highp vec2 uv; -out highp vec4 frag; - -void main() -{ - highp vec3 rgb = texture(tex, uv).rgb; - highp float a = texture(tex_alpha, uv).a; - highp vec4 c = vec4(rgb, a); - frag = highlight ? - vec4(clamp(vec3(0.3) + c.rgb, vec3(0.0), vec3(1.0)), c.a) : - texture(tex, uv) * vec4(1.0, 1.0, 1.0, alpha); -} diff --git a/data/shaders/texture-blend.glsl b/data/shaders/texture-blend.glsl index e05c4ea..74b8e6d 100644 --- a/data/shaders/texture-blend.glsl +++ b/data/shaders/texture-blend.glsl @@ -18,7 +18,6 @@ void main() #include "include/blend.glsl" uniform sampler2D tex; -uniform sampler2D tex_alpha; uniform sampler2D tex_bg; uniform highp float alpha; uniform int blend_mode; @@ -41,7 +40,7 @@ void main() highp vec4 bg = texture(tex_bg, uv); #endif - highp vec4 fg = vec4(texture(tex, uv).rgb, texture(tex_alpha, uv).a); + highp vec4 fg = texture(tex, uv); if (fg.a == 0.0) { frag = bg; diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp index fe1b93a..5cf3444 100644 --- a/src/app_shaders.cpp +++ b/src/app_shaders.cpp @@ -31,8 +31,6 @@ void App::initShaders() LOG("Failed to create shader TextureAlpha"); if (!ShaderManager::load(kShader::TextureMask, "data/shaders/texture-mask.glsl")) LOG("Failed to create shader TextureMask"); - if (!ShaderManager::load(kShader::TextureAlphaSep, "data/shaders/texture-alpha-sep.glsl")) - LOG("Failed to create shader TextureAlphaSep"); if (!ShaderManager::load(kShader::TextureColorize, "data/shaders/texture-colorize.glsl")) LOG("Failed to create shader TextureColorize"); if (!ShaderManager::load(kShader::TextureBlend, "data/shaders/texture-blend.glsl")) @@ -59,6 +57,10 @@ void App::initShaders() LOG("Failed to create shader Atlas"); if (!ShaderManager::load(kShader::Stroke, "data/shaders/stroke.glsl")) LOG("Failed to create shader Stroke"); + if (!ShaderManager::load(kShader::StrokePad, "data/shaders/stroke-pad.glsl")) + LOG("Failed to create shader StrokePad"); + if (!ShaderManager::load(kShader::StrokeDilate, "data/shaders/stroke-dilate.glsl")) + LOG("Failed to create shader StrokeDilate"); if (!ShaderManager::load(kShader::Checkerboard, "data/shaders/checkerboard.glsl")) LOG("Failed to create shader Checkerboard"); if (!ShaderManager::load(kShader::Equirect, "data/shaders/equirect.glsl")) diff --git a/src/app_vr.cpp b/src/app_vr.cpp index 97bcace..f25358e 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -301,23 +301,15 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat { sampler.bind(0); sampler_linear.bind(1); - ShaderManager::use(kShader::TextureAlphaSep); + ShaderManager::use(kShader::TextureAlpha); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index]->m_opacity); ShaderManager::u_int(kShaderUniform::Highlight, canvas->m_canvas->m_layers[layer_index]->m_hightlight); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE1); - canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - m_face_plane.draw_fill(); - - glActiveTexture(GL_TEXTURE1); - canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE0); canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); } } diff --git a/src/canvas.cpp b/src/canvas.cpp index 8efcfc3..6990538 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -475,7 +475,7 @@ void Canvas::stroke_draw() glViewport(0, 0, m_width, m_height); m_sampler_brush.bind(0); - m_sampler_bg.bind(1); + m_sampler_nearest.bind(1); m_sampler_stencil.bind(2); m_sampler.bind(3); //m_sampler_linear.bind(5); @@ -517,7 +517,12 @@ void Canvas::stroke_draw() glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE3); m_mixer.bindTexture(); + auto frames = stroke_draw_compute(*m_current_stroke); + + std::array box_face = SIXPLETTE(glm::vec4(m_size, 0, 0)); + std::array box_dirty = SIXPLETTE(false); + glm::vec4 pad_color; for (auto& f : frames) { if (brush->m_tip_mix > 0.f) @@ -525,10 +530,6 @@ void Canvas::stroke_draw() stroke_draw_mix(xy(f.m_mixer_rect), zw(f.m_mixer_rect)); } - ShaderManager::use(kShader::Stroke); - ShaderManager::u_vec4(kShaderUniform::Col, f.col); - ShaderManager::u_float(kShaderUniform::Alpha, f.flow); - ShaderManager::u_float(kShaderUniform::Opacity, f.opacity); for (int i = 0; i < 6; i++) { auto& P = f.shapes[i]; @@ -536,17 +537,84 @@ void Canvas::stroke_draw() continue; m_dirty_face[i] = true; merge_faces[i] = true; + box_dirty[i] = true; + m_tmp[i].bindFramebuffer(); - auto rect = stroke_draw_samples(i, P); + + ShaderManager::use(kShader::Stroke); + ShaderManager::u_vec4(kShaderUniform::Col, f.col); + ShaderManager::u_float(kShaderUniform::Alpha, f.flow); + ShaderManager::u_float(kShaderUniform::Opacity, f.opacity); + auto box_sample = stroke_draw_samples(i, P); + m_tmp[i].unbindFramebuffer(); - m_dirty_box[i] = glm::clamp(box_union(m_dirty_box[i], rect), glm::vec4(0), glm::vec4(m_width)); + + m_dirty_box[i] = glm::clamp(box_union(m_dirty_box[i], box_sample), glm::vec4(0), glm::vec4(m_width)); + box_face[i] = box_union(box_face[i], box_sample); + // TODO: maybe average color? + pad_color = f.col; } } + glActiveTexture(GL_TEXTURE3); m_mixer.unbindTexture(); glActiveTexture(GL_TEXTURE0); brush->m_tip_texture->unbind(); + // pad stroke + // In order to mitigate color bleeding at the edge of shapes in transparent layers + // we need to fill the area around the stroke with the same color because by default + // the transparent area may have black or other undefined color. + // This step is only useful for previewing the stroke because on commit the dilate + // algorithm fixes this issue. + // NOTE: at the moment this works on the whole canvas, but it can be optimized + // to only affect the current dirty box. In this case it may be necessary to do this + // work on documents that doesn't have the padding, so on document loading. + ShaderManager::use(kShader::StrokePad); + ShaderManager::u_vec4(kShaderUniform::Col, pad_color); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE1); + ShaderManager::u_int(kShaderUniform::TexBG, 1); + } + for (int i = 0; i < 6; i++) + { + if (!box_dirty[i]) + continue; + const auto& b = box_face[i]; + glm::vec2 box_size = zw(b) - xy(b); + glm::vec2 pad = { 20, 20 }; // pixels padding + glm::vec4 pad_box = { + glm::max({0, 0}, xy(b) - pad) * 2.f / m_size - 1.f, + glm::min(m_size, zw(b) + pad) * 2.f / m_size - 1.f + }; + // B(xw)--(zw)C box + // | // | coordinates + // A(xy)--(zy)D mapping + std::array pad_quad = { + vertex_t({pad_box.x, pad_box.y}), // A + vertex_t({pad_box.x, pad_box.w}), // B + vertex_t({pad_box.z, pad_box.w}), // C + vertex_t({pad_box.x, pad_box.y}), // A + vertex_t({pad_box.z, pad_box.w}), // C + vertex_t({pad_box.z, pad_box.y}), // D + }; + m_brush_shape.update_vertices(pad_quad.data(), pad_quad.size()); + + m_tmp[i].bindFramebuffer(); + if (!ShaderManager::ext_framebuffer_fetch) + { + m_tex[i].bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, b.x, b.y, b.x, b.y, box_size.x, box_size.y); + } + m_brush_shape.draw_fill(); + m_tmp[i].unbindFramebuffer(); + } + if (!ShaderManager::ext_framebuffer_fetch) + { + glBindTexture(GL_TEXTURE_2D, 0); + } + // DRAW DUAL BRUSH if (brush->m_dual_enabled) @@ -573,18 +641,18 @@ void Canvas::stroke_draw() if (P.size() < 3) continue; m_tmp_dual[i].bindFramebuffer(); - auto rect = stroke_draw_samples(i, P); + auto box_sample = stroke_draw_samples(i, P); m_tmp_dual[i].unbindFramebuffer(); // this mode overflows the main brush boundries if (brush->m_dual_blend_mode == 0) - m_dirty_box[i] = glm::clamp(box_union(m_dirty_box[i], rect), glm::vec4(0), glm::vec4(m_width)); + m_dirty_box[i] = glm::clamp(box_union(m_dirty_box[i], box_sample), glm::vec4(0), glm::vec4(m_width)); } } } m_sampler_brush.unbind(); - m_sampler_bg.unbind(); + m_sampler_nearest.unbind(); m_sampler_stencil.unbind(); glViewport(vp[0], vp[1], vp[2], vp[3]); @@ -751,8 +819,8 @@ void Canvas::stroke_commit() glActiveTexture(GL_TEXTURE1); m_tex2[i].bind(); m_sampler.bind(0); - m_sampler_bg.bind(1); - m_sampler_mask.bind(2); + m_sampler_nearest.bind(1); + m_sampler.bind(2); m_sampler.bind(3); m_sampler_stencil.bind(4); if (m_current_mode == kCanvasMode::Erase) @@ -847,6 +915,15 @@ void Canvas::stroke_commit() // m_tex2[i].unbind(); // m_tmp[i].unbindTexture(); // } + + // Dilate borders to avoid interpolation bleeding + ShaderManager::use(kShader::StrokeDilate); + ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); + ShaderManager::u_int(kShaderUniform::TexBG, 0); + glActiveTexture(GL_TEXTURE0); + m_tex2[i].bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + m_plane.draw_fill(); m_layers[m_current_layer_idx]->m_rtt[i].unbindFramebuffer(); } @@ -1000,40 +1077,16 @@ void Canvas::draw_merge(std::array faces /*= SIXPLETTE(false)*/) else { m_sampler.bind(0); - m_sampler_linear.bind(1); - ShaderManager::use(kShader::TextureAlphaSep); + ShaderManager::use(kShader::TextureAlpha); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity); ShaderManager::u_int(kShaderUniform::Highlight, m_layers[layer_index]->m_hightlight); ShaderManager::u_mat4(kShaderUniform::MVP, ortho); glActiveTexture(GL_TEXTURE0); m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - m_plane.draw_fill(); - - glActiveTexture(GL_TEXTURE1); m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE0); - m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); -/* - m_sampler.bind(0); - m_sampler_linear.bind(1); - ShaderManager::use(kShader::TextureColorize); - ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_vec4(kShaderUniform::Col, { glm::vec3((float)layer_index / (float)m_order.size()), 1.f }); - ShaderManager::u_mat4(kShaderUniform::MVP, ortho); - - glActiveTexture(GL_TEXTURE0); - m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - - m_plane.draw_fill(); - - m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); -*/ } if (use_blend) @@ -1045,22 +1098,20 @@ void Canvas::draw_merge(std::array faces /*= SIXPLETTE(false)*/) if (use_blend) { m_sampler.bind(0); - m_sampler_linear.bind(1); - m_sampler.bind(2); ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); - if (!ShaderManager::ext_framebuffer_fetch) - ShaderManager::u_int(kShaderUniform::TexBG, 2); ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[layer_index]->m_blend_mode); ShaderManager::u_float(kShaderUniform::Alpha, 1.f); ShaderManager::u_mat4(kShaderUniform::MVP, ortho); + if (!ShaderManager::ext_framebuffer_fetch) + { + m_sampler.bind(2); + ShaderManager::u_int(kShaderUniform::TexBG, 2); + } glActiveTexture(GL_TEXTURE0); m_merge_rtt.bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_merge_rtt.bindTexture(); if (!ShaderManager::ext_framebuffer_fetch) { glActiveTexture(GL_TEXTURE2); @@ -1075,8 +1126,6 @@ void Canvas::draw_merge(std::array faces /*= SIXPLETTE(false)*/) glActiveTexture(GL_TEXTURE2); m_merge_tex.unbind(); } - glActiveTexture(GL_TEXTURE1); - m_merge_rtt.unbindTexture(); glActiveTexture(GL_TEXTURE0); m_merge_rtt.unbindTexture(); } @@ -1120,6 +1169,8 @@ void Canvas::stroke_update(glm::vec3 point, float pressure) } void Canvas::stroke_start(glm::vec3 point, float pressure) { + assert(App::I->is_render_thread()); + // need to commit this now before starting a new stroke if (m_current_stroke && m_commit_delayed) { @@ -1169,14 +1220,32 @@ void Canvas::stroke_start(glm::vec3 point, float pressure) m_dual_stroke->add_point(point, pressure); } + auto const& l = m_layers[m_current_layer_idx]; for (int i = 0; i < 6; i++) { m_dirty_box[i] = glm::vec4(m_width, m_height, 0, 0); // reset bounding box m_dirty_face[i] = false; - m_tmp[i].bindFramebuffer(); - m_tmp[i].clear({ 0, 0, 0, 0 }); - m_tmp[i].unbindFramebuffer(); + if (l->m_dirty_face[i]) + { + m_tmp[i].bindFramebuffer(); + // clear + m_tmp[i].clear(); + glActiveTexture(GL_TEXTURE1); + m_tex[i].bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, 0, 0, m_width, m_height); + + m_tmp[i].copy(l->m_rtt[i]); + m_tmp[i].clear_mask({ 0, 0, 0, 1 }); + m_tmp[i].unbindFramebuffer(); + } + else + { + m_tmp[i].bindFramebuffer(); + m_tmp[i].clear({ 0, 0, 0, 0 }); + m_tmp[i].unbindFramebuffer(); + } if (m_current_brush->m_dual_enabled) { @@ -1244,7 +1313,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index m_tex2[i].unbind(); m_sampler.bind(0); - m_sampler_bg.bind(1); + m_sampler_nearest.bind(1); { ShaderManager::use(kShader::CompDraw); ShaderManager::u_int(kShaderUniform::Tex, 0); // dest @@ -1520,13 +1589,10 @@ bool Canvas::create(int width, int height) #else m_sampler_brush.create(GL_LINEAR, GL_CLAMP_TO_BORDER); #endif - m_sampler.create(GL_NEAREST); m_sampler.create(GL_LINEAR); m_sampler_nearest.create(GL_NEAREST); m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); m_sampler_brush.set_border({ 1, 1, 1, 1 }); - 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_NEAREST, GL_REPEAT); m_sampler_linear.create(); @@ -1726,7 +1792,6 @@ void Canvas::export_equirectangular_thread(std::string file_path) ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); m_tmp[i].bindFramebuffer(); @@ -1738,10 +1803,9 @@ void Canvas::export_equirectangular_thread(std::string file_path) ShaderManager::u_int(kShaderUniform::TexBG, 2); glActiveTexture(GL_TEXTURE2); face.bind(); - m_sampler_bg.bind(2); + m_sampler_nearest.bind(2); } - m_sampler_bg.bind(0); // nearest - m_sampler_mask.bind(1); // linear + m_sampler_nearest.bind(0); // nearest for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { if (!m_layers[layer_index]->m_visible || @@ -1757,12 +1821,8 @@ void Canvas::export_equirectangular_thread(std::string file_path) ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity); glActiveTexture(GL_TEXTURE0); m_layers[layer_index]->m_rtt[i].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_layers[layer_index]->m_rtt[i].bindTexture(); m_plane.draw_fill(); m_layers[layer_index]->m_rtt[i].unbindTexture(); - glActiveTexture(GL_TEXTURE0); - m_layers[layer_index]->m_rtt[i].unbindTexture(); } if (!ShaderManager::ext_framebuffer_fetch) @@ -1776,7 +1836,7 @@ void Canvas::export_equirectangular_thread(std::string file_path) ShaderManager::use(kShader::Texture); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - m_sampler_mask.bind(0); // linear + m_sampler.bind(0); // linear glActiveTexture(GL_TEXTURE0); face.bind(); // copy the framebuffer before clearing to white @@ -1825,9 +1885,8 @@ void Canvas::export_equirectangular_thread(std::string file_path) ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); ShaderManager::u_int(kShaderUniform::Tex, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id); - m_sampler_mask.bind(0); + m_sampler.bind(0); m_plane.draw_fill(); - m_sampler_mask.unbind(); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); m_latlong.unbindFramebuffer(); }); @@ -1965,24 +2024,15 @@ void Canvas::export_depth_thread(std::string file_name) glm::scale(glm::vec3(2)); m_sampler.bind(0); - m_sampler_linear.bind(1); - ShaderManager::use(kShader::TextureAlphaSep); + ShaderManager::use(kShader::TextureAlpha); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_float(kShaderUniform::Alpha, 1.f); ShaderManager::u_int(kShaderUniform::Highlight, false); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); m_layers_merge.m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_layers_merge.m_rtt[plane_index].bindTexture(); - m_plane.draw_fill(); - - glActiveTexture(GL_TEXTURE1); - m_layers_merge.m_rtt[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE0); m_layers_merge.m_rtt[plane_index].unbindTexture(); } rtt.unbindFramebuffer(); @@ -2016,7 +2066,6 @@ void Canvas::export_depth_thread(std::string file_name) glm::scale(glm::vec3(2)); m_sampler.bind(0); - m_sampler_linear.bind(1); ShaderManager::use(kShader::TextureColorize); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_vec4(kShaderUniform::Col, { glm::vec3((float)(layer_index + 1) / (float)(m_layers.size() + 1)), 1.f }); @@ -2098,43 +2147,12 @@ void Canvas::export_layers_thread(std::string file_name) { App::I->render_task([&] { - glEnable(GL_BLEND); - glViewport(0, 0, m_width, m_height); - m_tmp[i].bindFramebuffer(); - - //if (seq == 0) - //{ - // m_tmp[i].clear({ 1, 1, 1, 1 }); - // ShaderManager::use(kShader::Checkerboard); - // ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - // m_plane.draw_fill(); - // glEnable(GL_BLEND); - //} - //else - { - m_tmp[i].clear({ 1, 1, 1, 0 }); - //glDisable(GL_BLEND); - } - - glActiveTexture(GL_TEXTURE0); - ShaderManager::use(kShader::TextureAlpha); - ShaderManager::u_float(kShaderUniform::Alpha, 1); - ShaderManager::u_int(kShaderUniform::Highlight, false); - ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - - m_sampler_mask.bind(0); - m_layers[layer_index]->m_rtt[i].bindTexture(); - m_plane.draw_fill(); - m_layers[layer_index]->m_rtt[i].unbindTexture(); - m_sampler_mask.unbind(); - - // copy result to cubemap + // copy layer to cubemap + m_layers[layer_index]->m_rtt[i].bindFramebuffer(); glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id); glCopyTexImage2D(faces[i], 0, GL_RGBA8, 0, 0, m_width, m_height, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - - m_tmp[i].unbindFramebuffer(); + m_layers[layer_index]->m_rtt[i].unbindFramebuffer(); }); progress++; @@ -2158,9 +2176,8 @@ void Canvas::export_layers_thread(std::string file_name) ShaderManager::u_int(kShaderUniform::Tex, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id); glDisable(GL_BLEND); - m_sampler_mask.bind(0); + m_sampler_linear.bind(0); m_plane.draw_fill(); - m_sampler_mask.unbind(); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); m_latlong.unbindFramebuffer(); }); @@ -2667,17 +2684,15 @@ Image Canvas::thumbnail_generate(int w, int h) ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); if (!ShaderManager::ext_framebuffer_fetch) { ShaderManager::u_int(kShaderUniform::TexBG, 2); glActiveTexture(GL_TEXTURE2); blendtex.bind(); - m_sampler_bg.bind(2); + m_sampler_nearest.bind(2); } - m_sampler_bg.bind(0); // nearest - m_sampler_mask.bind(1); // linear + m_sampler_nearest.bind(0); // nearest for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) { if (!m_layers[layer_index]->m_visible || @@ -2693,12 +2708,8 @@ Image Canvas::thumbnail_generate(int w, int h) ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity); glActiveTexture(GL_TEXTURE0); m_layers[layer_index]->m_rtt[i].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_layers[layer_index]->m_rtt[i].bindTexture(); m_face_plane.draw_fill(); m_layers[layer_index]->m_rtt[i].unbindTexture(); - glActiveTexture(GL_TEXTURE0); - m_layers[layer_index]->m_rtt[i].unbindTexture(); } if (!ShaderManager::ext_framebuffer_fetch) @@ -2722,7 +2733,7 @@ Image Canvas::thumbnail_generate(int w, int h) ShaderManager::use(kShader::Texture); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - m_sampler_mask.bind(0); // linear + m_sampler.bind(0); // linear m_plane.draw_fill(); blendtex.unbind(); diff --git a/src/canvas.h b/src/canvas.h index d196872..a3fe74c 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -134,8 +134,6 @@ public: Sampler m_sampler_nearest; Sampler m_sampler_linear; Sampler m_sampler_brush; - Sampler m_sampler_bg; - Sampler m_sampler_mask; Sampler m_sampler_stencil; Sampler m_sampler_mix; glm::mat4 m_cam_rot = glm::mat4(1); diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 94d05ef..a19b112 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -1398,8 +1398,8 @@ void CanvasModeTransform::leave(kCanvasMode next) 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); + Canvas::I->m_sampler_nearest.bind(1); + Canvas::I->m_sampler_nearest.bind(0); m_tex[j].bind(); m_shape[j].draw_fill(); m_tex[j].unbind(); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 344d02e..bc6b6a2 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -18,7 +18,7 @@ void NodeCanvas::init() m_canvas->m_node = this; m_sampler.create(); - m_sampler.set_filter(GL_LINEAR, GL_NEAREST); + //m_sampler.set_filter(GL_LINEAR, GL_NEAREST); m_sampler_nearest.create(GL_NEAREST); @@ -80,11 +80,6 @@ void NodeCanvas::draw() m_canvas->m_box = box; m_canvas->m_vp = c; - m_sampler.bind(0); - m_sampler.bind(1); - m_sampler.bind(2); - m_sampler.bind(3); - m_sampler_stencil.bind(4); auto blend = glIsEnabled(GL_BLEND); auto depth = glIsEnabled(GL_DEPTH_TEST); @@ -152,24 +147,15 @@ void NodeCanvas::draw() glm::translate(glm::vec3(0, 0, -1)); m_sampler.bind(0); - m_sampler_linear.bind(1); - ShaderManager::use(kShader::TextureAlphaSep); + ShaderManager::use(kShader::TextureAlpha); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_float(kShaderUniform::Alpha, 1.f); ShaderManager::u_int(kShaderUniform::Highlight, false); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); m_canvas->m_layers_merge.m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_canvas->m_layers_merge.m_rtt[plane_index].bindTexture(); - m_face_plane.draw_fill(); - - glActiveTexture(GL_TEXTURE1); - m_canvas->m_layers_merge.m_rtt[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE0); m_canvas->m_layers_merge.m_rtt[plane_index].unbindTexture(); } } @@ -237,6 +223,9 @@ void NodeCanvas::draw() if (m_canvas->m_current_stroke && m_canvas->m_current_mode == kCanvasMode::Erase && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) { m_sampler.bind(0); + m_sampler.bind(1); + m_sampler.bind(2); + ShaderManager::use(kShader::CompErase); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexStroke, 1); @@ -259,10 +248,14 @@ void NodeCanvas::draw() glActiveTexture(GL_TEXTURE0); m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); } - else if(m_canvas->m_current_stroke && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) + else if(!App::I->keys[(int)kKey::KeyQ] && m_canvas->m_current_stroke && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) { m_sampler.bind(0); - + m_sampler.bind(1); + m_sampler.bind(2); + m_sampler.bind(3); + m_sampler_stencil.bind(4); + glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale); if (b->m_pattern_flipx) patt_scale.x *= -1.f; if (b->m_pattern_flipy) patt_scale.y *= -1.f; @@ -318,25 +311,18 @@ void NodeCanvas::draw() } else { - m_sampler.bind(0); - m_sampler_linear.bind(1); - ShaderManager::use(kShader::TextureAlphaSep); + if (App::I->keys[(int)kKey::KeyQ]) + glDisable(GL_BLEND); + m_canvas->m_cam_fov < 20.f ? m_sampler_nearest.bind(0) : m_sampler.bind(0); + ShaderManager::use(kShader::TextureAlpha); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index]->m_opacity); ShaderManager::u_int(kShaderUniform::Highlight, m_canvas->m_layers[layer_index]->m_hightlight); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); glActiveTexture(GL_TEXTURE0); m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - m_face_plane.draw_fill(); - - glActiveTexture(GL_TEXTURE1); - m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE0); m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); } @@ -349,12 +335,10 @@ void NodeCanvas::draw() if (use_blend) { m_sampler.bind(0); - m_sampler_linear.bind(1); m_sampler.bind(2); ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_int(kShaderUniform::TexA, 1); if (!ShaderManager::ext_framebuffer_fetch) ShaderManager::u_int(kShaderUniform::TexBG, 2); ShaderManager::u_int(kShaderUniform::BlendMode, m_canvas->m_layers[layer_index]->m_blend_mode); @@ -363,8 +347,6 @@ void NodeCanvas::draw() glActiveTexture(GL_TEXTURE0); m_blender_rtt.bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_blender_rtt.bindTexture(); if (!ShaderManager::ext_framebuffer_fetch) { glActiveTexture(GL_TEXTURE2); @@ -380,8 +362,6 @@ void NodeCanvas::draw() glActiveTexture(GL_TEXTURE2); m_blender_bg.unbind(); } - glActiveTexture(GL_TEXTURE1); - m_blender_rtt.unbindTexture(); glActiveTexture(GL_TEXTURE0); m_blender_rtt.unbindTexture(); } diff --git a/src/shader.h b/src/shader.h index e9e6de7..68bde7a 100644 --- a/src/shader.h +++ b/src/shader.h @@ -7,7 +7,6 @@ enum class kShaderUniform : uint16_t { MVP = const_hash("mvp"), Tex = const_hash("tex"), - TexA = const_hash("tex_alpha"), TexFG = const_hash("tex_fg"), TexBG = const_hash("tex_bg"), TexMix = const_hash("tex_mix"), @@ -60,7 +59,6 @@ enum class kShader : uint16_t TextureMask = const_hash("texture-mask"), TextureColorize = const_hash("texture-colorize"), TextureAlpha= const_hash("texture-alpha"), - TextureAlphaSep= const_hash("texture-alpha-sep"), TextureBlend= const_hash("texture-blend"), CompErase = const_hash("comp-erase"), CompDraw = const_hash("comp-draw"), @@ -69,6 +67,8 @@ enum class kShader : uint16_t Font = const_hash("font"), Atlas = const_hash("atlas"), Stroke = const_hash("stroke"), + StrokePad = const_hash("stroke-pad"), + StrokeDilate= const_hash("stroke-dilate"), StrokePreview = const_hash("stroke-preview"), Checkerboard= const_hash("checkerboard"), Equirect = const_hash("equirect"),