1333 lines
44 KiB
C++
1333 lines
44 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:
|
|
// if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
// {
|
|
// m_draggingR = true;
|
|
// m_dragR_start = me->m_pos;
|
|
// m_pan_start = canvas->m_pan;
|
|
// node->mouse_capture();
|
|
// }
|
|
break;
|
|
case kEventType::MouseUpL:
|
|
// if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
// {
|
|
// m_draggingR = false;
|
|
// node->mouse_release();
|
|
// }
|
|
break;
|
|
case kEventType::MouseDownR:
|
|
if (App::I.keys[(int)kKey::KeyAlt])
|
|
break;
|
|
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)
|
|
{
|
|
auto dir = (App::I.has_vr && App::I.vr_active) ? glm::vec2(1, 1) : glm::vec2(-1, -1);
|
|
canvas->m_pan = m_pan_start + (me->m_pos - m_dragR_start) * dir * (canvas->m_cam_fov / 85.f);
|
|
auto angle = canvas->m_pan * 0.003f;
|
|
canvas->m_cam_rot = glm::eulerAngleXY(angle.y, angle.x);
|
|
}
|
|
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;
|
|
auto angle = canvas->m_pan * 0.003f;
|
|
canvas->m_cam_rot = glm::eulerAngleXY(angle.y, angle.x);
|
|
App::I.brush_update();
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
#if defined(__IOS__)
|
|
m_draw_tip = (me->m_source == kEventSource::Mouse);
|
|
#else
|
|
m_draw_tip = (me->m_source == kEventSource::Mouse || me->m_source == kEventSource::Stylus);
|
|
#endif // _WIN32
|
|
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownL:
|
|
if (App::I.keys[(int)kKey::KeyAlt] || m_picking)
|
|
{
|
|
m_picking = true;
|
|
canvas->pick_start();
|
|
glm::vec4 pix = canvas->pick_get(loc);
|
|
canvas->m_current_brush.m_tip_color = pix;
|
|
App::I.color->set_color(pix);
|
|
}
|
|
else
|
|
{
|
|
canvas->stroke_start({ loc, 0 }, 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::MouseDownR:
|
|
if (App::I.keys[(int)kKey::KeyAlt])
|
|
{
|
|
m_resizing = true;
|
|
m_dragging = true;
|
|
m_size_pos_start = m_cur_pos;
|
|
m_size_value_start = canvas->m_current_brush.m_tip_size;
|
|
node->mouse_capture();
|
|
}
|
|
break;
|
|
case kEventType::MouseUpR:
|
|
if (m_dragging && m_resizing)
|
|
{
|
|
node->mouse_release();
|
|
m_dragging = false;
|
|
m_resizing = false;
|
|
}
|
|
break;
|
|
case kEventType::MouseMove:
|
|
if (m_dragging && !m_picking && !m_resizing)
|
|
canvas->stroke_update({ loc, 0 }, 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);
|
|
}
|
|
if (m_dragging && m_resizing)
|
|
{
|
|
auto diff = m_cur_pos - m_size_pos_start;
|
|
canvas->m_current_brush.m_tip_size = m_size_value_start + diff.x * 0.001f;
|
|
}
|
|
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;
|
|
if (m_resizing)
|
|
m_resizing = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
|
{
|
|
if (m_draw_tip)
|
|
{
|
|
auto pos = m_resizing ? m_size_pos_start : m_cur_pos;
|
|
if (App::I.keys[(int)kKey::KeyAlt] && !m_resizing)
|
|
pos.x = pos.x - canvas->m_current_brush.m_tip_size * 500.f;
|
|
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);
|
|
float tip_scale_fix = 1.f / glm::tan(glm::radians(ui::Canvas::I->m_cam_fov * 0.5f));
|
|
float tip_scale = canvas->m_current_brush.m_tip_size * 800.f * tip_scale_fix;
|
|
float tip_angle = canvas->m_current_brush.m_tip_angle * (float)(M_PI * 2.0);
|
|
glm::vec2 tip_offset = glm::vec2(0);
|
|
auto tip_color = glm::vec4(glm::vec3(canvas->m_current_brush.m_tip_color), 1);
|
|
if (canvas->m_current_stroke)
|
|
{
|
|
const auto& s = canvas->m_current_stroke->m_prev_sample;
|
|
if (s.size > 0.f)
|
|
{
|
|
tip_scale = s.size;
|
|
tip_angle = s.angle;
|
|
tip_offset = s.pos - s.origin;
|
|
tip_color = glm::vec4(s.col, s.flow);
|
|
}
|
|
}
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, tip_color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP,
|
|
glm::scale(glm::vec3(1, -1, 1)) *
|
|
ortho *
|
|
glm::translate(glm::vec3(pos + tip_offset, 0)) *
|
|
glm::scale(glm::vec3(tip_scale)) *
|
|
glm::eulerAngleZ(tip_angle)
|
|
);
|
|
bool blend = glIsEnabled(GL_BLEND);
|
|
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();
|
|
if (!blend) glDisable(GL_BLEND);
|
|
}
|
|
}
|
|
|
|
void CanvasModePen::leave()
|
|
{
|
|
m_brush = canvas->m_current_brush;
|
|
}
|
|
|
|
void CanvasModePen::enter()
|
|
{
|
|
m_cur_pos = ui::Canvas::I->m_cur_pos;
|
|
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)
|
|
{
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
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, 0 }, 1.f, canvas->m_current_brush);
|
|
canvas->stroke_update({ m_drag_pos, 0 }, 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)
|
|
{
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
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)
|
|
{
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
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(1), std::placeholders::_1, std::placeholders::_2));
|
|
// m_points.clear();
|
|
}
|
|
|
|
void CanvasModeMaskFree::clear()
|
|
{
|
|
m_points.clear();
|
|
m_points2d.clear();
|
|
m_shape.clear();
|
|
}
|
|
|
|
void CanvasModeMaskFree::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
static glm::vec2 oldpos;
|
|
static glm::vec2 oldvec;
|
|
static float acc = 0.f;
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
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;
|
|
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)
|
|
{
|
|
if (!m_points.empty())
|
|
{
|
|
|
|
//m_points2d = poly_intersect(poly_remove_duplicate(m_points2d), canvas->face_to_shape2D(0));
|
|
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();
|
|
};
|
|
// use m_shape to render the mask polygon
|
|
auto v = canvas->triangulate(poly_remove_duplicate(m_points2d));
|
|
canvas->project2Dpoints(v);
|
|
m_shape.update_vertices(v.data(), (int)v.size());
|
|
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask);
|
|
|
|
// close the path and reset m_shape to contour rendering
|
|
m_points.push_back(m_points.back());
|
|
m_points.push_back(m_points.front());
|
|
canvas->project2Dpoints(m_points);
|
|
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.f - 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);
|
|
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)
|
|
{
|
|
bool depth = glIsEnabled(GL_DEPTH_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
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();
|
|
}
|
|
}
|
|
if (depth) glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModeMaskLine::init()
|
|
{
|
|
m_shape.create();
|
|
}
|
|
|
|
void CanvasModeMaskLine::leave()
|
|
{
|
|
if (m_points2d.size() > 3)
|
|
{
|
|
std::vector<vertex_t> points;
|
|
for (int i = 0; i < (int)m_points2d.size(); i++)
|
|
points.emplace_back(m_points2d[i]);
|
|
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)
|
|
{
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownL:
|
|
{
|
|
node->mouse_capture();
|
|
m_dragging = true;
|
|
m_points2d.push_back(loc);
|
|
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)
|
|
{
|
|
if (canvas->m_touch_lock && me->m_source == kEventSource::Touch)
|
|
return;
|
|
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]++;
|
|
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))
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModeTransform::init()
|
|
{
|
|
m_sphere.create(1.f, glm::radians(-10.f), glm::radians(10.f), glm::radians(-10.f), glm::radians(10.f), 1.f);
|
|
m_circle.create<16>(1.f);
|
|
for (int i = 0; i < 6; i++)
|
|
m_shape[i].create();
|
|
m_xform = glm::mat4(1);
|
|
m_xform_local = glm::mat4(1);
|
|
}
|
|
|
|
void CanvasModeTransform::enter()
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
m_shape[i].clear();
|
|
m_points_face[i].clear();
|
|
m_shape[i].clear();
|
|
}
|
|
|
|
if (m_action == ActionType::Import)
|
|
{
|
|
float aspect = 1.f;
|
|
if (m_source_image.data())
|
|
{
|
|
m_tex[0].create(m_source_image);
|
|
aspect = (float)m_source_image.width / (float)m_source_image.height;
|
|
}
|
|
|
|
auto center = zw(canvas->m_box) * 0.5f;
|
|
glm::vec2 bb_sz = glm::vec2(aspect, 1.f) * 100.f;
|
|
glm::vec2 bb_min = center - bb_sz * 0.5f;
|
|
glm::vec2 bb_max = center + bb_sz * 0.5f;
|
|
glm::vec2 midpoint = (bb_min + bb_max) * 0.5f;
|
|
|
|
auto cam_up = glm::inverse(canvas->m_mv) * glm::vec4(0, 1, 0, 1);
|
|
auto center_mat = glm::lookAt({ 0, 0, 0 }, canvas->point_trace(midpoint), xyz(cam_up));
|
|
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, canvas->point_trace(midpoint), xyz(cam_up)));
|
|
m_xform_local = glm::mat4(1);
|
|
|
|
corners.clear();
|
|
corners.emplace_back(bb_min, 0); // A
|
|
corners.emplace_back(bb_max, 0); // C
|
|
corners.emplace_back(bb_max.x, bb_min.y, 0); // B
|
|
corners.emplace_back(bb_min.x, bb_max.y, 0); // D
|
|
corners.emplace_back(midpoint, 0);
|
|
corners.emplace_back(midpoint + (bb_max - bb_min) * glm::vec2(0.75f, 0), 0);
|
|
|
|
for (auto& c : corners)
|
|
c = center_mat * glm::vec4(canvas->point_trace(c), 1);
|
|
|
|
m_points_face[0] = std::vector<vertex_t>({
|
|
vertex_t(corners[0], { 0, 0 }),
|
|
vertex_t(corners[2], { 1, 0 }),
|
|
vertex_t(corners[1], { 1, 1 }),
|
|
vertex_t(corners[3], { 0, 1 }),
|
|
});
|
|
auto shape3d = canvas->triangulate(m_points_face[0]);
|
|
m_shape[0].update_vertices(shape3d.data(), shape3d.size());
|
|
|
|
return;
|
|
}
|
|
|
|
auto m = static_cast<CanvasModeMaskFree*>(canvas->modes[(int)ui::Canvas::kCanvasMode::MaskFree][0]);
|
|
canvas->m_smask_active = false;
|
|
auto points = m->m_points2d;
|
|
|
|
glm::vec2 bb_min(FLT_MAX);
|
|
glm::vec2 bb_max(-FLT_MAX);
|
|
for (auto p2d : points)
|
|
{
|
|
bb_min = glm::min(bb_min, p2d);
|
|
bb_max = glm::max(bb_max, p2d);
|
|
}
|
|
glm::vec2 midpoint = (bb_min + bb_max) * 0.5f;
|
|
auto cam_up = glm::inverse(canvas->m_mv) * glm::vec4(0, 1, 0, 1);
|
|
auto center_mat = glm::lookAt({ 0, 0, 0 }, canvas->point_trace(midpoint), xyz(cam_up));
|
|
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, canvas->point_trace(midpoint), xyz(cam_up)));
|
|
m_xform_local = glm::mat4(1);
|
|
corners.clear();
|
|
corners.emplace_back(bb_min, 0);
|
|
corners.emplace_back(bb_max, 0);
|
|
corners.emplace_back(bb_max.x, bb_min.y, 0);
|
|
corners.emplace_back(bb_min.x, bb_max.y, 0);
|
|
corners.emplace_back(midpoint, 0);
|
|
corners.emplace_back(midpoint + (bb_max-bb_min) * glm::vec2(0.75f, 0), 0);
|
|
for (auto& c : corners)
|
|
c = center_mat * glm::vec4(canvas->point_trace(c), 1);
|
|
|
|
for (int plane = 0; plane < 6; plane++)
|
|
{
|
|
auto face = canvas->face_to_shape2D(plane);
|
|
auto shape2d = poly_intersect(points, face);
|
|
if (shape2d.size() < 3)
|
|
{
|
|
m_shape[plane].clear();
|
|
m_points_face[plane].clear();
|
|
continue;
|
|
}
|
|
m_points_face[plane].reserve(shape2d.size());
|
|
glm::vec2 bb_min(canvas->m_size);
|
|
glm::vec2 bb_max(0, 0);
|
|
for (auto p2d : shape2d)
|
|
{
|
|
p2d.y = canvas->m_box.w - p2d.y - 1;
|
|
auto p2d_clip = ((p2d / zw(canvas->m_box)) * 2.f - 1.f);
|
|
auto p3d_plane = canvas->m_plane_unproject[plane] * glm::vec4(p2d_clip, 0, 1);
|
|
auto p3d_norm = -p3d_plane / p3d_plane.z;
|
|
if (p3d_norm.w < 0)
|
|
continue;
|
|
auto p2d_plane = xy(p3d_norm);
|
|
auto p2d_plane_raster = (p2d_plane * 0.5f + 0.5f) * canvas->m_size;
|
|
auto p3d_world = canvas->m_plane_transform[plane] * glm::vec4(p2d_plane, -1, 1);
|
|
bb_min = glm::min(bb_min, p2d_plane_raster);
|
|
bb_max = glm::max(bb_max, p2d_plane_raster);
|
|
|
|
//glm::vec3 pt_o, pt_d;
|
|
//canvas->point_unproject(p2d, pt_o, pt_d);
|
|
|
|
vertex_t v;
|
|
v.pos = glm::vec4(xyz(p3d_world), 1);
|
|
v.uvs = p2d_plane_raster;
|
|
m_points_face[plane].push_back(v);
|
|
}
|
|
|
|
if (m_points_face[plane].size() < 3)
|
|
{
|
|
m_shape[plane].clear();
|
|
m_points_face[plane].clear();
|
|
continue;
|
|
}
|
|
|
|
auto bb_sz = bb_max - bb_min;
|
|
for (auto& v : m_points_face[plane])
|
|
{
|
|
v.uvs2 = v.uvs / canvas->m_size;
|
|
v.uvs = (v.uvs - bb_min) / bb_sz;
|
|
v.pos = center_mat * v.pos;
|
|
}
|
|
|
|
auto shape3d = canvas->triangulate(m_points_face[plane]);
|
|
m_shape[plane].update_vertices(shape3d.data(), shape3d.size());
|
|
|
|
canvas->m_layers[canvas->m_current_layer_idx].m_rtt[plane].bindFramebuffer();
|
|
m_tex[plane].create(bb_sz.x, bb_sz.y);
|
|
m_tex[plane].bind();
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bb_min.x, bb_min.y, bb_sz.x, bb_sz.y);
|
|
m_tex[plane].unbind();
|
|
canvas->m_layers[canvas->m_current_layer_idx].m_rtt[plane].unbindFramebuffer();
|
|
}
|
|
|
|
if (m_action == ActionType::Cut)
|
|
{
|
|
auto& layer = canvas->m_layers[canvas->m_current_layer_idx];
|
|
|
|
GLint vp[4];
|
|
glGetIntegerv(GL_VIEWPORT, vp);
|
|
glViewport(0, 0, layer.w, layer.h);
|
|
|
|
bool depth = glIsEnabled(GL_DEPTH_TEST);
|
|
bool blend = glIsEnabled(GL_BLEND);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_BLEND);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 0 });
|
|
|
|
auto action = new ui::ActionStroke;
|
|
action->was_saved = !canvas->m_unsaved;
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
auto plane_camera = glm::lookAt(glm::vec3(0), canvas->m_plane_origin[i], canvas->m_plane_tangent[i]);
|
|
auto mvp = proj * plane_camera * m_xform * m_xform_local;
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, mvp);
|
|
|
|
layer.m_rtt[i].bindFramebuffer();
|
|
|
|
glm::vec2 bb_min(canvas->m_size);
|
|
glm::vec2 bb_max(0, 0);
|
|
for (int j = 0; j < 6; j++)
|
|
{
|
|
for (auto p : m_points_face[j])
|
|
{
|
|
auto p_clip = mvp * p.pos;
|
|
auto p_norm = p_clip / p_clip.z;
|
|
if (p_clip.w < 0 || glm::any(glm::greaterThan(glm::abs(xy(p_norm)), { 1, 1 })))
|
|
continue;
|
|
auto p_raster = (xy(p_norm) * 0.5f + 0.5f) * canvas->m_size;
|
|
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p_raster));
|
|
bb_max = glm::min(canvas->m_size, glm::max(bb_max, p_raster));
|
|
}
|
|
}
|
|
glm::vec2 pad(2);
|
|
bb_min = glm::max({ 0, 0 }, glm::floor(bb_min) - pad);
|
|
bb_max = glm::min(canvas->m_size, glm::ceil(bb_max) + pad);
|
|
auto bb_sz = bb_max - bb_min;
|
|
|
|
if (bb_sz.x <= 0.f || bb_sz.y <= 0.f)
|
|
{
|
|
layer.m_rtt[i].unbindFramebuffer();
|
|
continue;
|
|
}
|
|
|
|
action->m_image[i] = std::make_unique<uint8_t[]>(bb_sz.x * bb_sz.y * 4);
|
|
glReadPixels(bb_min.x, bb_min.y, bb_sz.x, bb_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get());
|
|
action->m_box[i] = { bb_min, bb_max };
|
|
action->m_old_box[i] = layer.m_dirty_box[i];
|
|
action->m_old_dirty[i] = layer.m_dirty_face[i];
|
|
|
|
layer.m_dirty_face[i] = true;
|
|
layer.m_dirty_box[i] = {
|
|
glm::min(xy(layer.m_dirty_box[i]), bb_min),
|
|
glm::max(zw(layer.m_dirty_box[i]), bb_max),
|
|
};
|
|
|
|
for (int j = 0; j < 6; j++)
|
|
m_shape[j].draw_fill();
|
|
|
|
layer.m_rtt[i].unbindFramebuffer();
|
|
}
|
|
|
|
depth ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
|
|
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
|
|
|
action->m_layer_idx = canvas->m_current_layer_idx;
|
|
action->m_canvas = canvas;
|
|
//action->m_stroke = std::move(m_current_stroke);
|
|
ActionManager::add(action);
|
|
|
|
m_source_image.destroy();
|
|
}
|
|
}
|
|
|
|
void CanvasModeTransform::leave()
|
|
{
|
|
auto& layer = canvas->m_layers[canvas->m_current_layer_idx];
|
|
|
|
GLint vp[4];
|
|
glGetIntegerv(GL_VIEWPORT, vp);
|
|
glViewport(0, 0, layer.w, layer.h);
|
|
|
|
bool depth = glIsEnabled(GL_DEPTH_TEST);
|
|
bool blend = glIsEnabled(GL_BLEND);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_BLEND);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
|
ui::ShaderManager::use(ui::kShader::CompDraw);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::Tex, 0);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::TexStroke, 1);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::TexMask, 2);
|
|
ui::ShaderManager::u_float(ui::kShaderUniform::Alpha, 1);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::Lock, false);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::Mask, false);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::UseFragCoordUV2, true);
|
|
ui::ShaderManager::u_vec2(ui::kShaderUniform::Resolution, canvas->m_size);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::BlendMode, 0);
|
|
|
|
canvas->m_sampler_bg.bind(1);
|
|
canvas->m_sampler_bg.bind(0);
|
|
|
|
auto action = new ui::ActionStroke;
|
|
action->was_saved = !canvas->m_unsaved;
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
auto plane_camera = glm::lookAt(glm::vec3(0), canvas->m_plane_origin[i], canvas->m_plane_tangent[i]);
|
|
auto mvp = proj * plane_camera * m_xform * m_xform_local;
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, mvp);
|
|
|
|
layer.m_rtt[i].bindFramebuffer();
|
|
|
|
glm::vec2 bb_min(canvas->m_size);
|
|
glm::vec2 bb_max(0, 0);
|
|
for (int j = 0; j < 6; j++)
|
|
{
|
|
for (auto p : m_points_face[j])
|
|
{
|
|
auto p_clip = mvp * p.pos;
|
|
auto p_norm = p_clip / p_clip.z;
|
|
if (p_clip.w < 0 || glm::any(glm::greaterThan(glm::abs(xy(p_norm)), { 1, 1 })))
|
|
continue;
|
|
auto p_raster = (xy(p_norm) * 0.5f + 0.5f) * canvas->m_size;
|
|
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p_raster));
|
|
bb_max = glm::min(canvas->m_size, glm::max(bb_max, p_raster));
|
|
}
|
|
}
|
|
glm::vec2 pad(2);
|
|
bb_min = glm::max({ 0, 0 }, glm::floor(bb_min) - pad);
|
|
bb_max = glm::min(canvas->m_size, glm::ceil(bb_max) + pad);
|
|
auto bb_sz = bb_max - bb_min;
|
|
|
|
if (bb_sz.x <= 0.f || bb_sz.y <= 0.f)
|
|
{
|
|
layer.m_rtt[i].unbindFramebuffer();
|
|
continue;
|
|
}
|
|
|
|
action->m_image[i] = std::make_unique<uint8_t[]>(bb_sz.x * bb_sz.y * 4);
|
|
glReadPixels(bb_min.x, bb_min.y, bb_sz.x, bb_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get());
|
|
action->m_box[i] = { bb_min, bb_max };
|
|
action->m_old_box[i] = layer.m_dirty_box[i];
|
|
action->m_old_dirty[i] = layer.m_dirty_face[i];
|
|
|
|
layer.m_dirty_face[i] = true;
|
|
layer.m_dirty_box[i] = {
|
|
glm::min(xy(layer.m_dirty_box[i]), bb_min),
|
|
glm::max(zw(layer.m_dirty_box[i]), bb_max),
|
|
};
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
canvas->m_tex2[i].bind();
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, bb_min.x, bb_min.y, bb_min.x, bb_min.y, bb_sz.x, bb_sz.y);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
for (int j = 0; j < 6; j++)
|
|
{
|
|
m_tex[j].bind();
|
|
m_shape[j].draw_fill();
|
|
m_tex[j].unbind();
|
|
}
|
|
|
|
layer.m_rtt[i].unbindFramebuffer();
|
|
}
|
|
depth ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
|
|
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
|
|
|
action->m_layer_idx = canvas->m_current_layer_idx;
|
|
action->m_canvas = canvas;
|
|
//action->m_stroke = std::move(m_current_stroke);
|
|
ActionManager::add(action);
|
|
|
|
//auto m = static_cast<CanvasModeMaskFree*>(canvas->modes[(int)ui::Canvas::kCanvasMode::MaskFree][0]);
|
|
//m->clear();
|
|
}
|
|
|
|
void CanvasModeTransform::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
|
{
|
|
bool depth = glIsEnabled(GL_DEPTH_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_BLEND);
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera * m_xform * m_xform_local);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 1, 1, .1 });
|
|
m_shape[i].draw_fill();
|
|
|
|
ui::ShaderManager::use(ui::kShader::Texture);
|
|
ui::ShaderManager::u_int(ui::kShaderUniform::Tex, 0);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera * m_xform * m_xform_local);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
m_tex[i].bind();
|
|
canvas->m_sampler.bind(0);
|
|
m_shape[i].draw_fill();
|
|
m_tex[i].unbind();
|
|
}
|
|
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
auto m2d = canvas->m_proj * canvas->m_mv * m_xform * m_xform_local;
|
|
for (int i = 0; i < corners.size(); i++)
|
|
{
|
|
auto c = m2d * glm::vec4(corners[i], 1);
|
|
auto c3d = c / c.z;
|
|
if (c3d.w < 0)
|
|
continue;
|
|
auto c2d = (xy(c3d) * 0.5f + 0.5f) * zw(canvas->m_box);
|
|
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP,
|
|
ortho * glm::translate(glm::vec3(c2d, 0)) * glm::scale(glm::vec3(20.f) * App::I.zoom));
|
|
|
|
// draw inside
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 1, 1, 1, i == corner_hl ? 1.f : .1f });
|
|
m_circle.draw_fill();
|
|
|
|
// draw black border
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 });
|
|
m_circle.draw_stroke();
|
|
}
|
|
|
|
if (depth) glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
void CanvasModeTransform::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
auto m2d = glm::scale(glm::vec3(1, -1, 1)) * canvas->m_proj *
|
|
canvas->m_mv * m_xform * m_xform_local;
|
|
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownR:
|
|
{
|
|
}
|
|
break;
|
|
case kEventType::MouseUpL:
|
|
m_dragging = false;
|
|
corner_hl = -1;
|
|
break;
|
|
case kEventType::MouseDownL:
|
|
corner_hl = -1;
|
|
corners2d.resize(corners.size());
|
|
for (int i = 0; i < corners.size(); i++)
|
|
{
|
|
auto c = m2d * glm::vec4(corners[i], 1);
|
|
corners2d[i] = ((xy(c) / c.z) * 0.5f + 0.5f) * zw(canvas->m_box);
|
|
float d = glm::distance(corners2d[i], loc);
|
|
if (d < 20.f * App::I.zoom)
|
|
corner_hl = i;
|
|
}
|
|
if (corner_hl != -1)
|
|
{
|
|
m_dragging = true;
|
|
m_drag_start = loc;
|
|
m_drag_xform = m_xform;
|
|
m_drag_xform_local = m_xform_local;
|
|
m_drag_corner = corner_hl;
|
|
m_drag_corners2d = corners2d;
|
|
if (m_drag_corner < 4)
|
|
{
|
|
m_drag_diag = glm::distance(corners2d[4], corners2d[m_drag_corner]);
|
|
}
|
|
}
|
|
break;
|
|
case kEventType::MouseMove:
|
|
{
|
|
corner_hl = -1;
|
|
corners2d.resize(corners.size());
|
|
for (int i = 0; i < corners.size(); i++)
|
|
{
|
|
auto c = m2d * glm::vec4(corners[i], 1);
|
|
corners2d[i] = ((xy(c) / c.z) * 0.5f + 0.5f) * zw(canvas->m_box);
|
|
float d = glm::distance(corners2d[i], loc);
|
|
if (d < 20.f * App::I.zoom)
|
|
corner_hl = i;
|
|
}
|
|
if (m_dragging)
|
|
{
|
|
auto cam_up = glm::inverse(canvas->m_mv) * glm::vec4(0, 1, 0, 1);
|
|
//auto diff = glm::radians(loc - m_drag_start) * 0.1f;
|
|
//auto m = glm::eulerAngleXY(-diff.y, -diff.x);
|
|
//m_xform = m * m_drag_xform;
|
|
if (m_drag_corner > -1 && m_drag_corner < 4)
|
|
{
|
|
auto diag = glm::distance(corners2d[4], loc);
|
|
auto scale = diag / m_drag_diag;
|
|
m_xform_local = m_drag_xform_local * glm::scale(glm::vec3(scale, scale, 1));
|
|
}
|
|
if (m_drag_corner == 4)
|
|
{
|
|
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, canvas->point_trace(loc), xyz(cam_up)));
|
|
}
|
|
if (m_drag_corner == 5)
|
|
{
|
|
auto a = glm::normalize(m_drag_corners2d[m_drag_corner] - m_drag_corners2d[4]);
|
|
auto b = glm::normalize(loc - m_drag_corners2d[4]);
|
|
auto angle = glm::orientedAngle(a, b);
|
|
m_xform_local = m_drag_xform_local * glm::eulerAngleZ(-angle);
|
|
}
|
|
}
|
|
/*
|
|
{
|
|
auto p2d = loc;
|
|
//p2d.y = canvas->m_box.w - p2d.y - 1;
|
|
auto p2d_clip = ((p2d / zw(canvas->m_box)) * 2.f - 1.f) * glm::vec2(1, -1);
|
|
auto p3d_plane = canvas->m_plane_unproject[0] * glm::vec4(p2d_clip, 0, 1);
|
|
auto p2d_plane = -p3d_plane / p3d_plane.z;
|
|
// auto p3d_world = canvas->m_plane_transform[0] * glm::vec4(p2d_plane, -1, 1);
|
|
int x = 0;
|
|
LOG("pt %f %f %f %f", p2d_plane.x, p2d_plane.y, p2d_plane.z, p2d_plane.w);
|
|
}
|
|
*/
|
|
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|