diff --git a/src/app_layout.cpp b/src/app_layout.cpp index b5d25af..59ed670 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -203,29 +203,34 @@ void App::init_sidebar() layers->on_layer_opacity_changed = [this](Node*, int idx, float value) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_opacity = value; canvas->m_canvas->m_unsaved = true; + canvas->m_canvas->draw_merge(); title_update(); }; layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_visible = visible; canvas->m_canvas->m_unsaved = true; + canvas->m_canvas->draw_merge(); title_update(); }; layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_alpha_locked = locked; canvas->m_canvas->m_unsaved = true; + canvas->m_canvas->draw_merge(); title_update(); }; layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_blend_mode = mode; canvas->m_canvas->m_unsaved = true; + canvas->m_canvas->draw_merge(); title_update(); }; layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) { canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]]->m_hightlight = highlight; + canvas->m_canvas->draw_merge(); }; if (auto* button = layout[main_id]->find("btn-stroke")) { diff --git a/src/canvas.cpp b/src/canvas.cpp index 466cea0..c9f4d0c 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -143,11 +143,13 @@ void Canvas::clear(const glm::vec4& c/*={0,0,0,1}*/) snap_history({ 0, 1, 2, 3, 4, 5 }); m_layers[m_current_layer_idx]->clear(c); m_unsaved = true; + draw_merge(); } void Canvas::clear_all() { for (auto& l : m_layers) l->clear({0, 0, 0, 0}); + draw_merge(); } void Canvas::snap_history(const std::vector& planes) { @@ -196,9 +198,9 @@ void Canvas::stroke_end() } else { + m_show_tmp = false; stroke_commit(); m_current_stroke = nullptr; - m_show_tmp = false; } } void Canvas::stroke_cancel() @@ -465,6 +467,7 @@ void Canvas::stroke_draw() } m_dirty = true; + std::array merge_faces; GLint vp[4]; GLfloat cc[4]; @@ -538,6 +541,7 @@ void Canvas::stroke_draw() if (P.size() < 3) continue; m_dirty_face[i] = true; + merge_faces[i] = true; m_tmp[i].bindFramebuffer(); auto rect = stroke_draw_samples(i, P); m_tmp[i].unbindFramebuffer(); @@ -594,11 +598,13 @@ void Canvas::stroke_draw() if (m_commit_delayed) { - stroke_commit(); - m_current_stroke = nullptr; m_show_tmp = false; m_commit_delayed = false; + stroke_commit(); + m_current_stroke = nullptr; } + + draw_merge(merge_faces); } bool Canvas::point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, glm::vec3& hit_pos, glm::vec2& fb_pos, glm::vec3& hit_normal, int& out_plane_id) @@ -864,7 +870,248 @@ void Canvas::stroke_commit() action->m_canvas = this; //action->m_stroke = std::move(m_current_stroke); ActionManager::add(action); + + draw_merge(); } + +void Canvas::draw_merge(std::array faces /*= SIXPLETTE(false)*/) +{ + gl_state gl; + gl.save(); + glViewport(0, 0, m_width, m_height); + auto ortho = glm::ortho(-0.5f, 0.5f, -0.5f, 0.5f, -1.f, 1.f); + const auto& b = m_current_stroke->m_brush; + + // check if any layer use blend, otherwise draw directly on main framebuffer + bool use_blend = false; + for (size_t i = 0; i < m_order.size(); i++) + { + auto layer_index = m_order[i]; + use_blend |= m_layers[layer_index]->m_blend_mode != 0; + } + + // if not using shader blend, use gl rasterizer blend + glDisable(GL_DEPTH_TEST); + + for (int plane_index = 0; plane_index < 6; plane_index++) + { + if (!faces[plane_index]) + continue; + + m_layers_merge.m_rtt[plane_index].bindFramebuffer(); + + if (use_blend) + { + glDisable(GL_BLEND); + m_layers_merge.m_rtt[plane_index].clear(); + } + else + { + ShaderManager::use(kShader::Checkerboard); + ShaderManager::u_int(kShaderUniform::Colorize, false); + ShaderManager::u_mat4(kShaderUniform::MVP, ortho); + m_plane.draw_fill(); + glEnable(GL_BLEND); + } + + for (int layer_index : m_order) + { + if (!(m_show_tmp && m_current_layer_idx == layer_index) && + (!m_layers[layer_index]->m_visible || + m_layers[layer_index]->m_opacity == .0f || + !m_layers[layer_index]->m_dirty_face[plane_index])) + continue; + + if (use_blend) + { + m_merge_rtt.bindFramebuffer(); + m_merge_rtt.clear(); + } + + if (m_current_stroke && m_current_mode == kCanvasMode::Erase && m_show_tmp && m_current_layer_idx == layer_index) + { + m_sampler.bind(0); + ShaderManager::use(kShader::CompErase); + 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_box) / zoom); + ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity); + //ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index]->m_alpha_locked); + ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); + ShaderManager::u_mat4(kShaderUniform::MVP, ortho); + glActiveTexture(GL_TEXTURE0); + m_layers[layer_index]->m_rtt[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_tmp[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE2); + m_smask.m_rtt[plane_index].bindTexture(); + m_plane.draw_fill(); + m_smask.m_rtt[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE1); + m_tmp[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE0); + m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); + } + else if (m_current_stroke && m_show_tmp && m_current_layer_idx == layer_index) + { + m_sampler.bind(0); + + 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; + + ShaderManager::use(kShader::CompDraw); + 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_vec2(kShaderUniform::Resolution, Canvas::I->m_size); + ShaderManager::u_int(kShaderUniform::TexPattern, 4); + ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity); + ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index]->m_alpha_locked); + ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); + ShaderManager::u_int(kShaderUniform::UseFragcoord, false); + ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); + ShaderManager::u_mat4(kShaderUniform::MVP, ortho); + 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); + ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale); + ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert); + ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness); + ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast); + ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth); + ShaderManager::u_int(kShaderUniform::PatternBlendMode, b->m_pattern_blend_mode); + ShaderManager::u_vec2(kShaderUniform::PatternOffset, Canvas::I->m_pattern_offset); + ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity); + + glActiveTexture(GL_TEXTURE0); + m_layers[layer_index]->m_rtt[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_tmp[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE2); + m_smask.m_rtt[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE3); + if (b->m_dual_enabled) + m_tmp_dual[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE4); + b->m_pattern_texture ? + b->m_pattern_texture->bind() : + glBindTexture(GL_TEXTURE_2D, 0); + m_plane.draw_fill(); + glActiveTexture(GL_TEXTURE3); + if (b->m_dual_enabled) + m_tmp_dual[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE2); + m_smask.m_rtt[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE1); + m_tmp[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE0); + m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); + } + else + { + m_sampler.bind(0); + m_sampler_linear.bind(1); + ShaderManager::use(kShader::TextureAlphaSep); + 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(); + } + + if (use_blend) + { + m_merge_rtt.unbindFramebuffer(); + } + + // draw the blended + 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); + + glActiveTexture(GL_TEXTURE0); + m_merge_rtt.bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_merge_rtt.bindTexture(); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + m_merge_tex.bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + } + + m_plane.draw_fill(); + + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + m_merge_tex.unbind(); + } + glActiveTexture(GL_TEXTURE1); + m_merge_rtt.unbindTexture(); + glActiveTexture(GL_TEXTURE0); + m_merge_rtt.unbindTexture(); + } + } + + glActiveTexture(GL_TEXTURE2); + m_merge_tex.bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + + // draw the grid behind the layers using a temporary copy + if (use_blend) + { + glEnable(GL_BLEND); + + //draw the grid + ShaderManager::use(kShader::Checkerboard); + ShaderManager::u_int(kShaderUniform::Colorize, false); + ShaderManager::u_mat4(kShaderUniform::MVP, ortho); + m_plane.draw_fill(); + + // draw the layers + m_sampler.bind(0); + glActiveTexture(GL_TEXTURE0); + m_merge_tex.bind(); + ShaderManager::use(kShader::Texture); + ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_mat4(kShaderUniform::MVP, ortho); + m_plane.draw_fill(); + m_merge_tex.unbind(); + } + + m_layers_merge.m_rtt[plane_index].unbindFramebuffer(); + } + + gl.restore(); +} + void Canvas::stroke_update(glm::vec3 point, float pressure) { m_current_stroke->add_point(point, pressure); @@ -876,11 +1123,11 @@ void Canvas::stroke_start(glm::vec3 point, float pressure) // need to commit this now before starting a new stroke if (m_current_stroke && m_commit_delayed) { + m_show_tmp = false; + m_commit_delayed = false; stroke_commit(); m_current_stroke = nullptr; m_dual_stroke = nullptr; - m_show_tmp = false; - m_commit_delayed = false; } m_pattern_offset = m_current_brush->m_pattern_rand_offset ? @@ -947,6 +1194,7 @@ void Canvas::layer_add(std::string name) m_layers.back()->create(m_width, m_height, name); m_order.push_back(idx); m_current_layer_idx = idx; + draw_merge(); } void Canvas::layer_remove(int idx) // m_order index { @@ -958,10 +1206,12 @@ void Canvas::layer_remove(int idx) // m_order index m_layers.erase(m_layers.begin() + n); m_order.erase(m_order.begin() + idx); m_current_layer_idx = m_order[std::min((int)m_layers.size() - 1, idx)]; + draw_merge(); } void Canvas::layer_order(int idx, int pos) // m_order index { std::swap(m_order[idx], m_order[pos]); + draw_merge(); } void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index { @@ -1054,6 +1304,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index action->m_stroke = std::move(m_current_stroke); ActionManager::add(action); */ + draw_merge(); } void Canvas::resize(int width, int height) { @@ -1073,9 +1324,12 @@ void Canvas::resize(int width, int height) #endif m_tex2[i].create(width, height, GL_RGBA8); } + m_layers_merge.resize(width, height); for (auto& l : m_layers) l->resize(width, height); m_smask.create(width, height, "mask"); + m_merge_rtt.create(width, height); + m_merge_tex.create(width, height); m_unsaved = true; } @@ -1088,10 +1342,13 @@ void Canvas::destroy() m_tex[i].destroy(); m_tex2[i].destroy(); } + m_layers_merge.destroy(); for (auto& l : m_layers) l->destroy(); m_smask.destroy(); m_mixer.destroy(); + m_merge_rtt.destroy(); + m_merge_tex.destroy(); } bool Canvas::create(int width, int height) @@ -1105,15 +1362,18 @@ bool Canvas::create(int width, int height) m_tmp[i].create(width, height, -1, GL_RGBA8); m_tmp_dual[i].create(width, height, -1, GL_RGBA8); m_tex[i].create(width, height, GL_RGBA8); - m_sampler_brush.create(); #else m_tmp[i].create(width, height, -1, GL_RGBA32F); m_tmp_dual[i].create(width, height, -1, GL_RGBA32F); m_tex[i].create(width, height, GL_RGBA32F); - m_sampler_brush.create(GL_LINEAR, GL_CLAMP_TO_BORDER); #endif m_tex2[i].create(width, height, GL_RGBA8); } +#if defined(__IOS__) || defined(__ANDROID__) + m_sampler_brush.create(); +#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); @@ -1129,11 +1389,15 @@ bool Canvas::create(int width, int height) m_brush_shape.create(); m_mesh.create(); m_brush_mix.create(8, 8); + m_layers_merge.create(width, height, "merge"); for (auto& l : m_layers) l->create(width, height, ""); m_smask.create(width, height, "mask"); //m_smask.clear({1, 1, 1, 1}); + m_merge_rtt.create(width, height); + m_merge_tex.create(width, height); m_unsaved = true; + draw_merge(); return true; } @@ -2198,6 +2462,17 @@ bool Canvas::project_open_thread(std::string file_path) fclose(fp); LOG("project restore from %s", file_path.c_str()); + m_current_layer_idx = 0; + m_current_stroke = nullptr; + m_dual_stroke = nullptr; + m_show_tmp = false; + m_smask_active = false; + m_smask_mode = 0; + m_dirty = false; + m_commit_delayed = false; + m_dirty_stroke = false; + memset(m_dirty_face, 0, sizeof(bool) * 6); + memset(m_pick_ready, 0, sizeof(bool) * 6); m_unsaved = false; m_newdoc = false; if (App::I.layout.m_loaded) @@ -2205,11 +2480,18 @@ bool Canvas::project_open_thread(std::string file_path) App::I.async_start(); pb->destroy(); gl.save(); + draw_merge(); App::I.async_update(); gl.restore(); App::I.title_update(); App::I.async_end(); } + else + { + App::I.async_start(); + draw_merge(); + App::I.async_end(); + } return true; } @@ -2393,6 +2675,8 @@ void Canvas::draw_objects_direct(std::function observer, Layer& layer) @@ -2483,6 +2767,8 @@ void Canvas::draw_objects(std::function observer) @@ -2794,6 +3080,7 @@ void ActionStroke::undo() LOG("undo invalid box size (%d, %d)", (int)box_sz.x, (int)box_sz.y); } } + m_canvas->draw_merge(); } size_t ActionStroke::memory() diff --git a/src/canvas.h b/src/canvas.h index f117c22..c90e7d8 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -167,6 +167,7 @@ public: std::unique_ptr m_dual_stroke; bool m_show_tmp = false; std::vector> m_layers; + Layer m_layers_merge; std::vector m_order; std::vector m_plane_shape[6]; // screen space projection of the plane glm::mat4 m_plane_unproject[6] = SIXPLETTE(glm::mat4(1)); @@ -184,6 +185,8 @@ public: Texture2D m_brush_mix; Texture2D m_tex[6]; Texture2D m_tex2[6]; + RTT m_merge_rtt; + Texture2D m_merge_tex; bool m_pick_ready[6]; std::unique_ptr m_pick_data[6] = SIXPLETTE(nullptr); static glm::vec3 m_plane_origin[6]; @@ -247,6 +250,7 @@ public: void stroke_end(); void stroke_cancel(); void stroke_commit(); + void draw_merge(std::array faces = SIXPLETTE(true)); void clear(const glm::vec4& color = { 1, 1, 1, 0 }); void clear_all(); void pick_start(); diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 808dee8..2a992f4 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -81,10 +81,6 @@ void NodeCanvas::draw() m_canvas->m_box = box; m_canvas->m_vp = c; - // auto plane_mvp = proj * camera * transform * - // glm::scale(glm::vec3(sz, 1)); - - m_sampler.bind(0); m_sampler.bind(1); m_sampler.bind(2); @@ -114,21 +110,11 @@ void NodeCanvas::draw() m_canvas->m_plane_shape[plane_index] = m_canvas->face_to_shape2D(plane_index); } - // check if any layer use blend, otherwise draw directly on main framebuffer - bool use_blend = false; - for (size_t i = 0; i < m_canvas->m_order.size(); i++) - { - auto layer_index = m_canvas->m_order[i]; - use_blend |= m_canvas->m_layers[layer_index]->m_blend_mode != 0; - } + bool draw_merged = !(m_canvas->m_current_mode == kCanvasMode::Camera); - if (use_blend) - { - m_cache_rtt.bindFramebuffer(); - m_cache_rtt.clear({ 1, 1, 1, 0 }); - } - else + if (draw_merged) { + glDisable(GL_BLEND); // draw the grid for (int plane_index = 0; plane_index < 6; plane_index++) { @@ -141,243 +127,303 @@ void NodeCanvas::draw() ShaderManager::u_int(kShaderUniform::Colorize, false); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); m_face_plane.draw_fill(); - } - } - // if not using shader blend, use gl rasterizer blend - 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]; - for (int plane_index = 0; plane_index < 6; plane_index++) - { - if (!(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) && - (!m_canvas->m_layers[layer_index]->m_visible || - m_canvas->m_layers[layer_index]->m_opacity == .0f || - !m_canvas->m_layers[layer_index]->m_dirty_face[plane_index])) - continue; - - if (use_blend) - { - m_blender_rtt.bindFramebuffer(); - m_blender_rtt.clear(); - } - - int z = (int)(m_canvas->m_order.size() - i); - auto plane_mvp_z = proj * camera * - glm::scale(glm::vec3(z + 1)) * - glm::eulerAngleYXZ(yaw, pitch, roll) * - m_canvas->m_plane_transform[plane_index] * - glm::translate(glm::vec3(0, 0, -1)); - - 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); - ShaderManager::use(kShader::CompErase); - 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::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_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_tmp[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE2); - m_canvas->m_smask.m_rtt[plane_index].bindTexture(); - m_face_plane.draw_fill(); - m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE1); - m_canvas->m_tmp[plane_index].unbindTexture(); - 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) - { - m_sampler.bind(0); - - 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; - - ShaderManager::use(kShader::CompDraw); - 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_vec2(kShaderUniform::Resolution, Canvas::I->m_size); - ShaderManager::u_int(kShaderUniform::TexPattern, 4); - 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::UseFragcoord, false); - ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); - ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); - 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); - ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale); - ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert); - ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness); - ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast); - ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth); - ShaderManager::u_int(kShaderUniform::PatternBlendMode, b->m_pattern_blend_mode); - ShaderManager::u_vec2(kShaderUniform::PatternOffset, Canvas::I->m_pattern_offset); - ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity); - - glActiveTexture(GL_TEXTURE0); - m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_canvas->m_tmp[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE2); - m_canvas->m_smask.m_rtt[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE3); - if (b->m_dual_enabled) - m_canvas->m_tmp_dual[plane_index].bindTexture(); - glActiveTexture(GL_TEXTURE4); - b->m_pattern_texture ? - b->m_pattern_texture->bind() : - glBindTexture(GL_TEXTURE_2D, 0); - m_face_plane.draw_fill(); - 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(); - glActiveTexture(GL_TEXTURE1); - m_canvas->m_tmp[plane_index].unbindTexture(); - glActiveTexture(GL_TEXTURE0); - m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); - } - else - { - m_sampler.bind(0); - m_sampler_linear.bind(1); - ShaderManager::use(kShader::TextureAlphaSep); - 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(); - } - - if (use_blend) - { - m_blender_rtt.unbindFramebuffer(); - } - - // draw the blended - 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); - ShaderManager::u_float(kShaderUniform::Alpha, 1.f); - ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-1, 1, -1, 1)); - - glActiveTexture(GL_TEXTURE0); - m_blender_rtt.bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_blender_rtt.bindTexture(); - if (!ShaderManager::ext_framebuffer_fetch) - { - glActiveTexture(GL_TEXTURE2); - m_blender_bg.bind(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - m_blender_bg.size().x, m_blender_bg.size().y); - } - - m_face_plane.draw_fill(); - - if (!ShaderManager::ext_framebuffer_fetch) - { - glActiveTexture(GL_TEXTURE2); - m_blender_bg.unbind(); - } - glActiveTexture(GL_TEXTURE1); - m_blender_rtt.unbindTexture(); - glActiveTexture(GL_TEXTURE0); - m_blender_rtt.unbindTexture(); - } - -#ifdef _DEBUG - // draw dirty area - { - auto bb = m_canvas->m_layers[layer_index]->m_dirty_box[plane_index] / (float)m_canvas->m_layers[layer_index]->w; - glm::vec2 bbmin = xy(bb); - glm::vec2 bbsz = zw(bb) - xy(bb); - ShaderManager::use(kShader::Color); - ShaderManager::u_vec4(kShaderUniform::Col, { 1, 0, 0, 1 }); - ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z - * glm::translate(glm::vec3(bbmin * 2.f, 0)) - * glm::translate(glm::vec3(-1, -1, 0)) - * glm::scale(glm::vec3(bbsz, 1)) - * glm::translate(glm::vec3(1, 1, 0)) - ); - m_face_plane.draw_stroke(); - } -#endif - } - } - if (use_blend) - { - m_cache_rtt.unbindFramebuffer(); - } - - // draw the grid behind the layers using a temporary copy - if (use_blend) - { - glEnable(GL_BLEND); - - //draw the grid - for (int plane_index = 0; plane_index < 6; plane_index++) - { - auto plane_mvp = proj * camera * - glm::scale(glm::vec3(m_canvas->m_order.size() + 500.f)) * + int z = 1; + auto plane_mvp_z = proj * camera * + //glm::scale(glm::vec3(z + 1)) * + //glm::eulerAngleYXZ(yaw, pitch, roll) * m_canvas->m_plane_transform[plane_index] * - glm::translate(glm::vec3(0, 0, -1.f)); + glm::translate(glm::vec3(0, 0, -1)); + + m_sampler.bind(0); + m_sampler_linear.bind(1); + ShaderManager::use(kShader::TextureAlphaSep); + 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(); - ShaderManager::use(kShader::Checkerboard); - ShaderManager::u_int(kShaderUniform::Colorize, false); - ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); 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(); + } + } + else + { + // check if any layer use blend, otherwise draw directly on main framebuffer + bool use_blend = false; + for (size_t i = 0; i < m_canvas->m_order.size(); i++) + { + auto layer_index = m_canvas->m_order[i]; + use_blend |= m_canvas->m_layers[layer_index]->m_blend_mode != 0; } - // draw the layers - m_sampler.bind(0); - glActiveTexture(GL_TEXTURE0); - m_cache_rtt.bindTexture(); - ShaderManager::use(kShader::Texture); - ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-1, 1, -1, 1)); - m_face_plane.draw_fill(); - m_cache_rtt.unbindTexture(); + if (use_blend) + { + m_cache_rtt.bindFramebuffer(); + m_cache_rtt.clear({ 1, 1, 1, 0 }); + } + else + { + // draw the grid + for (int plane_index = 0; plane_index < 6; plane_index++) + { + auto plane_mvp = proj * camera * + glm::scale(glm::vec3(m_canvas->m_order.size() + 500)) * + m_canvas->m_plane_transform[plane_index] * + glm::translate(glm::vec3(0, 0, -1)); + + ShaderManager::use(kShader::Checkerboard); + ShaderManager::u_int(kShaderUniform::Colorize, false); + ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); + m_face_plane.draw_fill(); + } + } + + // if not using shader blend, use gl rasterizer blend + 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]; + for (int plane_index = 0; plane_index < 6; plane_index++) + { + if (!(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) && + (!m_canvas->m_layers[layer_index]->m_visible || + m_canvas->m_layers[layer_index]->m_opacity == .0f || + !m_canvas->m_layers[layer_index]->m_dirty_face[plane_index])) + continue; + + if (use_blend) + { + m_blender_rtt.bindFramebuffer(); + m_blender_rtt.clear(); + } + + int z = (int)(m_canvas->m_order.size() - i); + auto plane_mvp_z = proj * camera * + glm::scale(glm::vec3(z + 1)) * + glm::eulerAngleYXZ(yaw, pitch, roll) * + m_canvas->m_plane_transform[plane_index] * + glm::translate(glm::vec3(0, 0, -1)); + + 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); + ShaderManager::use(kShader::CompErase); + 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::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_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_tmp[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE2); + m_canvas->m_smask.m_rtt[plane_index].bindTexture(); + m_face_plane.draw_fill(); + m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE1); + m_canvas->m_tmp[plane_index].unbindTexture(); + 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) + { + m_sampler.bind(0); + + 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; + + ShaderManager::use(kShader::CompDraw); + 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_vec2(kShaderUniform::Resolution, Canvas::I->m_size); + ShaderManager::u_int(kShaderUniform::TexPattern, 4); + 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::UseFragcoord, false); + ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); + ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); + 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); + ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale); + ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert); + ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness); + ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast); + ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth); + ShaderManager::u_int(kShaderUniform::PatternBlendMode, b->m_pattern_blend_mode); + ShaderManager::u_vec2(kShaderUniform::PatternOffset, Canvas::I->m_pattern_offset); + ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity); + + glActiveTexture(GL_TEXTURE0); + m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_canvas->m_tmp[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE2); + m_canvas->m_smask.m_rtt[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE3); + if (b->m_dual_enabled) + m_canvas->m_tmp_dual[plane_index].bindTexture(); + glActiveTexture(GL_TEXTURE4); + b->m_pattern_texture ? + b->m_pattern_texture->bind() : + glBindTexture(GL_TEXTURE_2D, 0); + m_face_plane.draw_fill(); + 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(); + glActiveTexture(GL_TEXTURE1); + m_canvas->m_tmp[plane_index].unbindTexture(); + glActiveTexture(GL_TEXTURE0); + m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture(); + } + else + { + m_sampler.bind(0); + m_sampler_linear.bind(1); + ShaderManager::use(kShader::TextureAlphaSep); + 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(); + } + + if (use_blend) + { + m_blender_rtt.unbindFramebuffer(); + } + + // draw the blended + 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); + ShaderManager::u_float(kShaderUniform::Alpha, 1.f); + ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-1, 1, -1, 1)); + + glActiveTexture(GL_TEXTURE0); + m_blender_rtt.bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_blender_rtt.bindTexture(); + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + m_blender_bg.bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, + m_blender_bg.size().x, m_blender_bg.size().y); + } + + m_face_plane.draw_fill(); + + if (!ShaderManager::ext_framebuffer_fetch) + { + glActiveTexture(GL_TEXTURE2); + m_blender_bg.unbind(); + } + glActiveTexture(GL_TEXTURE1); + m_blender_rtt.unbindTexture(); + glActiveTexture(GL_TEXTURE0); + m_blender_rtt.unbindTexture(); + } + + #ifdef _DEBUG + // draw dirty area + { + auto bb = m_canvas->m_layers[layer_index]->m_dirty_box[plane_index] / (float)m_canvas->m_layers[layer_index]->w; + glm::vec2 bbmin = xy(bb); + glm::vec2 bbsz = zw(bb) - xy(bb); + ShaderManager::use(kShader::Color); + ShaderManager::u_vec4(kShaderUniform::Col, { 1, 0, 0, 1 }); + ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z + * glm::translate(glm::vec3(bbmin * 2.f, 0)) + * glm::translate(glm::vec3(-1, -1, 0)) + * glm::scale(glm::vec3(bbsz, 1)) + * glm::translate(glm::vec3(1, 1, 0)) + ); + m_face_plane.draw_stroke(); + } + #endif + } + } + if (use_blend) + { + m_cache_rtt.unbindFramebuffer(); + } + + // draw the grid behind the layers using a temporary copy + if (use_blend) + { + glEnable(GL_BLEND); + + //draw the grid + for (int plane_index = 0; plane_index < 6; plane_index++) + { + auto plane_mvp = proj * camera * + glm::scale(glm::vec3(m_canvas->m_order.size() + 500.f)) * + m_canvas->m_plane_transform[plane_index] * + glm::translate(glm::vec3(0, 0, -1.f)); + + ShaderManager::use(kShader::Checkerboard); + ShaderManager::u_int(kShaderUniform::Colorize, false); + ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); + m_face_plane.draw_fill(); + } + + // draw the layers + m_sampler.bind(0); + glActiveTexture(GL_TEXTURE0); + m_cache_rtt.bindTexture(); + ShaderManager::use(kShader::Texture); + ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-1, 1, -1, 1)); + m_face_plane.draw_fill(); + m_cache_rtt.unbindTexture(); + } } glDisable(GL_DEPTH_TEST);