code cleanup and improve brush direction

This commit is contained in:
2019-02-11 18:39:26 +01:00
parent 97c3ac0d19
commit 171ab31b47
5 changed files with 97 additions and 144 deletions

View File

@@ -27,13 +27,15 @@
"{ return mix(stroke.rgb, mix(base.rgb, base.rgb/(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\ "{ return mix(stroke.rgb, mix(base.rgb, base.rgb/(1.0-stroke.rgb), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\
"mediump vec3 blend_overlay(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\ "mediump vec3 blend_overlay(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot)"\
"{ return mix(stroke.rgb, mix(base.rgb, mix(2.0*base.rgb*stroke.rgb, 1.0-2.0*(1.0-base.rgb)*(1.0-stroke.rgb), floor(base.rgb*2.0)), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\ "{ return mix(stroke.rgb, mix(base.rgb, mix(2.0*base.rgb*stroke.rgb, 1.0-2.0*(1.0-base.rgb)*(1.0-stroke.rgb), floor(base.rgb*2.0)), stroke.a/alpha_tot), base.a/alpha_tot); }\n"\
"mediump vec3 blend(mediump vec4 base, mediump vec4 stroke, mediump float alpha_tot, int mode) {\n"\ "mediump vec4 blend(mediump vec4 base, mediump vec4 stroke, int mode) {\n"\
" if (mode == 0) return blend_normal(base, stroke, alpha_tot);\n"\ " mediump float contribution = (1.0 - base.a) * stroke.a;\n"\
" else if (mode == 1) return blend_multiply(base, stroke, alpha_tot);\n"\ " mediump float alpha_tot = base.a + contribution;\n"\
" else if (mode == 2) return blend_screen(base, stroke, alpha_tot);\n"\ " if (mode == 0) return vec4(blend_normal(base, stroke, alpha_tot), alpha_tot);\n"\
" else if (mode == 3) return blend_colorDodge(base, stroke, alpha_tot);\n"\ " else if (mode == 1) return vec4(blend_multiply(base, stroke, alpha_tot), alpha_tot);\n"\
" else if (mode == 4) return blend_overlay(base, stroke, alpha_tot);\n"\ " else if (mode == 2) return vec4(blend_screen(base, stroke, alpha_tot), alpha_tot);\n"\
" else return blend_multiply(base, stroke, alpha_tot);\n"\ " else if (mode == 3) return vec4(blend_colorDodge(base, stroke, alpha_tot), alpha_tot);\n"\
" else if (mode == 4) return vec4(blend_overlay(base, stroke, alpha_tot), alpha_tot);\n"\
" else return vec4(1, 0, 0, 1);\n"\
"}\n" "}\n"
#define SHADER_FUNCTION_HSV \ #define SHADER_FUNCTION_HSV \
@@ -115,9 +117,8 @@ void App::initShaders()
"#endif\n" "#endif\n"
" mediump vec4 fg = vec4(texture(tex, uv).rgb, texture(tex_alpha, uv).a);\n" " mediump vec4 fg = vec4(texture(tex, uv).rgb, texture(tex_alpha, uv).a);\n"
" if (fg.a == 0.0) { frag = bg; return; }\n" " if (fg.a == 0.0) { frag = bg; return; }\n"
" mediump float contribution = (1.0 - bg.a) * fg.a;\n" " mediump vec4 blended = blend(bg, fg, blend_mode);\n"
" mediump float alpha_tot = bg.a + contribution;\n" " frag = vec4(blended.rgb, blended.a * alpha);\n"
" frag = vec4(blend(bg, fg, alpha_tot, blend_mode), alpha_tot * alpha);\n"
"}\n"; "}\n";
static const char* shader_uv_f = static const char* shader_uv_f =
SHADER_VERSION SHADER_VERSION
@@ -207,14 +208,17 @@ void App::initShaders()
"uniform sampler2D tex;\n" "uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n" "uniform sampler2D tex_stroke;\n"
"uniform sampler2D tex_mask;\n" "uniform sampler2D tex_mask;\n"
"uniform sampler2D tex_dual;\n"
//"uniform sampler2D tex_stencil;\n" //"uniform sampler2D tex_stencil;\n"
"uniform mediump float alpha;\n" "uniform mediump float alpha;\n"
"uniform mediump float stroke_alpha;\n" "uniform mediump float stroke_alpha;\n"
"uniform mediump int blend_mode;\n" "uniform mediump int blend_mode;\n"
"uniform mediump int dual_blend_mode;\n"
"uniform mediump vec2 resolution;\n" "uniform mediump vec2 resolution;\n"
"uniform bool lock;\n" "uniform bool lock;\n"
"uniform bool mask;\n" "uniform bool mask;\n"
"uniform bool fragUV2;\n" "uniform bool fragUV2;\n"
"uniform bool useDual;\n"
"in mediump vec2 uv;\n" "in mediump vec2 uv;\n"
"out mediump vec4 frag;\n" "out mediump vec4 frag;\n"
SHADER_FUNCTION_BLUR SHADER_FUNCTION_BLUR
@@ -225,10 +229,8 @@ void App::initShaders()
" mediump vec4 stroke = texture(tex_stroke, uv);\n" " mediump vec4 stroke = texture(tex_stroke, uv);\n"
" stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n" " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n"
" if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n" " if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n"
" mediump float contribution = (1.0 - base.a) * stroke.a;\n" " mediump vec4 blended = blend(base, stroke, blend_mode);\n"
" mediump float alpha_tot = base.a + contribution;\n" " frag = vec4(blended.rgb, (lock ? base.a : blended.a) * alpha);\n"
" mediump vec3 rgb = blend(base, stroke, alpha_tot, blend_mode);\n"
" frag = vec4(rgb, (lock ? base.a : alpha_tot) * alpha);\n"
"}\n"; "}\n";
// TEXTURE ATLAS // TEXTURE ATLAS

View File

@@ -161,6 +161,7 @@ std::vector<StrokeSample> Stroke::compute_samples()
{ {
bool is_first = m_last_kp == 0; bool is_first = m_last_kp == 0;
m_dist += m_step; m_dist += m_step;
m_dir_dist += m_step;
while (m_dist > m_keypoints[m_last_kp + 1].dist) while (m_dist > m_keypoints[m_last_kp + 1].dist)
m_last_kp++; m_last_kp++;
const auto& A = m_keypoints[m_last_kp]; const auto& A = m_keypoints[m_last_kp];
@@ -174,22 +175,35 @@ std::vector<StrokeSample> Stroke::compute_samples()
{ {
if (m_brush->m_tip_angle_follow) if (m_brush->m_tip_angle_follow)
{ {
glm::vec2 v = s.origin - m_prev_sample.origin; if (m_dir_dist > m_dir_step)
if (v.length() > 0)
{ {
m_direction.add((v)); glm::vec2 v = glm::normalize(m_keypoints[m_last_kp].pos - m_keypoints[m_dir_kp].pos);
auto avg = m_direction.average(); m_dir_angle = -glm::orientedAngle(v, m_dir_ref);
float curve_angle = -glm::orientedAngle(glm::normalize(avg), glm::vec2(1, 0)); if (glm::abs(m_dir_angle) > glm::pi<float>() / 2.f || !m_dir_valid)
{
m_direction.clear();
m_dir_ref = v;
m_dir_ref_angle = -glm::orientedAngle(m_dir_ref, { 1, 0 });
m_dir_angle = 0;
}
m_dir_kp = m_last_kp;
m_dir_dist = 0;
m_dir_valid = true;
}
// NOTE: average angles need correction for 0-360 discontinuity if (m_dir_valid)
//m_curve_angles.add(curve_angle); {
//float avg = m_curve_angles.average(); m_direction.add(m_dir_angle);
s.angle += m_direction.average() + m_dir_ref_angle;
s.angle += curve_angle; m_prev_sample = s;
samples.push_back(s);
} }
} }
m_prev_sample = s; else
samples.push_back(s); {
m_prev_sample = s;
samples.push_back(s);
}
} }
else else
{ {
@@ -205,6 +219,10 @@ bool Stroke::has_sample()
} }
void Stroke::reset(bool clear_keypoints /*= false*/) void Stroke::reset(bool clear_keypoints /*= false*/)
{ {
m_dir_kp = 0;
m_dir_angle = 0;
m_dir_valid = false;
m_dir_dist = 0;
m_last_kp = 0; m_last_kp = 0;
m_dist = 0.f; m_dist = 0.f;
if (clear_keypoints) if (clear_keypoints)
@@ -251,6 +269,10 @@ void Stroke::start(const std::shared_ptr<Brush>& brush)
m_hsv_jitter.clear(); m_hsv_jitter.clear();
m_last_kp = 0; m_last_kp = 0;
m_dist = 0.f; m_dist = 0.f;
m_dir_kp = 0;
m_dir_angle = 0;
m_dir_valid = false;
m_dir_dist = 0;
m_brush = brush; m_brush = brush;
float size = glm::min(m_brush->m_tip_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), m_max_size); float size = glm::min(m_brush->m_tip_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), m_max_size);
m_step = glm::max(m_brush->m_tip_spacing * size * 800.f, 1.f); m_step = glm::max(m_brush->m_tip_spacing * size * 800.f, 1.f);

View File

@@ -96,6 +96,13 @@ public:
float fov = 0; float fov = 0;
}; };
int m_layer = 0; int m_layer = 0;
int m_dir_kp = 0;
bool m_dir_valid = false;
glm::vec2 m_dir_ref = { 1, 0 };
float m_dir_ref_angle = 0;
float m_dir_dist = 0;
float m_dir_step = 10;
float m_dir_angle = 0;
float m_curve = 0; float m_curve = 0;
float m_dist = 0; float m_dist = 0;
float m_step = 0; float m_step = 0;
@@ -103,7 +110,7 @@ public:
bool m_filter_points = true; bool m_filter_points = true;
Camera m_camera; Camera m_camera;
std::shared_ptr<Brush> m_brush; std::shared_ptr<Brush> m_brush;
cbuffer<glm::vec2, 3> m_direction; cbuffer<float, 3> m_direction;
cbuffer<float, 10> m_pressure_buff; cbuffer<float, 10> m_pressure_buff;
cbuffer<glm::vec3, 3> m_hsv_jitter; cbuffer<glm::vec3, 3> m_hsv_jitter;
StrokeSample m_prev_sample; StrokeSample m_prev_sample;

View File

@@ -210,18 +210,18 @@ void Canvas::stroke_cancel()
} }
void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz) void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
{ {
gl_state gl;
gl.save();
m_mixer.bindFramebuffer(); m_mixer.bindFramebuffer();
float zoom = m_node->root()->m_zoom;
glViewport(0, 0, m_mixer.getWidth(), m_mixer.getHeight()); glViewport(0, 0, m_mixer.getWidth(), m_mixer.getHeight());
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glScissor(bb_min.x, bb_min.y, bb_sz.x, bb_sz.y); glScissor(bb_min.x, bb_min.y, bb_sz.x, bb_sz.y);
m_mixer.clear({ 1, 1, 1, 0 });
m_sampler.bind(0);
m_sampler_linear.bind(1);
auto layer_index = m_current_layer_idx; auto layer_index = m_current_layer_idx;
for (int plane_index = 0; plane_index < 6; plane_index++) for (int plane_index = 0; plane_index < 6; plane_index++)
{ {
@@ -237,36 +237,6 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
m_plane_transform[plane_index] * m_plane_transform[plane_index] *
glm::translate(glm::vec3(0, 0, -1)); glm::translate(glm::vec3(0, 0, -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, false);
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
glEnable(GL_BLEND);
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_node->m_face_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();
glEnable(GL_BLEND);
// glActiveTexture(GL_TEXTURE0);
// m_tmp[plane_index].bindTexture();
// glActiveTexture(GL_TEXTURE1);
// m_tmp[plane_index].bindTexture();
// m_node->m_face_plane.draw_fill();
// glActiveTexture(GL_TEXTURE1);
// m_tmp[plane_index].unbindTexture();
// glActiveTexture(GL_TEXTURE0);
// m_tmp[plane_index].unbindTexture();
m_sampler.bind(0); m_sampler.bind(0);
m_sampler.bind(1); m_sampler.bind(1);
m_sampler.bind(2); m_sampler.bind(2);
@@ -279,8 +249,8 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
//ShaderManager::u_int(kShaderUniform::TexStencil, 3); //ShaderManager::u_int(kShaderUniform::TexStencil, 3);
ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush->m_tip_opacity); ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush->m_tip_opacity);
ShaderManager::u_float(kShaderUniform::Alpha, 1); ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index].m_alpha_locked); ShaderManager::u_int(kShaderUniform::Lock, false/*m_layers[layer_index].m_alpha_locked*/);
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active); ShaderManager::u_int(kShaderUniform::Mask, false/*m_smask_active*/);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false); ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush->m_blend_mode); ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush->m_blend_mode);
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z); ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
@@ -290,15 +260,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
m_tmp[plane_index].bindTexture(); m_tmp[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[plane_index].bindTexture(); m_smask.m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE3);
if (m_current_stroke->m_brush->m_stencil_texture)
m_current_stroke->m_brush->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
m_node->m_face_plane.draw_fill(); m_node->m_face_plane.draw_fill();
if (m_current_stroke->m_brush->m_stencil_texture)
m_current_stroke->m_brush->m_stencil_texture->unbind();
glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[plane_index].unbindTexture(); m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
m_tmp[plane_index].unbindTexture(); m_tmp[plane_index].unbindTexture();
@@ -307,7 +269,8 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
} }
m_sampler.unbind(); m_sampler.unbind();
m_mixer.unbindFramebuffer(); m_mixer.unbindFramebuffer();
glDisable(GL_SCISSOR_TEST);
gl.restore();
} }
void Canvas::stroke_draw() void Canvas::stroke_draw()
{ {
@@ -386,7 +349,6 @@ void Canvas::stroke_draw()
m_mixer_idle = false; m_mixer_idle = false;
} }
static glm::vec2 UV2[4];
glm::vec2 dx_mix(m_mixer_sample.size * 0.5f, 0), dy_mix(0, m_mixer_sample.size * 0.5f); glm::vec2 dx_mix(m_mixer_sample.size * 0.5f, 0), dy_mix(0, m_mixer_sample.size * 0.5f);
glm::vec2 off_mix[4] = { glm::vec2 off_mix[4] = {
-dx_mix - dy_mix, // A - bottom-left -dx_mix - dy_mix, // A - bottom-left
@@ -402,60 +364,43 @@ void Canvas::stroke_draw()
+dx + dy, // C - top-right +dx + dy, // C - top-right
+dx - dy, // D - bottom-right +dx - dy, // D - bottom-right
}; };
auto sz = glm::vec2(m_mixer.getWidth(), m_mixer.getHeight()) * m_mixer_scale;
glm::vec2 bb_min(sz); glm::vec2 mixer_sz(m_mixer.getWidth(), m_mixer.getHeight());
glm::vec2 bb_max(0, 0); glm::vec2 mixer_bb_min(mixer_sz);
glm::vec2 mixer_bb_max(0, 0);
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
auto p = (xy(m_mixer_sample.pos) + off_mix[j] * glm::orientate2(-s.angle) + glm::vec2(0, 1)); auto p = (xy(m_mixer_sample.pos) + off_mix[j] * glm::orientate2(-s.angle) + glm::vec2(0, 1));
UV2[j] = p / sz; mixer_bb_min = glm::max({ 0, 0 }, glm::min(mixer_bb_min, p));
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p)); mixer_bb_max = glm::min(mixer_sz, glm::max(mixer_bb_max, p));
bb_max = glm::min(sz, glm::max(bb_max, p));
B[j].pos = glm::vec4(xy(s.pos) + off[j] * glm::orientate2(-s.angle), 1, 1); B[j].pos = glm::vec4(xy(s.pos) + off[j] * glm::orientate2(-s.angle), 1, 1);
B[j].uvs2 = UV2[j]; B[j].uvs2 = p / mixer_sz;
} }
auto bb_sz = bb_max - bb_min;
if (m_brush->m_tip_mix > 0.f) if (m_brush->m_tip_mix > 0.f)
{ {
stroke_draw_mix(bb_min, bb_sz); stroke_draw_mix(mixer_bb_min, mixer_bb_max - mixer_bb_min);
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.bind(3);
//m_sampler_linear.bind(5);
glActiveTexture(GL_TEXTURE2);
if (m_brush->m_stencil_texture)
m_brush->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE3);
m_mixer.bindTexture();
glDisable(GL_BLEND);
} }
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
/*
// check if plane is even visible // check if plane is even visible
glm::vec4 forward = m_mv * glm::vec4(0, 0, 1, 1); glm::vec4 forward = m_mv * glm::vec4(0, 0, 1, 1);
float dot = glm::dot(xyz(forward), m_plane_normal[i]); float dot = glm::dot(xyz(forward), m_plane_normal[i]);
// TODO: use better threshold than 0.3 // TODO: use better threshold than 0.3
// some trigonometric shit, tangent and stuff // some trigonometric shit, tangent and stuff
// if (dot < -0.3f) if (dot < -0.3f)
// continue; continue;
*/
int intersected = 0; int intersected = 0;
int inside = 0;
// intersect P with the current face to clip diverging points from the plane // intersect P with the current face to clip diverging points from the plane
auto P = poly_intersect(B, m_plane_shape[i]); auto P = poly_intersect(B, m_plane_shape[i]);
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
for (int j = 0; j < P.size(); j++) for (int j = 0; j < P.size(); j++)
{ {
glm::vec3 ray_origin, ray_dir; glm::vec3 ray_origin, ray_dir;
@@ -481,12 +426,8 @@ void Canvas::stroke_draw()
float hit_t; float hit_t;
if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit, hit_t)) if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit, hit_t))
{ {
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1); glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1);
if (glm::abs(plane_local.x) < 1.5f && glm::abs(plane_local.y) < 1.5f)
{
inside++;
}
//P[j].uvs2 = xy(P[j].pos) / glm::vec2(App::I.width, App::I.height); //P[j].uvs2 = xy(P[j].pos) / glm::vec2(App::I.width, App::I.height);
P[j].pos.x = -(plane_local.x * 0.5f - 0.5f) * m_width; P[j].pos.x = -(plane_local.x * 0.5f - 0.5f) * m_width;
P[j].pos.y = (plane_local.y * 0.5f + 0.5f) * m_height; P[j].pos.y = (plane_local.y * 0.5f + 0.5f) * m_height;
@@ -510,7 +451,7 @@ void Canvas::stroke_draw()
} }
} }
if (intersected < 3 || inside == 0) if (intersected < 3)
continue; continue;
m_dirty_face[i] = true; m_dirty_face[i] = true;
@@ -541,10 +482,8 @@ void Canvas::stroke_draw()
tex_pos.x, tex_pos.y, tex_sz.x, tex_sz.y); tex_pos.x, tex_pos.y, tex_sz.x, tex_sz.y);
} }
m_dirty_box[i] = glm::vec4( m_dirty_box[i] = glm::vec4(glm::min(xy(m_dirty_box[i]), (glm::vec2)tex_pos),
glm::min(xy(m_dirty_box[i]), (glm::vec2)tex_pos), glm::max(zw(m_dirty_box[i]), (glm::vec2)(tex_pos + tex_sz)));
glm::max(zw(m_dirty_box[i]), (glm::vec2)(tex_pos + tex_sz))
);
ShaderManager::use(kShader::Stroke); ShaderManager::use(kShader::Stroke);
ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj); ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj);
@@ -573,33 +512,6 @@ void Canvas::stroke_draw()
} }
m_brush_shape.draw_fill(); m_brush_shape.draw_fill();
/*
// draw sample wireframe
std::vector<vertex_t> lines;
for (int vi = 0; vi < P.size(); vi += 3)
{
auto a = P[vi];
auto b = P[(vi + 1) % P.size()];
auto c = P[(vi + 2) % P.size()];
a.pos.z = b.pos.z = c.pos.z = 0;
lines.push_back(a);
lines.push_back(b);
lines.push_back(b);
lines.push_back(c);
lines.push_back(c);
lines.push_back(a);
}
ShaderManager::use(kShader::Color);
ShaderManager::u_vec4(kShaderUniform::Col, { s.col, 1 });
ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj);
m_brush_shape.update_vertices(lines.data(), lines.size());
m_brush_shape.draw_stroke();
*/
if (!ShaderManager::ext_framebuffer_fetch) if (!ShaderManager::ext_framebuffer_fetch)
{ {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);

View File

@@ -95,7 +95,7 @@ template<typename T, int N> struct cbuffer
m_index = 0; m_index = 0;
m_count = 0; m_count = 0;
} }
T& head() const T& head() const
{ {
return m_index == 0 ? m_vec[m_count - 1] : m_vec[m_index - 1]; return m_index == 0 ? m_vec[m_count - 1] : m_vec[m_index - 1];
} }
@@ -118,6 +118,16 @@ template<typename T, int N> struct cbuffer
tot += m_vec[i]; tot += m_vec[i];
return tot / (float)m_count; return tot / (float)m_count;
} }
template<typename T2 = T> T2 average_threshold(T threshold) const
{
T2 tot{};
if (m_count == 0)
return tot;
int n = 0;
for (int i = 0; i < m_count; i++)
tot += glm::abs(m_vec[i] - head()) < threshold ? 0 : m_vec[i], n++;
return tot / (float)n;
}
}; };
template<typename T, int Max = 0> template<typename T, int Max = 0>