diff --git a/src/app.cpp b/src/app.cpp index 0b3da56..96537c6 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -361,7 +361,6 @@ void App::init() glEnable(GL_LINE_SMOOTH); #endif glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glBlendEquation(GL_FUNC_ADD); glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); initShaders(); diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp index 2cd1c50..0cd47e1 100644 --- a/src/app_shaders.cpp +++ b/src/app_shaders.cpp @@ -83,6 +83,24 @@ void App::initShaders() "void main() {\n" " frag = texture(tex, uv);\n" "}\n"; + static const char* shader_blend_f = + SHADER_VERSION + "uniform sampler2D tex;\n" + "uniform sampler2D tex_alpha;\n" + "uniform sampler2D tex_bg;\n" + "uniform mediump float alpha;\n" + "uniform int blend_mode;\n" + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + SHADER_FUNCTION_BLEND + "void main() {\n" + " mediump vec4 bg = texture(tex_bg, uv);\n" + " mediump vec4 fg = vec4(texture(tex, uv).rgb, texture(tex_alpha, uv).a);\n" + " if (fg.a == 0.0) { frag = bg; return; }\n" + " mediump float contribution = (1.0 - bg.a) * fg.a;\n" + " mediump float alpha_tot = bg.a + contribution;\n" + " frag = vec4(blend(bg, fg, alpha_tot, blend_mode), alpha_tot * alpha);\n" + "}\n"; static const char* shader_uv_f = SHADER_VERSION "in mediump vec2 uv;\n" @@ -109,6 +127,7 @@ void App::initShaders() SHADER_VERSION "uniform sampler2D tex;\n" "uniform sampler2D tex_alpha;\n" + "uniform sampler2D tex_bg;\n" "uniform mediump float alpha;\n" "uniform bool highlight;\n" "in mediump vec2 uv;\n" @@ -503,6 +522,8 @@ void App::initShaders() LOG("Failed to create shader TextureAlpha"); if (!ShaderManager::create(kShader::TextureAlphaSep, shader_v, shader_alpha_sep_f)) LOG("Failed to create shader TextureAlphaSep"); + if (!ShaderManager::create(kShader::TextureBlend, shader_v, shader_blend_f)) + LOG("Failed to create shader TextureBlend"); if (!ShaderManager::create(kShader::StrokePreview, shader_v, shader_stroke_preview_f)) LOG("Failed to create shader StrokePreview"); if (!ShaderManager::create(kShader::CompErase, shader_v, shader_comp_erase_f)) diff --git a/src/app_vr.cpp b/src/app_vr.cpp index e7fde59..924d98a 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -46,7 +46,9 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat auto layer_index = canvas->m_canvas->m_order[i]; for (int plane_index = 0; plane_index < 6; plane_index++) { - if (!canvas->m_canvas->m_layers[layer_index].m_visible || canvas->m_canvas->m_layers[layer_index].m_opacity == .0f) + if (!canvas->m_canvas->m_layers[layer_index].m_visible || + canvas->m_canvas->m_layers[layer_index].m_opacity == .0f || + !canvas->m_canvas->m_layers[layer_index].m_dirty_face) continue; int z = (int)(canvas->m_canvas->m_order.size() - i); diff --git a/src/canvas.cpp b/src/canvas.cpp index 5c819bd..59d8bfd 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -244,7 +244,9 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) auto layer_index = m_current_layer_idx; for (int plane_index = 0; plane_index < 6; plane_index++) { - if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == .0f) + if (!m_layers[layer_index].m_visible || + m_layers[layer_index].m_opacity == .0f || + !m_layers[layer_index].m_dirty_face) continue; glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)m_mixer.getWidth() / m_mixer.getHeight(), 0.1f, 1000.f); @@ -1018,7 +1020,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1); ShaderManager::u_float(kShaderUniform::Alpha, m_layers[source_idx].m_opacity); ShaderManager::u_int(kShaderUniform::Lock, false); - ShaderManager::u_int(kShaderUniform::BlendMode, 0); // TODO: defaulted to normal, change to layer blend mode when implemented + ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[source_idx].m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); glActiveTexture(GL_TEXTURE0); @@ -1273,32 +1275,60 @@ void Canvas::export_equirectangular_thread(std::string file_path) int progress = 0; int total = 6 + 2; + Texture2D face; + face.create(m_width, m_height); + for (int i = 0; i < 6; i++) { // prepare common states glViewport(0, 0, m_width, m_height); - glEnable(GL_BLEND); + glDisable(GL_BLEND); - ShaderManager::use(kShader::TextureAlpha); - ShaderManager::u_int(kShaderUniform::Highlight, false); + ShaderManager::use(kShader::TextureBlend); ShaderManager::u_int(kShaderUniform::Tex, 0); + ShaderManager::u_int(kShaderUniform::TexA, 1); + ShaderManager::u_int(kShaderUniform::TexBG, 2); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); m_tmp[i].bindFramebuffer(); - m_tmp[i].clear({ 1, 1, 1, 1 }); + m_tmp[i].clear({ 1, 1, 1, 0 }); - glActiveTexture(GL_TEXTURE0); // TODO: maybe remove this line - m_sampler_mask.bind(0); + glActiveTexture(GL_TEXTURE2); + face.bind(); + m_sampler_bg.bind(0); // nearest + m_sampler_mask.bind(1); // linear + m_sampler_bg.bind(2); for (auto layer_index : m_order) { if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f) continue; + glActiveTexture(GL_TEXTURE2); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[layer_index].m_blend_mode); 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(); } - m_sampler_mask.unbind(); + glActiveTexture(GL_TEXTURE2); + face.unbind(); + + glEnable(GL_BLEND); + 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 + glActiveTexture(GL_TEXTURE0); + face.bind(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); + m_tmp[i].clear({ 1, 1, 1, 1 }); + m_plane.draw_fill(); + face.unbind(); // copy result to cubemap glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id); @@ -1320,6 +1350,8 @@ void Canvas::export_equirectangular_thread(std::string file_path) } } + face.destroy(); + //auto data = std::make_unique(m_tmp[0].bytes()); //for (int i = 0; i < 1; i++) //{ diff --git a/src/canvas.h b/src/canvas.h index e6aa04e..b978551 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -8,7 +8,7 @@ #include "canvas_modes.h" #include -#define CANVAS_RES 512 +#define CANVAS_RES 1536 class Layer { @@ -20,7 +20,7 @@ public: bool m_alpha_locked = false; float m_opacity = 1.f; bool m_hightlight = false; - bool m_blend_mode = 0; + int m_blend_mode = 0; std::string m_name; int w = 0; int h = 0; diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 2351f3b..0c4b7d5 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -65,7 +65,7 @@ void NodeCanvas::draw() glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); - glClearColor(0, 0, 0, 1); + glClearColor(1, 1, 1, 0); glClear(GL_COLOR_BUFFER_BIT); float zoom = root()->m_zoom; auto box = m_clip * zoom; @@ -96,30 +96,6 @@ void NodeCanvas::draw() glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT); - - for (int plane_index = 0; plane_index < 6; plane_index++) - { - glm::mat4 plane_camera = glm::lookAt(m_canvas->m_plane_origin[plane_index], m_canvas->m_plane_normal[plane_index], m_canvas->m_plane_tangent[plane_index]); - m_canvas->m_plane_unproject[plane_index] = glm::inverse(m_canvas->m_proj * m_canvas->m_mv * m_canvas->m_plane_transform[plane_index]); - m_canvas->m_plane_dir[plane_index] = -(m_canvas->m_plane_transform[plane_index] * glm::vec4(m_canvas->m_plane_origin[plane_index], 1)); - - // face is the 2d shape of the cube plane i projected onto the window space - m_canvas->m_plane_shape[plane_index] = m_canvas->face_to_shape2D(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_mat4(kShaderUniform::MVP, plane_mvp); - m_face_plane.draw_fill(); - } - - glEnable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT); float pitch = 0; if (auto slider = root()->find("pitch-slider")) @@ -131,15 +107,21 @@ void NodeCanvas::draw() if (auto slider = root()->find("roll-slider")) roll = (slider->get_value() - 0.5) * glm::half_pi(); - + m_cache_rtt.bindFramebuffer(); + m_cache_rtt.clear({ 1, 1, 1, 0 }); 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_layers[layer_index].m_visible || m_canvas->m_layers[layer_index].m_opacity == .0f) + if (!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) continue; + 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)) * @@ -231,45 +213,80 @@ void NodeCanvas::draw() 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) -// { -// glDisable(GL_BLEND); -// ShaderManager::use(kShader::TextureAlpha); -// ShaderManager::u_int(kShaderUniform::Tex, 0); -// ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity); -// ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); -// ShaderManager::u_float(kShaderUniform::Alpha, 1); -// m_canvas->m_tmp[plane_index].bindTexture(); -// m_face_plane.draw_fill(); -// m_canvas->m_tmp[plane_index].unbindTexture(); -// glEnable(GL_BLEND); -// } + m_blender_rtt.unbindFramebuffer(); + + // draw the blended + { + 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); + 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(); + 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(); + + glActiveTexture(GL_TEXTURE2); + m_blender_bg.unbind(); + glActiveTexture(GL_TEXTURE1); + m_blender_bg.unbind(); + glActiveTexture(GL_TEXTURE0); + m_blender_rtt.unbindTexture(); + + } } } + m_cache_rtt.unbindFramebuffer(); -/* - if (m_canvas->m_smask_active && !m_canvas->m_show_tmp) + // draw the grid behind the layers using a temporary copy { - glDisable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_BLEND); + + //draw the grid for (int plane_index = 0; plane_index < 6; plane_index++) { + glm::mat4 plane_camera = glm::lookAt(m_canvas->m_plane_origin[plane_index], m_canvas->m_plane_normal[plane_index], m_canvas->m_plane_tangent[plane_index]); + m_canvas->m_plane_unproject[plane_index] = glm::inverse(m_canvas->m_proj * m_canvas->m_mv * m_canvas->m_plane_transform[plane_index]); + m_canvas->m_plane_dir[plane_index] = -(m_canvas->m_plane_transform[plane_index] * glm::vec4(m_canvas->m_plane_origin[plane_index], 1)); + + // face is the 2d shape of the cube plane i projected onto the window space + m_canvas->m_plane_shape[plane_index] = m_canvas->face_to_shape2D(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::TextureAlpha); - ShaderManager::u_int(kShaderUniform::Tex, 0); - ShaderManager::u_float(kShaderUniform::Alpha, 0.5f); - ShaderManager::u_int(kShaderUniform::Highlight, 0); + ShaderManager::use(kShader::Checkerboard); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); - glActiveTexture(GL_TEXTURE0); - m_canvas->m_smask.m_rtt[plane_index].bindTexture(); m_face_plane.draw_fill(); - m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); } + + // 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(); } -*/ + + for (auto& mode : *m_canvas->m_mode) mode->on_Draw(ortho_proj, proj, camera); @@ -390,6 +407,9 @@ void NodeCanvas::handle_resize(glm::vec2 old_size, glm::vec2 new_size) m_canvas->m_mixer.create((int)new_size.x * m_canvas->m_mixer_scale, (int)new_size.y * m_canvas->m_mixer_scale, -1, GL_RGBA32F); #endif + m_blender_rtt.create((int)new_size.x, (int)new_size.y, -1, GL_RGBA8); + m_cache_rtt.create((int)new_size.x, (int)new_size.y, -1, GL_RGBA8); + m_blender_bg.create((int)new_size.x, (int)new_size.y, GL_RGBA8); if (auto img = root()->find("tex-debug")) img->tex.assign(m_canvas->m_mixer.getTextureID()); // m_canvas->resize((int)new_size.x, (int)new_size.y); diff --git a/src/node_canvas.h b/src/node_canvas.h index 8dc8cf9..c7f49f4 100644 --- a/src/node_canvas.h +++ b/src/node_canvas.h @@ -6,6 +6,9 @@ class NodeCanvas : public Node { public: std::unique_ptr m_canvas; + RTT m_blender_rtt; + RTT m_cache_rtt; + Texture2D m_blender_bg; Sampler m_sampler; Sampler m_sampler_linear; Sampler m_sampler_stencil; diff --git a/src/node_panel_layer.cpp b/src/node_panel_layer.cpp index f58d40c..85a46e2 100644 --- a/src/node_panel_layer.cpp +++ b/src/node_panel_layer.cpp @@ -132,6 +132,7 @@ void NodePanelLayer::init() add_layer(); if (on_layer_add) on_layer_add(this); + update_attributes(); }; btn_remove->on_click = [this](Node*) { if (m_layers.size() == 1) diff --git a/src/shader.h b/src/shader.h index d103acd..bf9bc88 100644 --- a/src/shader.h +++ b/src/shader.h @@ -42,6 +42,7 @@ enum class kShader : uint16_t Texture = const_hash("texture"), 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"), UVs = const_hash("uvs"),