From a6a020a3894fcaaf69ec72f130d13ae863953f91 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Thu, 27 Apr 2017 21:13:09 +0100 Subject: [PATCH] prepare to draw on multiple planes --- engine/brush.h | 18 --- engine/canvas.cpp | 372 ++++++++++++++++++++++++---------------------- engine/canvas.h | 67 +++++++-- engine/layout.h | 94 +++--------- 4 files changed, 270 insertions(+), 281 deletions(-) diff --git a/engine/brush.h b/engine/brush.h index dca4439..1df4d01 100644 --- a/engine/brush.h +++ b/engine/brush.h @@ -76,22 +76,4 @@ public: StrokeSample randomize_sample(const glm::vec2& pos, float pressure); }; -class Layer -{ -public: - RTT m_rtt; - bool m_visible = true; - bool m_locked = false; - float m_opacity = 1.f; - std::string m_name; - bool create(int width, int height, std::string name) - { - m_rtt.create(width, height); - m_rtt.bindFramebuffer(); - m_rtt.clear(); - m_rtt.unbindFramebuffer(); - return true; - } -}; - NS_END diff --git a/engine/canvas.cpp b/engine/canvas.cpp index 35107b7..b24e8d8 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -4,14 +4,7 @@ void ui::Canvas::clear(const glm::vec4& c/*={0,0,0,1}*/) { - GLfloat cc[4]; - m_layers[m_current_layer_idx].m_rtt.bindFramebuffer(); - glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); - glClearColor(c.r, c.g, c.b, c.a); - glClear(GL_COLOR_BUFFER_BIT); - glViewport(0, 0, m_width, m_height); - glClearColor(cc[0], cc[1], cc[2], cc[3]); - m_layers[m_current_layer_idx].m_rtt.unbindFramebuffer(); + m_layers[m_current_layer_idx].clear(c); } void ui::Canvas::stroke_end() { @@ -26,8 +19,6 @@ void ui::Canvas::stroke_draw() m_dirty = true; - m_tmp.bindFramebuffer(); - GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); @@ -42,133 +33,140 @@ void ui::Canvas::stroke_draw() auto& tex = TextureManager::get(m_brush.m_tex_id); tex.bind(); m_sampler.bind(0); - glActiveTexture(GL_TEXTURE1); - m_tex.bind(); // bg, copy of framebuffer (copied before drawing) m_sampler_bg.bind(1); - - if (m_use_instanced) + + for (int i = 0; i < 6; i++) { - glEnable(GL_BLEND); - m_mesh.shader.use(); - m_mesh.shader.u_vec4(kShaderUniform::Col, m_brush.m_tip_color); - m_mesh.shader.u_int(kShaderUniform::Tex, 0); - m_mesh.draw(samples, proj); - } - else - { - glDisable(GL_BLEND); - if (m_erase) + m_tmp[i].bindFramebuffer(); + + glActiveTexture(GL_TEXTURE1); + m_tex[i].bind(); // bg, copy of framebuffer (copied before drawing) + + if (m_use_instanced) { - ShaderManager::use(ui::kShader::StrokeErase); - //ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); + glEnable(GL_BLEND); + m_mesh.shader.use(); + m_mesh.shader.u_vec4(kShaderUniform::Col, m_brush.m_tip_color); + m_mesh.shader.u_int(kShaderUniform::Tex, 0); + m_mesh.draw(samples, proj); } else { - ShaderManager::use(ui::kShader::Stroke); - ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); - } - ShaderManager::u_int(kShaderUniform::Tex, 0); // brush - ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg - ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); - for (const auto& s : samples) - { - auto unproject = [](glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj, glm::vec3& out_origin, glm::vec3& out_dir) { - auto clip_space = glm::vec2(loc.x, vp.w - loc.y - 1.f) / vp.zw() * 2.f - 1.f; - auto inv = glm::inverse(proj * camera); - auto wp0 = inv * glm::vec4(clip_space, 0, 1); - auto wp1 = inv * glm::vec4(clip_space, .5, 1); - out_origin = (wp0 / wp0.w).xyz(); - out_dir = glm::normalize((wp1 / wp1.w).xyz() - out_origin); - }; - auto intersect = [](glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, glm::vec3 plane_normal, glm::vec3& out_hit) { - float den = glm::dot(ray_dir, plane_normal); - if (den == 0) - return false; // no intersection - float num = glm::dot(plane_origin - ray_origin, plane_normal); - float t = num / den; - if (t > 0) - out_hit = ray_origin + ray_dir * t; - else - // negative intersection - return false; - return true; - }; - glm::vec3 ray_origin, ray_dir; - unproject(s.pos, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir); - glm::vec3 plane_origin{ 0, 0, -1 }, plane_dir{ 0, 0, 1 }; - glm::vec3 hit; - glm::vec2 fb_pos; - if (intersect(ray_origin, ray_dir, plane_origin, plane_dir, hit)) + glDisable(GL_BLEND); + if (m_erase) { - glm::mat4 plane_camera = glm::lookAt(plane_origin, plane_dir, { 0, 1, 0 }); - glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1); - if (glm::abs(plane_local.x) < 0.5f && glm::abs(plane_local.y) < 0.5f) - { - fb_pos.x = -(plane_local.x - 0.5f) * m_width; - fb_pos.y = (plane_local.y + 0.5f) * m_height; - LOG("draw %f %f", fb_pos.x, fb_pos.y); - } + ShaderManager::use(ui::kShader::StrokeErase); + //ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); } - - auto mvp = proj * + else + { + ShaderManager::use(ui::kShader::Stroke); + ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); + } + ShaderManager::u_int(kShaderUniform::Tex, 0); // brush + ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg + ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); + for (const auto& s : samples) + { + auto unproject = [](glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj, glm::vec3& out_origin, glm::vec3& out_dir) { + auto clip_space = glm::vec2(loc.x, vp.w - loc.y - 1.f) / vp.zw() * 2.f - 1.f; + auto inv = glm::inverse(proj * camera); + auto wp0 = inv * glm::vec4(clip_space, 0, 1); + auto wp1 = inv * glm::vec4(clip_space, .5, 1); + out_origin = (wp0 / wp0.w).xyz(); + out_dir = glm::normalize((wp1 / wp1.w).xyz() - out_origin); + }; + auto intersect = [](glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, glm::vec3 plane_normal, glm::vec3& out_hit) { + float den = glm::dot(ray_dir, plane_normal); + if (den == 0) + return false; // no intersection + float num = glm::dot(plane_origin - ray_origin, plane_normal); + float t = num / den; + if (t > 0) + out_hit = ray_origin + ray_dir * t; + else + // negative intersection + return false; + return true; + }; + glm::vec3 ray_origin, ray_dir; + unproject(s.pos, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir); + glm::vec3 plane_origin{ 0, 0, -1 }, plane_dir{ 0, 0, 1 }; + glm::vec3 hit; + glm::vec2 fb_pos; + if (intersect(ray_origin, ray_dir, plane_origin, plane_dir, hit)) + { + glm::mat4 plane_camera = glm::lookAt(plane_origin, plane_dir, { 0, 1, 0 }); + glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1); + if (glm::abs(plane_local.x) < 0.5f && glm::abs(plane_local.y) < 0.5f) + { + fb_pos.x = -(plane_local.x - 0.5f) * m_width; + fb_pos.y = (plane_local.y + 0.5f) * m_height; + LOG("draw %f %f", fb_pos.x, fb_pos.y); + } + } + + auto mvp = proj * glm::translate(glm::vec3(fb_pos, 0)) * glm::scale(glm::vec3(s.size, s.size, 1)) * glm::eulerAngleZ(s.angle); - - glm::vec4 P[4] { - mvp * glm::vec4(glm::vec2(-.5f, -.5f), 0, 1.f), // A - bottom-left - mvp * glm::vec4(glm::vec2(-.5f, +.5f), 0, 1.f), // B - top-left - 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::inverse(proj); - glm::vec4 P2[4]{ - mvp_inv * P[0], - mvp_inv * P[1], - mvp_inv * P[2], - mvp_inv * P[3], - }; - - glm::vec2 bb_min(m_width, m_height); - glm::vec2 bb_max(0, 0); - for (int i = 0; i < 4; i++) - { - bb_min = glm::max({ 0, 0 }, glm::min(bb_min, P2[i].xy())); - bb_max = glm::min({ m_width, m_height }, glm::max(bb_max, P2[i].xy())); + + glm::vec4 P[4] { + mvp * glm::vec4(glm::vec2(-.5f, -.5f), 0, 1.f), // A - bottom-left + mvp * glm::vec4(glm::vec2(-.5f, +.5f), 0, 1.f), // B - top-left + 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::inverse(proj); + glm::vec4 P2[4]{ + mvp_inv * P[0], + mvp_inv * P[1], + mvp_inv * P[2], + mvp_inv * P[3], + }; + + glm::vec2 bb_min(m_width, m_height); + glm::vec2 bb_max(0, 0); + for (int i = 0; i < 4; i++) + { + bb_min = glm::max({ 0, 0 }, glm::min(bb_min, P2[i].xy())); + bb_max = glm::min({ m_width, m_height }, glm::max(bb_max, P2[i].xy())); + } + auto bb_sz = bb_max - bb_min; + + 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::ceil(bb_sz ) + pad*2.f, { 0, 0 }, (glm::vec2)(glm::ivec2(m_width, m_height) - tex_pos)); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + tex_pos.x, tex_pos.y, + tex_pos.x, tex_pos.y, + tex_sz.x, tex_sz.y); + + m_dirty_box[i].xy = glm::min(m_dirty_box[i].xy(), (glm::vec2)tex_pos); + m_dirty_box[i].zw = glm::max(m_dirty_box[i].zw(), (glm::vec2)(tex_pos + tex_sz)); + + ShaderManager::u_mat4(kShaderUniform::MVP, glm::mat4()); + ShaderManager::u_float(kShaderUniform::Alpha, s.flow); + m_plane_brush.update_vertices(P); + m_plane_brush.draw_fill(); } - auto bb_sz = bb_max - bb_min; - - 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::ceil(bb_sz ) + pad*2.f, { 0, 0 }, (glm::vec2)(glm::ivec2(m_width, m_height) - tex_pos)); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, - tex_pos.x, tex_pos.y, - tex_pos.x, tex_pos.y, - tex_sz.x, tex_sz.y); - - m_box.xy = glm::min(m_box.xy(), (glm::vec2)tex_pos); - m_box.zw = glm::max(m_box.zw(), (glm::vec2)(tex_pos + tex_sz)); - - ShaderManager::u_mat4(kShaderUniform::MVP, glm::mat4()); - ShaderManager::u_float(kShaderUniform::Alpha, s.flow); - m_plane_brush.update_vertices(P); - m_plane_brush.draw_fill(); } + + m_tex[i].unbind(); + m_tmp[i].unbindFramebuffer(); } - - m_tex.unbind(); + + glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE0); m_sampler.unbind(); m_sampler_bg.unbind(); tex.unbind(); - - glDisable(GL_BLEND); - + 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() { @@ -176,62 +174,71 @@ void ui::Canvas::stroke_commit() return; m_dirty = false; - m_layers[m_current_layer_idx].m_rtt.bindFramebuffer(); - - // save image before commit - glm::vec2 box_sz = m_box.zw() - m_box.xy(); - auto image = std::make_unique(box_sz.x * box_sz.y * 4); - glReadPixels(m_box.x, m_box.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, image.get()); - - // 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(); - + // save viewport and clear color states GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); - - glViewport(0, 0, m_width, m_height); GLboolean blend = glIsEnabled(GL_BLEND); + + // allocate action to add to history + auto action = new ActionStroke; + + // prepare common states + glViewport(0, 0, m_width, m_height); glDisable(GL_BLEND); - m_tmp.bindTexture(); - glActiveTexture(GL_TEXTURE1); - m_tex2.bind(); - m_sampler.bind(0); - m_sampler_bg.bind(1); - if (m_erase) + for (int i = 0; i < 6; i++) { - ShaderManager::use(ui::kShader::Texture); - } - else - { - ShaderManager::use(ui::kShader::StrokeLayer); - ShaderManager::u_int(kShaderUniform::TexBG, 1); - ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity); - } - 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_sampler_bg.unbind(); - m_tex2.unbind(); - glActiveTexture(GL_TEXTURE0); - m_tmp.unbindTexture(); + m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer(); + + // save image before commit + glm::vec2 box_sz = m_dirty_box[i].zw() - m_dirty_box[i].xy(); + action->m_image[i] = std::make_unique(box_sz.x * box_sz.y * 4); + glReadPixels(m_dirty_box[i].x, m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); + + action->m_box[i] = m_dirty_box[i]; + // copy to tmp2 for layer blending + glActiveTexture(GL_TEXTURE0); + m_tex2[i].bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + m_tex2[i].unbind(); + + m_tmp[i].bindTexture(); + glActiveTexture(GL_TEXTURE1); + m_tex2[i].bind(); + m_sampler.bind(0); + m_sampler_bg.bind(1); + if (m_erase) + { + ShaderManager::use(ui::kShader::Texture); + } + else + { + ShaderManager::use(ui::kShader::StrokeLayer); + ShaderManager::u_int(kShaderUniform::TexBG, 1); + ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity); + } + 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_sampler_bg.unbind(); + m_tex2[i].unbind(); + m_tmp[i].unbindTexture(); + + + m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer(); + } + + // restore viewport and clear color states 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]); - - m_layers[m_current_layer_idx].m_rtt.unbindFramebuffer(); + glActiveTexture(GL_TEXTURE0); // save history - auto action = new ActionStroke; - action->m_image = std::move(image); - action->m_box = m_box; action->m_layer_idx = m_current_layer_idx; action->m_canvas = this; action->m_stroke = std::move(m_current_stroke); @@ -248,21 +255,24 @@ void ui::Canvas::stroke_start(glm::vec2 point, float pressure, const ui::Brush& m_current_stroke->start(brush); m_current_stroke->add_point(point, pressure); - m_box = glm::vec4(m_width, m_height, 0, 0); // reset bounding box - - if (m_erase) + for (int i = 0; i < 6; i++) { - m_layers[m_current_layer_idx].m_rtt.bindFramebuffer(); - m_tmp.bindTexture(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); - m_tmp.unbindTexture(); - m_layers[m_current_layer_idx].m_rtt.unbindFramebuffer(); - } - else - { - m_tmp.bindFramebuffer(); - m_tmp.clear({ 0, 0, 0, 0 }); - m_tmp.unbindFramebuffer(); + m_dirty_box[i] = glm::vec4(m_width, m_height, 0, 0); // reset bounding box + + if (m_erase) + { + m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer(); + m_tmp[i].bindTexture(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + m_tmp[i].unbindTexture(); + m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer(); + } + else + { + m_tmp[i].bindFramebuffer(); + m_tmp[i].clear({ 0, 0, 0, 0 }); + m_tmp[i].unbindFramebuffer(); + } } m_show_tmp = true; } @@ -281,9 +291,12 @@ void ui::Canvas::resize(int width, int height) { m_width = width; m_height = height; - m_tmp.create(width, height); - m_tex.create(width, height); - m_tex2.create(width, height); + for (int i = 0; i < 6; i++) + { + m_tmp[i].create(width, height); + m_tex[i].create(width, height); + m_tex2[i].create(width, height); + } for (auto& l : m_layers) { l.create(width, height, ""); @@ -293,9 +306,12 @@ bool ui::Canvas::create(int width, int height) { m_width = width; m_height = height; - m_tmp.create(width, height); - m_tex.create(width, height); - m_tex2.create(width, height); // TODO: destroy before recreating + for (int i = 0; i < 6; i++) + { + m_tmp[i].create(width, height); + m_tex[i].create(width, height); + m_tex2[i].create(width, height); // TODO: destroy before recreating + } m_sampler.create(); m_sampler_bg.create(); m_plane.create<1>(1, 1); diff --git a/engine/canvas.h b/engine/canvas.h index 2cb9086..dfacc1c 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -8,6 +8,44 @@ NS_START +class Layer +{ +public: + RTT m_rtt[6]; + bool m_visible = true; + bool m_locked = false; + float m_opacity = 1.f; + std::string m_name; + bool create(int width, int height, std::string name) + { + for (int i = 0; i < 6; i++) + { + m_rtt[i].create(width, height); + m_rtt[i].bindFramebuffer(); + m_rtt[i].clear(); + m_rtt[i].unbindFramebuffer(); + } + return true; + } + void clear(const glm::vec4& c) + { + // push clear color state + GLfloat cc[4]; + glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); + glClearColor(c.r, c.g, c.b, c.a); + + for (int i = 0; i < 6; i++) + { + m_rtt[i].bindFramebuffer(); + glClear(GL_COLOR_BUFFER_BIT); + m_rtt[i].unbindFramebuffer(); + } + + // restore clear color state + glClearColor(cc[0], cc[1], cc[2], cc[3]); + } +}; + class Canvas { Plane m_plane; @@ -27,9 +65,12 @@ public: bool m_show_tmp = false; std::vector m_layers; std::vector m_order; - RTT m_tmp; - Texture2D m_tex; - Texture2D m_tex2; + glm::vec4 m_dirty_box[6]; + RTT m_tmp[6]; + Texture2D m_tex[6]; + Texture2D m_tex2[6]; + glm::vec3 m_plane_origin[6]; + glm::vec3 m_plane_normal[6]; Sampler m_sampler; Sampler m_sampler_bg; glm::vec2 m_cam_rot; @@ -52,8 +93,9 @@ class ActionStroke : public Action { public: std::unique_ptr m_stroke; - std::unique_ptr m_image; - glm::ivec4 m_box; + std::unique_ptr m_image[6]; + glm::ivec4 m_box[6]; + bool m_dirty[6]; int m_layer_idx; Canvas* m_canvas; virtual void run() override @@ -62,12 +104,17 @@ public: } virtual void undo() override { - m_canvas->m_layers[m_layer_idx].m_rtt.bindTexture(); + for (int i = 0; i < 6; i++) + { + // empty data + if (!m_image[i]) + continue; - glm::vec2 box_sz = m_box.zw() - m_box.xy(); - glTexSubImage2D(GL_TEXTURE_2D, 0, m_box.x, m_box.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image.get()); - - m_canvas->m_layers[m_layer_idx].m_rtt.unbindTexture(); + m_canvas->m_layers[m_layer_idx].m_rtt[i].bindTexture(); + glm::vec2 box_sz = m_box[i].zw() - m_box[i].xy(); + glTexSubImage2D(GL_TEXTURE_2D, 0, m_box[i].x, m_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get()); + m_canvas->m_layers[m_layer_idx].m_rtt[i].unbindTexture(); + } } }; diff --git a/engine/layout.h b/engine/layout.h index 8cf19cf..cf794b4 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -1910,90 +1910,37 @@ public: // auto plane_mvp = proj * camera * transform * // glm::scale(glm::vec3(sz, 1)); - auto plane_mvp = proj * camera * glm::translate(glm::vec3(0, 0, -1)); m_sampler.bind(0); ui::ShaderManager::use(kShader::TextureAlpha); ui::ShaderManager::u_int(kShaderUniform::Tex, 0); - ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); auto blend = glIsEnabled(GL_BLEND); glEnable(GL_BLEND); - for (auto i : m_canvas->m_order) + for (auto layer_index : m_canvas->m_order) { - if (!(m_canvas->m_erase && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == i)) + for (int plane_index = 0; plane_index < 4; plane_index++) { - ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[i].m_opacity); - m_canvas->m_layers[i].m_rtt.bindTexture(); - NodeBorder::m_plane.draw_fill(); - m_canvas->m_layers[i].m_rtt.unbindTexture(); - } - if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == i) - { - glEnable(GL_BLEND); - ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); - m_canvas->m_tmp.bindTexture(); - NodeBorder::m_plane.draw_fill(); - m_canvas->m_tmp.unbindTexture(); + auto plane_mvp = proj * camera * glm::eulerAngleY(glm::radians(90.f * plane_index)) * glm::translate(glm::vec3(0, 0, -1)); + ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); + if (!(m_canvas->m_erase && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)) + { + ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity); + m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture(); + NodeBorder::m_plane.draw_fill(); + m_canvas->m_layers[layer_index].m_rtt[plane_index].unbindTexture(); + } + if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) + { + glEnable(GL_BLEND); + ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity); + m_canvas->m_tmp[plane_index].bindTexture(); + NodeBorder::m_plane.draw_fill(); + m_canvas->m_tmp[plane_index].unbindTexture(); + } } } - - ui::ShaderManager::use(kShader::Color); - ui::ShaderManager::u_vec4(kShaderUniform::Col, { 1, 0, 0, 1 }); -// auto loc = m_cur; -// auto clip_space = glm::vec2(loc.x, box.w - loc.y - 1.f) / box.zw() * 2.f - 1.f; -// auto inv = glm::inverse(proj * camera); -// auto wp = inv * glm::vec4(clip_space, 0.9, 1); -// wp = wp / wp.w; - - auto unproject = [](glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj, glm::vec3& out_origin, glm::vec3& out_dir) { - auto clip_space = glm::vec2(loc.x, vp.w - loc.y - 1.f) / vp.zw() * 2.f - 1.f; - auto inv = glm::inverse(proj * camera); - auto wp0 = inv * glm::vec4(clip_space, 0, 1); - auto wp1 = inv * glm::vec4(clip_space, .5, 1); - out_origin = (wp0 / wp0.w).xyz(); - out_dir = glm::normalize((wp1 / wp1.w).xyz() - out_origin); - }; - auto intersect = [](glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, glm::vec3 plane_normal, glm::vec3& out_hit) { - float den = glm::dot(ray_dir, plane_normal); - if (den == 0) - return false; // no intersection - float num = glm::dot(plane_origin - ray_origin, plane_normal); - float t = num / den; - if (t > 0) - out_hit = ray_origin + ray_dir * t; - else - // negative intersection - return false; - return true; - }; - glm::vec3 ray_origin, ray_dir; - unproject(m_cur, { 0, 0, box.zw }, camera, proj, ray_origin, ray_dir); - glm::vec3 plane_origin{ 0, 0, -1 }, plane_dir{ 0, 0, 1 }; - glm::vec3 hit; - if (intersect(ray_origin, ray_dir, plane_origin, plane_dir, hit)) - { - glm::mat4 plane_camera = glm::lookAt(plane_origin, plane_dir, { 0, 1, 0 }); - glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1); - if (glm::abs(plane_local.x) < 0.5f && glm::abs(plane_local.y) < 0.5f) - { - LOG("hit %f %f %f", plane_local.x, plane_local.y, plane_local.z); - } - } - float fovy = glm::radians(m_canvas->m_cam_fov); - float fovx = fovy * box.z / box.w; - glm::vec2 fov = { fovx, fovy }; - auto fov_t = glm::vec2(m_cur.x, box.w - m_cur.y - 1.f) / box.zw(); - glm::vec2 fov_rot = glm::lerp(-fov*.5f, fov*.5f, fov_t); - glm::mat4 fov_rot_mat = glm::eulerAngleXY(-fov_rot.y, fov_rot.x) * camera; - if (method) - ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera * glm::translate(hit) * glm::scale(glm::vec3(.1))); - else - ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera * glm::translate(hit) * glm::scale(glm::vec3(.1)) * glm::transpose(fov_rot_mat)); - - //NodeBorder::m_plane.draw_fill(); - blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND); m_sampler.unbind(); @@ -2015,9 +1962,6 @@ public: KeyEvent* ke = static_cast(e); GestureEvent* ge = static_cast(e); auto loc = (me->m_pos - m_pos) * root()->m_zoom; - auto clip_space = glm::vec2(loc.x, m_size.y - loc.y - 1.f) / m_size * 2.f - 1.f; - //auto fb_space = glm::inverse(m_canvas->m_mvp) * glm::vec4(clip_space, 0, 1); - auto cur = glm::vec2(loc.x, m_size.y - loc.y - 1.f);// fb_space.xy(); switch (e->m_type) {