diff --git a/data/brushes/Round-Hard.png b/data/brushes/Round-Hard.png index 0ec829d..da3bfc4 100644 Binary files a/data/brushes/Round-Hard.png and b/data/brushes/Round-Hard.png differ diff --git a/data/layout.xml b/data/layout.xml index 78b791b..0527fd5 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -801,7 +801,9 @@ --> - + + + diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp index d2faafa..7f2a29a 100644 --- a/engine/app_layout.cpp +++ b/engine/app_layout.cpp @@ -627,8 +627,9 @@ void App::initLayout() } Brush b; - b.m_tex_id = brushes->get_texture_id(0); - b.id = brushes->get_brush_id(0); + int br_idx = brushes->find_brush("Round-Hard"); + b.m_tex_id = brushes->get_texture_id(br_idx); + b.id = brushes->get_brush_id(br_idx); b.m_tip_size = .1f; b.m_tip_flow = .5f; b.m_tip_spacing = .1f; diff --git a/engine/app_shaders.cpp b/engine/app_shaders.cpp index b4c0c3a..d01dd7d 100644 --- a/engine/app_shaders.cpp +++ b/engine/app_shaders.cpp @@ -350,21 +350,21 @@ void App::initShaders() #endif " fg.a *= 1.0-rand(uv2+uv)*noise;\n" " if (fg.a == 0.0) discard;\n" + " mediump float contribution = (1.0 - bg.a) * fg.a;\n" + " mediump float alpha_tot = bg.a + contribution;" + " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" " if (mix_alpha > 0.0){\n" " mediump vec2 uv_mix = uv_2 / q;\n" " if (uv_mix.x < 0.0 || uv_mix.x > 1.0 || uv_mix.y < 0.0 || uv_mix.y > 1.0) discard;\n" " mediump vec4 mbg = texture(tex_mix, uv_mix);\n" - " fg.rgb = mix(fg.rgb, mbg.rgb, mix_alpha * mbg.a);\n" + " rgb.rgb = mix(rgb.rgb, mbg.rgb, mix_alpha * mbg.a);\n" " }\n" - " mediump float contribution = (1.0 - bg.a) * fg.a;\n" - " mediump float alpha_tot = bg.a + contribution;" - " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" " mediump vec4 frag_wet = vec4(rgb, max(bg.a, fg.a * 1.2));\n" " mediump vec4 frag_dry = vec4(rgb, alpha_tot);\n" " frag = mix(frag_dry, frag_wet, wet);\n" // " mediump vec4 mbg = texture(tex_mix, uv_2 / q);\n" -// " frag.rgb = mix(frag.rgb, mbg.rgb, mix_alpha);\n" +// " frag.rgb = mix(frag.rgb, mbg.rgb, mix_alpha * mbg.a);\n" "}\n"; static const char* shader_checkerboard_v = diff --git a/engine/brush.cpp b/engine/brush.cpp index 30dc9a0..5119d71 100644 --- a/engine/brush.cpp +++ b/engine/brush.cpp @@ -211,7 +211,7 @@ void ui::Stroke::add_point(glm::vec2 pos, float pressure) if (m_brush.m_tip_size_pressure) m_step = glm::max(m_brush.m_tip_spacing * m_brush.m_tip_size * pressure * 800.f, 1.f); - float dist = m_keypoints.empty() ? 0.f : + float dist = m_keypoints.empty() ? m_step : m_keypoints.back().dist + glm::distance(m_keypoints.back().pos, pos); if (m_keypoints.empty()) m_prev_sample.origin = pos; diff --git a/engine/canvas.cpp b/engine/canvas.cpp index 40fa749..4d0a9e2 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -228,7 +228,7 @@ void ui::Canvas::stroke_draw_mix() glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); - m_sampler_bg.bind(0); + m_sampler.bind(0); auto layer_index = m_current_layer_idx; for (int plane_index = 0; plane_index < 6; plane_index++) { @@ -236,9 +236,10 @@ void ui::Canvas::stroke_draw_mix() continue; glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)m_mixer.getWidth() / m_mixer.getHeight(), 0.1f, 1000.f); - auto plane_mvp_z = m_proj * m_mv * + auto plane_mvp_z = + glm::scale(glm::vec3(1, -1, 1)) * + m_proj * m_mv * m_plane_transform[plane_index] * - //glm::scale(glm::vec3(1, -1, 1)) * glm::translate(glm::vec3(0, 0, -1)); ui::ShaderManager::use(kShader::TextureAlpha); @@ -258,7 +259,7 @@ void ui::Canvas::stroke_draw_mix() m_node->m_face_plane.draw_fill(); m_tmp[plane_index].unbindTexture(); } - m_sampler_bg.unbind(); + m_sampler.unbind(); m_mixer.unbindFramebuffer(); } void ui::Canvas::stroke_draw() @@ -273,42 +274,11 @@ void ui::Canvas::stroke_draw() glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); - stroke_draw_mix(); - - glViewport(0, 0, m_width, m_height); - - auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f); - auto m_brush = m_current_stroke->m_brush; auto samples = m_current_stroke->compute_samples(); auto& tex = TextureManager::get(m_brush.m_tex_id); auto& stencil = TextureManager::get(const_hash("data/paper.jpg")); - glActiveTexture(GL_TEXTURE0); - tex.bind(); - m_sampler_brush.bind(0); - m_sampler_bg.bind(1); - m_sampler_stencil.bind(2); - m_sampler_mix.bind(3); - - glActiveTexture(GL_TEXTURE2); - stencil.bind(); - glActiveTexture(GL_TEXTURE3); - m_mixer.bindTexture(); - - glDisable(GL_BLEND); - ShaderManager::use(ui::kShader::Stroke); - ShaderManager::u_int(kShaderUniform::Tex, 0); // brush -#ifndef __IOS__ - ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg -#endif - ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil - ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer - ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); - ShaderManager::u_vec2(kShaderUniform::StencilOffset, stencil_offset); - ShaderManager::u_float(kShaderUniform::StencilAlpha, m_brush.m_tip_stencil); - ShaderManager::u_float(kShaderUniform::MixAlpha, m_brush.m_tip_mix); - ShaderManager::u_float(kShaderUniform::Wet, m_brush.m_tip_wet); - ShaderManager::u_float(kShaderUniform::Noise, m_brush.m_tip_noise); + auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f); for (const auto& s : samples) { @@ -317,7 +287,39 @@ void ui::Canvas::stroke_draw() m_mixer_sample = s; m_mixer_idle = false; } - + + if (m_brush.m_tip_mix > 0.f) + stroke_draw_mix(); + + glViewport(0, 0, m_width, m_height); + + glActiveTexture(GL_TEXTURE0); + tex.bind(); + m_sampler_brush.bind(0); + m_sampler_bg.bind(1); + m_sampler_stencil.bind(2); + m_sampler_mix.bind(3); + + glActiveTexture(GL_TEXTURE2); + stencil.bind(); + glActiveTexture(GL_TEXTURE3); + m_mixer.bindTexture(); + + glDisable(GL_BLEND); + ShaderManager::use(ui::kShader::Stroke); + ShaderManager::u_int(kShaderUniform::Tex, 0); // brush +#ifndef __IOS__ + ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg +#endif + ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil + ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer + ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); + ShaderManager::u_vec2(kShaderUniform::StencilOffset, stencil_offset); + ShaderManager::u_float(kShaderUniform::StencilAlpha, m_brush.m_tip_stencil); + ShaderManager::u_float(kShaderUniform::MixAlpha, m_brush.m_tip_mix); + ShaderManager::u_float(kShaderUniform::Wet, m_brush.m_tip_wet); + ShaderManager::u_float(kShaderUniform::Noise, m_brush.m_tip_noise); + static glm::vec2 UV2[4]; for (int j = 0; j < 4; j++) { @@ -328,8 +330,8 @@ void ui::Canvas::stroke_draw() +dx + dy, // C - top-right +dx - dy, // D - bottom-right }; - UV2[j] = (m_mixer_sample.pos + off[j]) / glm::vec2(m_mixer.getWidth(), m_mixer.getHeight()) * m_mixer_scale; - UV2[j].y = 1 - UV2[j].y; + UV2[j] = (m_mixer_sample.pos + off[j] + glm::vec2(0,1)) / glm::vec2(m_mixer.getWidth(), m_mixer.getHeight()) * m_mixer_scale; + //UV2[j].y = 1.f - UV2[j].y; } for (int i = 0; i < 6; i++) @@ -866,7 +868,7 @@ bool ui::Canvas::create(int width, int height) 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_LINEAR, GL_REPEAT); + m_sampler_mix.create(GL_NEAREST, GL_REPEAT); m_plane.create<1>(1, 1); m_plane_brush.create<1>(1, 1); m_mesh.create(); diff --git a/engine/canvas.h b/engine/canvas.h index d06e87f..8da6ea6 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -76,7 +76,7 @@ public: bool m_smask_active = false; RTT m_tmp[6]; RTT m_mixer; - float m_mixer_scale = 0.25f; + float m_mixer_scale = 1; ui::StrokeSample m_mixer_sample; bool m_mixer_idle = true; Texture2D m_brush_mix; diff --git a/engine/node_canvas.cpp b/engine/node_canvas.cpp index 9bbaf19..0ab34cd 100644 --- a/engine/node_canvas.cpp +++ b/engine/node_canvas.cpp @@ -271,7 +271,7 @@ void NodeCanvas::handle_resize(glm::vec2 old_size, glm::vec2 new_size) if (new_size.x > m_canvas->m_width) { m_canvas->m_mixer.create((int)new_size.x * m_canvas->m_mixer_scale, - (int)new_size.y * m_canvas->m_mixer_scale); + (int)new_size.y * m_canvas->m_mixer_scale, -1, GL_RGBA32F); 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/engine/node_panel_brush.cpp b/engine/node_panel_brush.cpp index ba5567c..f700f39 100644 --- a/engine/node_panel_brush.cpp +++ b/engine/node_panel_brush.cpp @@ -63,6 +63,7 @@ void NodePanelBrush::init() brush->set_icon(path.c_str()); brush->m_brushID = count++; brush->high_path = path_hi; + brush->brush_name = i; brush->high_id = const_hash(path_hi.c_str()); m_brushes.push_back(brush); brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); @@ -82,6 +83,18 @@ void NodePanelBrush::handle_click(Node* target) on_brush_changed(this, m_current->m_brushID); } +int NodePanelBrush::find_brush(const std::string & name) const +{ + for (int i = 0; i < m_brushes.size(); i++) + { + if (m_brushes[i]->brush_name.find(name) != std::string::npos) + { + return i; + } + } + return -1; +} + uint16_t NodePanelBrush::get_texture_id(int index) const { TextureManager::load(m_brushes[index]->high_path.c_str(), true); diff --git a/engine/node_panel_brush.h b/engine/node_panel_brush.h index ff77001..8e54950 100644 --- a/engine/node_panel_brush.h +++ b/engine/node_panel_brush.h @@ -10,6 +10,7 @@ class NodeButtonBrush : public NodeButtonCustom public: int m_brushID; bool m_selected = false; + std::string brush_name; std::string high_path; uint16_t high_id; NodeImage* img; @@ -30,6 +31,7 @@ public: virtual void init() override; void handle_click(Node* target); std::vector FindAllBrushes(const std::string& folder); + int find_brush(const std::string& name) const; uint16_t get_texture_id(int index) const; int get_brush_id(int index) const; void select_brush(int brush_id);