Trying to add history to the Fill tool
This commit is contained in:
@@ -73,7 +73,7 @@ void App::initShaders()
|
|||||||
"in vec4 pos;"
|
"in vec4 pos;"
|
||||||
"void main(){"
|
"void main(){"
|
||||||
" gl_Position = mvp * pos;"
|
" gl_Position = mvp * pos;"
|
||||||
" gl_PointSize = 15.0;"
|
" gl_PointSize = 5.0;"
|
||||||
"}";
|
"}";
|
||||||
static const char* shader_color_f =
|
static const char* shader_color_f =
|
||||||
SHADER_VERSION
|
SHADER_VERSION
|
||||||
|
|||||||
@@ -46,8 +46,37 @@ glm::mat4 ui::Canvas::m_plane_transform[6] = {
|
|||||||
|
|
||||||
void ui::Canvas::clear(const glm::vec4& c/*={0,0,0,1}*/)
|
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);
|
m_layers[m_current_layer_idx].clear(c);
|
||||||
}
|
}
|
||||||
|
void ui::Canvas::snap_history(const std::vector<int>& 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<uint8_t[]>(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()
|
void ui::Canvas::stroke_end()
|
||||||
{
|
{
|
||||||
if (!m_current_stroke)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
bool ui::Canvas::point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
|
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);
|
point_unproject(loc, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir);
|
||||||
glm::vec3 hit;
|
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))
|
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::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_pos = hit;
|
||||||
hit_normal = m_plane_normal[plane_id];
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -330,6 +362,7 @@ void ui::Canvas::stroke_commit()
|
|||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
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])
|
if (!m_dirty_face[i])
|
||||||
continue; // no stroke on this face, skip it
|
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);
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||||
glClearColor(c.r, c.g, c.b, c.a);
|
glClearColor(c.r, c.g, c.b, c.a);
|
||||||
|
|
||||||
|
bool erase = (c.a == 0.f);
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
m_rtt[i].bindFramebuffer();
|
m_rtt[i].bindFramebuffer();
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
m_rtt[i].unbindFramebuffer();
|
m_rtt[i].unbindFramebuffer();
|
||||||
|
|
||||||
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
if (erase)
|
||||||
m_dirty_face[i] = false;
|
{
|
||||||
|
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
|
// restore clear color state
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ public:
|
|||||||
void clear(const glm::vec4& color = { 1, 1, 1, 0 });
|
void clear(const glm::vec4& color = { 1, 1, 1, 0 });
|
||||||
void snapshot_save(std::string data_path);
|
void snapshot_save(std::string data_path);
|
||||||
void snapshot_restore();
|
void snapshot_restore();
|
||||||
|
void snap_history(const std::vector<int>& planes);
|
||||||
void clear_context();
|
void clear_context();
|
||||||
void export_equirectangular(std::string data_path);
|
void export_equirectangular(std::string data_path);
|
||||||
void export_anim(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,
|
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);
|
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,
|
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
|
class ActionStroke : public Action
|
||||||
@@ -134,6 +135,7 @@ public:
|
|||||||
bool m_old_dirty[6];
|
bool m_old_dirty[6];
|
||||||
glm::ivec4 m_box[6];
|
glm::ivec4 m_box[6];
|
||||||
bool m_dirty[6];
|
bool m_dirty[6];
|
||||||
|
bool clear_layer = false;
|
||||||
int m_layer_idx;
|
int m_layer_idx;
|
||||||
Canvas* m_canvas;
|
Canvas* m_canvas;
|
||||||
virtual void run() override
|
virtual void run() override
|
||||||
@@ -142,6 +144,8 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void undo() override
|
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++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
// empty data
|
// empty data
|
||||||
|
|||||||
@@ -254,7 +254,8 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
case kEventType::MouseMove:
|
case kEventType::MouseMove:
|
||||||
{
|
{
|
||||||
glm::vec3 ro, rd, hit_o, hit_d;
|
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 };
|
m_lines.back() = { hit_o, hit_d };
|
||||||
origin = hit_o;
|
origin = hit_o;
|
||||||
@@ -326,8 +327,34 @@ void CanvasModeFill::init()
|
|||||||
|
|
||||||
void CanvasModeFill::leave()
|
void CanvasModeFill::leave()
|
||||||
{
|
{
|
||||||
canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2));
|
// canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2));
|
||||||
m_points.clear();
|
// 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)
|
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:
|
case kEventType::MouseDownR:
|
||||||
{
|
{
|
||||||
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
|
if (!m_points.empty())
|
||||||
ui::ShaderManager::use(ui::kShader::Color);
|
{
|
||||||
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
|
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
|
||||||
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { node->m_brush.m_tip_color.rgb(), node->m_brush.m_tip_opacity });
|
ui::ShaderManager::use(ui::kShader::Color);
|
||||||
m_shape.draw_fill();
|
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 });
|
||||||
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2));
|
m_shape.draw_fill();
|
||||||
m_points.clear();
|
};
|
||||||
|
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));
|
||||||
|
m_points.clear();
|
||||||
|
m_dirty_planes.clear();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kEventType::MouseDownL:
|
case kEventType::MouseDownL:
|
||||||
@@ -351,9 +390,11 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
node->mouse_capture();
|
node->mouse_capture();
|
||||||
m_dragging = true;
|
m_dragging = true;
|
||||||
glm::vec3 ro, rd, hit_o, hit_d;
|
glm::vec3 ro, rd, hit_o, hit_d;
|
||||||
|
glm::vec2 hit_fb;
|
||||||
int plane_id;
|
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;
|
ui::Shape::vertex_t v;
|
||||||
v.pos = glm::vec4(hit_o, 1);
|
v.pos = glm::vec4(hit_o, 1);
|
||||||
v.uvs = glm::vec2(0);
|
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(m_points[0]);
|
||||||
m_points.push_back(last);
|
m_points.push_back(last);
|
||||||
m_points.push_back(v);
|
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_shape.update_vertices(m_points.data(), m_points.size());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ class CanvasModeFill : public CanvasMode
|
|||||||
ui::DynamicShape m_shape;
|
ui::DynamicShape m_shape;
|
||||||
bool m_dragging = false;
|
bool m_dragging = false;
|
||||||
std::vector<ui::Shape::vertex_t> m_points;
|
std::vector<ui::Shape::vertex_t> m_points;
|
||||||
|
std::map<int, int> m_dirty_planes;
|
||||||
public:
|
public:
|
||||||
virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override;
|
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;
|
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ double now_seconds()
|
|||||||
|
|
||||||
time(&timer); /* get current time; same as: timer = time(NULL) */
|
time(&timer); /* get current time; same as: timer = time(NULL) */
|
||||||
seconds = difftime(timer, mktime(&y2k));
|
seconds = difftime(timer, mktime(&y2k));
|
||||||
|
return seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_OpenGLError(const char* stmt, const char* fname, int line)
|
void check_OpenGLError(const char* stmt, const char* fname, int line)
|
||||||
|
|||||||
Reference in New Issue
Block a user