Files
panopainter/engine/canvas_modes.cpp

757 lines
23 KiB
C++

#include "pch.h"
#include "log.h"
#include "canvas_modes.h"
#include "layout.h"
#include "canvas.h"
#include "shader.h"
#include "node_canvas.h"
#include "app.h"
#include "util.h"
NodeCanvas* CanvasMode::node;
ui::Canvas* CanvasMode::canvas;
void CanvasModeBasicCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownL:
break;
case kEventType::MouseUpL:
break;
case kEventType::MouseDownR:
m_draggingR = true;
m_dragR_start = me->m_pos;
m_pan_start = canvas->m_pan;
node->mouse_capture();
break;
case kEventType::MouseUpR:
m_draggingR = false;
node->mouse_release();
break;
case kEventType::MouseMove:
if (m_draggingR)
canvas->m_pan = m_pan_start + (me->m_pos - m_dragR_start) * glm::vec2(-1, -1) * (canvas->m_cam_fov / 85.f);
canvas->m_cam_rot = canvas->m_pan * 0.003f;
break;
case kEventType::MouseScroll:
m_zoom_canvas += me->m_scroll_delta * 0.1f;
canvas->m_cam_fov -= me->m_scroll_delta * 2.0f;
App::I.brush_update();
break;
case kEventType::MouseCancel:
m_draggingR = false;
node->mouse_release();
break;
default:
break;
}
}
void CanvasModeBasicCamera::on_GestureEvent(GestureEvent* ge)
{
switch (ge->m_type)
{
case kEventType::GestureStart:
m_pan_start = canvas->m_pan;
m_zoom_start = m_zoom_canvas;
m_camera_fov = canvas->m_cam_fov;
break;
case kEventType::GestureMove:
canvas->m_pan = m_pan_start + ge->m_pos_delta * glm::vec2(-1, -1) * 0.3f * (canvas->m_cam_fov / 85.f);
canvas->m_cam_fov = m_camera_fov - ge->m_distance_delta * .05f;
canvas->m_cam_rot = canvas->m_pan * 0.003f;
App::I.brush_update();
break;
default:
break;
}
}
////////////////////////////////////////////////////////////////////
void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownL:
if (App::I.keys[(int)kKey::KeyAlt] || m_picking)
{
m_picking = true;
canvas->pick_start();
}
else
{
canvas->stroke_start(loc, me->m_pressure, canvas->m_current_brush);
}
m_dragging = true;
node->mouse_capture();
break;
case kEventType::MouseUpL:
if (m_dragging && !m_picking)
{
node->mouse_release();
canvas->stroke_end();
}
if (m_dragging && m_picking)
{
node->mouse_release();
glm::vec4 pix = canvas->pick_get(loc);
canvas->m_current_brush.m_tip_color = pix;
App::I.color->set_color(pix);
canvas->pick_end();
}
m_dragging = false;
m_picking = false;
break;
case kEventType::MouseMove:
if (m_dragging && !m_picking)
canvas->stroke_update(loc, me->m_pressure);
if (m_dragging && m_picking)
{
glm::vec4 pix = canvas->pick_get(loc);
canvas->m_current_brush.m_tip_color = pix;
App::I.color->set_color(pix);
}
m_cur_pos = loc;
break;
case kEventType::MouseCancel:
if (m_dragging)
{
canvas->stroke_cancel();
m_dragging = false;
node->mouse_release();
}
if (m_picking)
{
m_picking = false;
}
break;
default:
break;
}
}
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
#ifndef __IOS__
if (!m_dragging && !m_picking)
{
ui::ShaderManager::use(ui::kShader::StrokePreview);
ui::ShaderManager::u_int(ui::kShaderUniform::Tex, 0);
ui::ShaderManager::u_float(ui::kShaderUniform::Alpha, canvas->m_current_brush.m_tip_flow);
auto tip_color = glm::vec4(glm::vec3(canvas->m_current_brush.m_tip_color), 1);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, tip_color);
//ui::ShaderManager::u_int(ui::kShaderUniform::Highlight, 0);
float tip_scale = 1.f / glm::tan(glm::radians(ui::Canvas::I->m_cam_fov * 0.5f));
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP,
glm::scale(glm::vec3(1, -1, 1)) *
ortho *
glm::translate(glm::vec3(m_cur_pos, 0)) *
glm::scale(glm::vec3(canvas->m_current_brush.m_tip_size * 800.f * tip_scale))
);
glEnable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
auto& tex = TextureManager::get(canvas->m_current_brush.m_tex_id);
tex.bind();
canvas->m_sampler_brush.bind(0);
canvas->m_plane.draw_fill();
tex.unbind();
}
#endif
}
void CanvasModePen::leave()
{
m_brush = canvas->m_current_brush;
}
void CanvasModePen::enter()
{
if (m_valid_brush)
{
canvas->m_current_brush = m_brush;
App::I.brush_update();
}
else
{
m_brush = canvas->m_current_brush;
m_valid_brush = true;
}
}
////////////////////////////////////////////////////////////////////
void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownL:
node->mouse_capture();
m_dragging = true;
m_drag_start = loc;
m_drag_pos = loc;
break;
case kEventType::MouseUpL:
node->mouse_release();
if (m_dragging)
{
canvas->stroke_start(m_drag_start, 1.f, canvas->m_current_brush);
canvas->stroke_update(m_drag_pos, 1.f);
canvas->stroke_end();
}
m_dragging = false;
break;
case kEventType::MouseMove:
if (m_dragging)
m_drag_pos = loc;
break;
case kEventType::MouseCancel:
node->mouse_release();
m_dragging = false;
break;
default:
break;
}
}
void CanvasModeLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_dragging)
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, ortho);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, canvas->m_current_brush.m_tip_color);
static glm::vec4 AB[2];
AB[0] = { m_drag_start, 0, 1 };
AB[1] = { m_drag_pos, 0, 1 };
AB[0].y = canvas->m_box.w - AB[0].y - 1; // invert Y
AB[1].y = canvas->m_box.w - AB[1].y - 1; // invert Y
m_line.update_vertices(AB);
m_line.draw_stroke();
}
}
void CanvasModeLine::init()
{
m_line.create();
}
////////////////////////////////////////////////////////////////////
void CanvasModeCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownR:
canvas->m_cam_pos = { 0, 0, 0 };
break;
case kEventType::MouseDownL:
m_dragging = true;
m_drag_start = me->m_pos;
m_pos_start = xy(canvas->m_cam_pos);
node->mouse_capture();
break;
case kEventType::MouseUpL:
m_dragging = false;
node->mouse_release();
canvas->m_cam_pos = { 0, 0, 0 };
break;
case kEventType::MouseMove:
if (m_dragging)
canvas->m_cam_pos = glm::vec3(m_pos_start + (me->m_pos - m_drag_start) * glm::vec2(1, -1) * 0.001f, canvas->m_cam_pos.z);
break;
case kEventType::MouseCancel:
m_dragging = false;
node->mouse_release();
break;
default:
break;
}
}
////////////////////////////////////////////////////////////////////
void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 fb_pos;
if (canvas->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, m_plane_id))
{
m_lines.push_back({ hit_o, hit_d });
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseUpL:
node->mouse_release();
m_dragging = false;
//commit();
break;
case kEventType::MouseMove:
{
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
if (m_dragging && canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, m_plane_id))
{
m_lines.back() = { hit_o, hit_d };
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
m_lines.pop_back();
m_dragging = false;
node->mouse_release();
break;
default:
break;
}
}
void CanvasModeGrid::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
//if (m_dragging)
for (auto l : m_lines)
{
auto origin = l.o;
auto dir = l.d;
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 0, 0, 1});
static glm::vec4 AB[2];
AB[0] = {origin - dir * 10.f, 1};
AB[1] = {origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
}
}
void CanvasModeGrid::init()
{
m_line.create();
}
void CanvasModeGrid::commit()
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj){
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 0, 0, 1});
static glm::vec4 AB[2];
AB[0] = {origin - dir * 10.f, 1};
AB[1] = {origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
};
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2));
}
void CanvasModeGrid::clear()
{
m_lines.clear();
}
////////////////////////////////////////////////////////////////////
void CanvasModeMaskFree::init()
{
m_shape.create();
}
void CanvasModeMaskFree::leave()
{
// canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2));
// m_points.clear();
}
void CanvasModeMaskFree::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::MouseDownL:
{
node->mouse_capture();
m_dragging = true;
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<std::shared_ptr<p2t::Point>> points;
for (int i = 0; i < (int)m_points2d.size() - 1; i++)
points.emplace_back(std::make_shared<p2t::Point>(m_points2d[i].x, m_points2d[i].y));
auto v = canvas->triangulate(points);
canvas->project2Dpoints(v);
LOG("%d points", (int)v.size());
m_shape.update_vertices(v.data(), (int)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();
};
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask);
//m_points.clear();
// close the path
m_points.push_back(m_points[m_points.size() - 2]);
m_points.push_back(m_points.front());
canvas->project2Dpoints(m_points);
// reset m_shape to contour rendering
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
else
{
canvas->m_smask_active = false;
}
break;
case kEventType::MouseMove:
{
if (m_dragging)
{
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(), (int)m_points.size());
}
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
node->mouse_release();
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeMaskFree::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_points.size() > 3)
{
if (m_dragging)
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, glm::scale(glm::vec3(1,-1,1)) * ortho);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 });
//m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
m_shape.draw_stroke();
}
else
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 });
m_shape.draw_stroke();
}
}
}
////////////////////////////////////////////////////////////////////
void CanvasModeMaskLine::init()
{
m_shape.create();
}
void CanvasModeMaskLine::leave()
{
if (m_points2d.size() > 3)
{
std::vector<std::shared_ptr<p2t::Point>> points;
for (int i = 0; i < (int)m_points2d.size(); i++)
points.emplace_back(std::make_shared<p2t::Point>(m_points2d[i].x, m_points2d[i].y));
auto v = canvas->triangulate(points);
canvas->project2Dpoints(v);
LOG("%d points", (int)v.size());
m_shape.update_vertices(v.data(), (int)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();
};
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask);
//m_points.clear();
// close the path
m_points.push_back(m_points.back());
m_points.push_back(m_points.back());
m_points.push_back(m_points.front());
canvas->project2Dpoints(m_points);
// reset m_shape to contour rendering
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
else
{
canvas->m_smask_active = false;
}
m_active_tool = false;
}
void CanvasModeMaskLine::enter()
{
m_points2d.clear();
m_points.clear();
canvas->m_smask.clear({0, 0, 0, 0});
canvas->m_smask_active = true;
m_active_tool = true;
}
void CanvasModeMaskLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
m_dragging = true;
m_points2d.push_back(loc);
ui::Shape::vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points.push_back(vert);
m_shape.update_vertices(m_points.data(), (int)m_points.size());
break;
}
case kEventType::MouseUpL:
node->mouse_release();
m_dragging = false;
if (m_points.size() > 1)
{
m_points.push_back(m_points.back());
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
case kEventType::MouseMove:
{
if (m_dragging)
{
m_points.back().pos = glm::vec4(loc, 0, 1);
m_points2d.back() = loc;
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
node->mouse_release();
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeMaskLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_points.size() > 3)
{
if (m_active_tool)
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, glm::scale(glm::vec3(1,-1,1)) * ortho);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 });
//m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
m_shape.draw_stroke();
}
else
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 });
m_shape.draw_stroke();
}
}
}
////////////////////////////////////////////////////////////////////
void CanvasModeFill::init()
{
m_shape.create();
}
void CanvasModeFill::leave()
{
if (m_points.size() > 2)
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
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();
};
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask);
m_points.clear();
canvas->m_smask_active = true;
}
else
{
canvas->m_smask_active = false;
}
}
void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
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);
}
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
canvas->m_smask.clear({0, 0, 0, 0});
break;
}
case kEventType::MouseUpL:
node->mouse_release();
m_dragging = 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))
{
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(), (int)m_points.size());
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
node->mouse_release();
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (!m_points.empty())
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, .25 });
m_dragging ? m_shape.draw_fill() : m_shape.draw_stroke();
}
}