From 4e765f1450caaab634db219644243fd70837b41c Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 15 Jul 2017 10:51:58 +0100 Subject: [PATCH] Trying to add history to the Fill tool --- engine/app_shaders.cpp | 2 +- engine/canvas.cpp | 49 +++++++++++++++++++++++++++-- engine/canvas.h | 6 +++- engine/canvas_modes.cpp | 70 ++++++++++++++++++++++++++++++++++------- engine/canvas_modes.h | 1 + engine/util.cpp | 1 + 6 files changed, 112 insertions(+), 17 deletions(-) diff --git a/engine/app_shaders.cpp b/engine/app_shaders.cpp index 0f5b53a..b3b594f 100644 --- a/engine/app_shaders.cpp +++ b/engine/app_shaders.cpp @@ -73,7 +73,7 @@ void App::initShaders() "in vec4 pos;" "void main(){" " gl_Position = mvp * pos;" - " gl_PointSize = 15.0;" + " gl_PointSize = 5.0;" "}"; static const char* shader_color_f = SHADER_VERSION diff --git a/engine/canvas.cpp b/engine/canvas.cpp index ec66883..225dad4 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -46,8 +46,37 @@ glm::mat4 ui::Canvas::m_plane_transform[6] = { void ui::Canvas::clear(const glm::vec4& c/*={0,0,0,1}*/) { + snap_history({ 0, 1, 2, 3, 4, 5 }); m_layers[m_current_layer_idx].clear(c); } +void ui::Canvas::snap_history(const std::vector& planes) +{ + auto action = new ActionStroke; + for (auto i : planes) + { + if (!m_dirty_face[i]) + continue; // no stroke on this face, skip it + + m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer(); + + // save image before commit + glm::vec2 box_sz = m_dirty_box[i].zw() - m_dirty_box[i].xy(); + action->m_image[i] = std::make_unique(box_sz.x * box_sz.y * 4); + glReadPixels(m_dirty_box[i].x, m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); + + action->m_box[i] = m_dirty_box[i]; + action->m_old_box[i] = m_layers[m_current_layer_idx].m_dirty_box[i]; + action->m_old_dirty[i] = m_layers[m_current_layer_idx].m_dirty_face[i]; + + m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer(); + } + // save history + action->m_layer_idx = m_current_layer_idx; + action->m_canvas = this; + action->m_stroke = std::move(m_current_stroke); + action->clear_layer = true; + ActionManager::add(action); +} void ui::Canvas::stroke_end() { if (!m_current_stroke) @@ -268,7 +297,7 @@ bool ui::Canvas::point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ra return false; } bool ui::Canvas::point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, - glm::vec3& hit_pos, glm::vec3& hit_normal, int plane_id) + glm::vec3& hit_pos, glm::vec3& hit_normal, glm::vec2& hit_fb_pos, int plane_id) { point_unproject(loc, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir); glm::vec3 hit; @@ -277,8 +306,11 @@ bool ui::Canvas::point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::ve m_plane_normal[plane_id], m_plane_tangent[plane_id], hit)) { glm::mat4 plane_camera = glm::lookAt(m_plane_origin[plane_id], m_plane_normal[plane_id], m_plane_tangent[plane_id]); + glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1); hit_pos = hit; hit_normal = m_plane_normal[plane_id]; + hit_fb_pos.x = -(plane_local.x * 0.5f - 0.5f); + hit_fb_pos.y = (plane_local.y * 0.5f + 0.5f); return true; } return false; @@ -330,6 +362,7 @@ void ui::Canvas::stroke_commit() for (int i = 0; i < 6; i++) { + m_dirty_box[i] = glm::vec4(0, 0, m_width, m_height); // reset bounding box if (!m_dirty_face[i]) continue; // no stroke on this face, skip it @@ -1067,14 +1100,24 @@ void ui::Layer::clear(const glm::vec4& c) glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glClearColor(c.r, c.g, c.b, c.a); + bool erase = (c.a == 0.f); + for (int i = 0; i < 6; i++) { m_rtt[i].bindFramebuffer(); glClear(GL_COLOR_BUFFER_BIT); m_rtt[i].unbindFramebuffer(); - m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box - m_dirty_face[i] = false; + if (erase) + { + m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box + m_dirty_face[i] = false; + } + else + { + m_dirty_box[i] = glm::vec4(0, 0, w, h); // reset bounding box + m_dirty_face[i] = true; + } } // restore clear color state diff --git a/engine/canvas.h b/engine/canvas.h index 387cb71..641393b 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -106,6 +106,7 @@ public: void clear(const glm::vec4& color = { 1, 1, 1, 0 }); void snapshot_save(std::string data_path); void snapshot_restore(); + void snap_history(const std::vector& planes); void clear_context(); void export_equirectangular(std::string data_path); void export_anim(std::string data_path); @@ -122,7 +123,7 @@ public: bool point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, glm::vec3& hit_pos, glm::vec3& hit_normal, int& out_plane_id); bool point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, - glm::vec3& hit_pos, glm::vec3& hit_normal, int plane_id); + glm::vec3& hit_pos, glm::vec3& hit_normal, glm::vec2& hit_fb_pos, int plane_id); }; class ActionStroke : public Action @@ -134,6 +135,7 @@ public: bool m_old_dirty[6]; glm::ivec4 m_box[6]; bool m_dirty[6]; + bool clear_layer = false; int m_layer_idx; Canvas* m_canvas; virtual void run() override @@ -142,6 +144,8 @@ public: } virtual void undo() override { + if (clear_layer) + m_canvas->m_layers[m_layer_idx].clear({ 0, 0, 0, 0 }); for (int i = 0; i < 6; i++) { // empty data diff --git a/engine/canvas_modes.cpp b/engine/canvas_modes.cpp index 9bc0eac..c9654ff 100644 --- a/engine/canvas_modes.cpp +++ b/engine/canvas_modes.cpp @@ -254,7 +254,8 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc) case kEventType::MouseMove: { glm::vec3 ro, rd, hit_o, hit_d; - if (m_dragging && canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, m_plane_id)) + 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; @@ -326,8 +327,34 @@ void CanvasModeFill::init() void CanvasModeFill::leave() { - canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2)); - m_points.clear(); +// canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2)); +// m_points.clear(); +} + +// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines +// intersect the intersection point may be stored in the floats i_x and i_y. +char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, + float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y) +{ + float s1_x, s1_y, s2_x, s2_y; + s1_x = p1_x - p0_x; s1_y = p1_y - p0_y; + s2_x = p3_x - p2_x; s2_y = p3_y - p2_y; + + float s, t; + s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y); + t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); + + if (s >= 0 && s <= 1 && t >= 0 && t <= 1) + { + // Collision detected + if (i_x != NULL) + *i_x = p0_x + (t * s1_x); + if (i_y != NULL) + *i_y = p0_y + (t * s1_y); + return 1; + } + + return 0; // No collision } void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) @@ -336,14 +363,26 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { case kEventType::MouseDownR: { - 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, { node->m_brush.m_tip_color.rgb(), node->m_brush.m_tip_opacity }); - m_shape.draw_fill(); - }; - canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2)); - m_points.clear(); + if (!m_points.empty()) + { + 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, { node->m_brush.m_tip_color.rgb(), node->m_brush.m_tip_opacity }); + m_shape.draw_fill(); + }; + std::vector 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)); + m_points.clear(); + m_dirty_planes.clear(); + } break; } case kEventType::MouseDownL: @@ -351,9 +390,11 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) 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(loc, ro, rd, hit_o, hit_d, 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); @@ -367,6 +408,11 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) 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()); } diff --git a/engine/canvas_modes.h b/engine/canvas_modes.h index 3abe67d..886976b 100644 --- a/engine/canvas_modes.h +++ b/engine/canvas_modes.h @@ -87,6 +87,7 @@ class CanvasModeFill : public CanvasMode ui::DynamicShape m_shape; bool m_dragging = false; std::vector m_points; + std::map m_dirty_planes; public: virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override; virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override; diff --git a/engine/util.cpp b/engine/util.cpp index 2810214..b8230d6 100644 --- a/engine/util.cpp +++ b/engine/util.cpp @@ -60,6 +60,7 @@ double now_seconds() time(&timer); /* get current time; same as: timer = time(NULL) */ seconds = difftime(timer, mktime(&y2k)); + return seconds; } void check_OpenGLError(const char* stmt, const char* fname, int line)