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);