implement selection mask with lasso tool

This commit is contained in:
2017-10-07 13:35:53 +01:00
parent 41e52b7757
commit 78ec5a079e
16 changed files with 249 additions and 49 deletions

View File

@@ -52,6 +52,7 @@ void App::initShaders()
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n"
"uniform sampler2D tex_mask;\n"
"uniform mediump float alpha;\n"
"uniform bool lock;\n"
"in mediump vec3 uv;\n"
@@ -67,19 +68,34 @@ void App::initShaders()
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n"
"uniform sampler2D tex_mask;\n"
"uniform mediump float alpha;\n"
"uniform bool lock;\n"
"uniform bool mask;\n"
"in mediump vec3 uv;\n"
"out mediump vec4 frag;\n"
"mediump vec4 blur(sampler2D t, mediump vec2 uv){\n"
" mediump vec4 sum = texture(t, uv);\n"
" sum += textureOffset(t, uv, ivec2(-1, -1));\n"
" sum += textureOffset(t, uv, ivec2(-1, 0));\n"
" sum += textureOffset(t, uv, ivec2(-1, 1));\n"
" sum += textureOffset(t, uv, ivec2( 0, -1));\n"
" sum += textureOffset(t, uv, ivec2( 0, 1));\n"
" sum += textureOffset(t, uv, ivec2( 1, -1));\n"
" sum += textureOffset(t, uv, ivec2( 1, 0));\n"
" sum += textureOffset(t, uv, ivec2( 1, 1));\n"
" return sum / vec4(9.0);\n"
"}\n"
"void main(){\n"
" mediump vec4 base = texture(tex, uv.xy);\n"
" mediump vec4 stroke = texture(tex_stroke, uv.xy);\n"
" stroke.a = stroke.a * alpha;\n"
" stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv.xy).r : stroke.a * alpha;\n"
" mediump float contribution = (1.0 - base.a) * stroke.a;\n"
" mediump float alpha_tot = base.a + contribution;"
" mediump vec3 rgb = mix(base.rgb, stroke.rgb, stroke.a / alpha_tot);\n"
" frag = vec4(rgb, lock ? base.a : alpha_tot);\n"
" mediump vec3 rgb = mix(base.rgb, stroke.rgb, (stroke.a / alpha_tot));\n"
" frag = vec4(rgb, (lock ? base.a : alpha_tot));\n"
"}\n";
// TEXTURE ATLAS

View File

@@ -457,11 +457,13 @@ void ui::Canvas::stroke_commit()
m_tex2[i].bind();
m_sampler.bind(0);
m_sampler_bg.bind(1);
m_sampler_mask.bind(2);
if (m_state == kCanvasMode::Erase)
{
ui::ShaderManager::use(kShader::CompErase);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
@@ -469,7 +471,11 @@ void ui::Canvas::stroke_commit()
m_tex2[i].bind();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].bindTexture();
glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[i].bindTexture();
m_plane.draw_fill();
m_smask.m_rtt[i].unbindTexture();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_tex2[i].unbind();
@@ -479,14 +485,20 @@ void ui::Canvas::stroke_commit()
ui::ShaderManager::use(kShader::CompDraw);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
ui::ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
glActiveTexture(GL_TEXTURE0);
m_tex2[i].bind();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].bindTexture();
glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[i].bindTexture();
m_plane.draw_fill();
m_smask.m_rtt[i].unbindTexture();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_tex2[i].unbind();
@@ -699,7 +711,7 @@ bool ui::Canvas::create(int width, int height)
m_sampler_brush.create();
m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
m_sampler_bg.create(GL_NEAREST);
m_sampler_mask.create(GL_NEAREST);
m_sampler_mask.create(GL_LINEAR);
m_plane.create<1>(1, 1);
m_plane_brush.create<1>(1, 1);
m_mesh.create();
@@ -707,6 +719,8 @@ bool ui::Canvas::create(int width, int height)
{
l.create(width, height, "");
}
m_smask.create(width*2, height*2, "mask");
m_smask.clear({1, 1, 1, 1});
return true;
}
@@ -1246,7 +1260,7 @@ ui::Image ui::Canvas::thumbnail_read(std::string data_path)
return std::move(thumb);
}
void ui::Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)> observer)
void ui::Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)> observer, Layer& layer)
{
// save viewport and clear color states
GLint vp[4];
@@ -1256,18 +1270,18 @@ void ui::Canvas::draw_objects(std::function<void(const glm::mat4& camera, const
GLboolean blend = glIsEnabled(GL_BLEND);
// prepare common states
glViewport(0, 0, m_width, m_height);
glViewport(0, 0, layer.w, layer.h);
glDisable(GL_BLEND);
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .1f, 100.f);
for (int i = 0; i < 6; i++)
{
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer();
layer.m_rtt[i].bindFramebuffer();
observer(plane_camera, proj);
m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer();
layer.m_rtt[i].unbindFramebuffer();
}
// restore viewport and clear color states
@@ -1277,6 +1291,11 @@ void ui::Canvas::draw_objects(std::function<void(const glm::mat4& camera, const
glActiveTexture(GL_TEXTURE0);
}
void ui::Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)> observer)
{
draw_objects(observer, m_layers[m_current_layer_idx]);
}
///////////////////////////////////////////////////////////////////////////////////////////
void ui::Layer::destroy()

View File

@@ -64,6 +64,8 @@ public:
std::vector<int> m_order;
glm::vec4 m_dirty_box[6];
bool m_dirty_face[6];
Layer m_smask; // selection mask
bool m_smask_active = false;
RTT m_tmp[6];
Texture2D m_tex[6];
Texture2D m_tex2[6];
@@ -131,6 +133,7 @@ public:
ui::Image thumbnail_read(std::string data_path);
void preview_generate();
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)>);
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)>, Layer& layer);
bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3 &out_hit);
void point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj,

View File

@@ -6,6 +6,7 @@
#include "shader.h"
#include "node_canvas.h"
#include "app.h"
#include <poly2tri.h>
NodeCanvas* CanvasMode::node;
ui::Canvas* CanvasMode::canvas;
@@ -376,10 +377,14 @@ char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
static glm::vec2 oldpos;
static glm::vec2 oldvec;
static float acc = 0.f;
switch (me->m_type)
{
case kEventType::MouseDownR:
{
/*
if (!m_points.empty())
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
@@ -400,59 +405,147 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
m_points.clear();
m_dirty_planes.clear();
}
*/
break;
}
case kEventType::MouseDownL:
{
node->mouse_capture();
m_dragging = true;
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
int plane_id;
if (canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0))
{
m_dirty_planes[plane_id]++;
ui::Shape::vertex_t v;
v.pos = glm::vec4(hit_o, 1);
v.uvs = glm::vec2(0);
if (m_points.size() < 3)
{
m_points.push_back(v);
}
else
{
auto last = m_points.back();
m_points.push_back(m_points[0]);
m_points.push_back(last);
m_points.push_back(v);
float isx, isy;
if (get_line_intersection(m_points[0].pos.x, m_points[0].pos.y, v.pos.x, v.pos.y, 1, -1, 1, 1, &isx, &isy))
{
LOG("intersection in %f %f", isx, isy);
}
}
m_shape.update_vertices(m_points.data(), m_points.size());
}
m_points2d.clear();
m_points.clear();
oldpos = loc;
oldvec = {1.f, 0.f};
acc = 0;
ui::Shape::vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points2d.push_back(loc);
m_points2d.push_back(loc);
m_points.push_back(vert);
m_points.push_back(vert);
canvas->m_smask.clear({0, 0, 0, 0});
canvas->m_smask_active = true;
break;
}
case kEventType::MouseUpL:
node->mouse_release();
m_dragging = false;
if (m_points2d.size() > 3)
{
std::vector<p2t::Point*> points;
for (int i = 0; i < (int)m_points2d.size() - 1; i++)
points.push_back(new p2t::Point(m_points2d[i].x, m_points2d[i].y));
p2t::CDT cdt(points);
cdt.Triangulate();
auto triangles = cdt.GetTriangles();
std::vector<ui::Shape::vertex_t> v;
for (auto t : triangles)
{
ui::Shape::vertex_t vertex;
for (int i = 0; i < 3; i++)
{
auto p = t->GetPoint(i);
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
int plane_id;
if (canvas->point_trace({p->x, p->y}, ro, rd, hit_o, hit_fb, hit_d, plane_id))
{
m_dirty_planes[plane_id]++;
vertex.pos = glm::vec4(hit_o, 1);
v.push_back(vertex);
}
}
}
m_shape.update_vertices(v.data(), v.size());
if (!m_points.empty())
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
//glEnable(GL_BLEND);
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 1, 1, 1});
m_shape.draw_fill();
};
std::vector<int> planes;
for (auto p : m_dirty_planes)
{
planes.push_back(p.first);
canvas->m_dirty_face[p.first] = true;
canvas->m_dirty_box[p.first] = { 0, 0, canvas->m_width, canvas->m_height };
}
canvas->snap_history(planes);
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask);
m_points.clear();
m_dirty_planes.clear();
}
}
else
{
canvas->m_smask_active = false;
}
break;
case kEventType::MouseMove:
{
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 fb_pos;
int plane_id;
if (m_dragging && canvas->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, plane_id))
if (m_dragging)
{
ui::Shape::vertex_t v;
v.pos = glm::vec4(hit_o, 1);
v.uvs = glm::vec2(0);
m_points.back() = v;
m_shape.update_vertices(m_points.data(), m_points.size());
auto v = loc-oldpos;
float len = glm::length(v);
if (len > 5)
{
m_points.back().pos = glm::vec4(loc, 0, 1);
m_points2d.back() = loc;
v = glm::normalize(v);
float d = 1-glm::dot(v, oldvec);
acc += d;
oldpos = loc;
oldvec = v;
if (acc > 0.001) // angle change tollerance
{
LOG("d=%f acc=%f", d, acc);
acc = 0;
m_points2d.push_back(loc);
ui::Shape::vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points.push_back(vert);
m_points.push_back(vert);
}
m_shape.update_vertices(m_points.data(), m_points.size());
}
}
break;
/*
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
int plane_id;
if (canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0))
{
m_dirty_planes[plane_id]++;
ui::Shape::vertex_t v;
v.pos = glm::vec4(hit_o, 1);
v.uvs = glm::vec2(0);
if (m_points.size() < 3)
{
m_points.push_back(v);
}
else
{
auto last = m_points.back();
m_points.push_back(m_points[0]);
m_points.push_back(last);
m_points.push_back(v);
float isx, isy;
if (get_line_intersection(m_points[0].pos.x, m_points[0].pos.y, v.pos.x, v.pos.y, 1, -1, 1, 1, &isx, &isy))
{
LOG("intersection in %f %f", isx, isy);
}
}
m_shape.update_vertices(m_points.data(), m_points.size());
}
*/
}
case kEventType::MouseCancel:
if (m_dragging)
@@ -478,8 +571,8 @@ void CanvasModeFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, cons
if (!m_points.empty())
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, glm::scale(glm::vec3(1,-1,1)) * ortho);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { node->m_brush.m_tip_color.rgb(), node->m_brush.m_tip_opacity });
m_shape.draw_fill();
m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
}
}

View File

@@ -93,6 +93,7 @@ class CanvasModeFill : public CanvasMode
ui::DynamicShape m_shape;
bool m_dragging = false;
std::vector<ui::Shape::vertex_t> m_points;
std::vector<glm::vec2> m_points2d;
std::map<int, int> m_dirty_planes;
public:
virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override;

View File

@@ -78,6 +78,7 @@ void NodeCanvas::draw()
m_sampler.bind(0);
m_sampler.bind(1);
m_sampler.bind(2);
auto blend = glIsEnabled(GL_BLEND);
auto depth = glIsEnabled(GL_DEPTH_TEST);
@@ -120,14 +121,20 @@ void NodeCanvas::draw()
ui::ShaderManager::use(kShader::CompErase);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked);
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE1);
m_canvas->m_tmp[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE2);
m_canvas->m_smask.m_rtt[plane_index].bindTexture();
m_face_plane.draw_fill();
m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1);
m_canvas->m_tmp[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].unbindTexture();
@@ -137,14 +144,20 @@ void NodeCanvas::draw()
ui::ShaderManager::use(kShader::CompDraw);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_int(kShaderUniform::TexMask, 2);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked);
ui::ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE1);
m_canvas->m_tmp[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE2);
m_canvas->m_smask.m_rtt[plane_index].bindTexture();
m_face_plane.draw_fill();
m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1);
m_canvas->m_tmp[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].unbindTexture();

View File

@@ -31,7 +31,7 @@ void NodeImage::clone_copy(Node* dest) const
void NodeImage::create()
{
if (!m_path.empty() && TextureManager::load(m_path.c_str()))
if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps))
{
//LOG("load image node %s", m_path.c_str());
auto tex_sz = TextureManager::get(m_tex_id).size();

View File

@@ -9,6 +9,7 @@ public:
static ui::Plane m_plane;
static Sampler m_sampler;
bool m_use_atlas = false;
bool m_use_mipmaps = false;
glm::vec4 m_region;
glm::vec2 m_off;
glm::vec2 m_sz;

View File

@@ -26,6 +26,7 @@ void NodeButtonBrush::set_icon(const char* path)
{
img->m_path = path;
img->m_tex_id = const_hash(img->m_path.c_str());
img->m_use_mipmaps = true;
img->create();
}

View File

@@ -31,7 +31,7 @@ void NodeStrokePreview::init_controls()
m_mesh.create();
m_sampler.create();
m_sampler_brush.create();
m_sampler_brush.set_filter(GL_LINEAR, GL_LINEAR);
m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
TextureManager::load("data/thumbs/Round-Hard.png");
m_brush.m_tex_id = const_hash("data/thumbs/Round-Hard.png");
}

View File

@@ -16,6 +16,7 @@ enum class kShaderUniform : uint16_t
Tof = const_hash("tof"),
Tsz = const_hash("tsz"),
Alpha = const_hash("alpha"),
Mask = const_hash("mask"),
Resolution = const_hash("resolution"),
Highlight = const_hash("highlight"),
};