diff --git a/src/action.cpp b/src/action.cpp index 7ffdae7..89852c9 100644 --- a/src/action.cpp +++ b/src/action.cpp @@ -19,13 +19,19 @@ void ActionManager::undo() if (I.m_actions.empty()) return; - I.m_redos.emplace(I.m_actions.top()->get_redo()); - I.m_redos.top()->was_saved = !Canvas::I->m_unsaved; + if (auto action = I.m_actions.top()->get_redo()) + { + I.m_redos.emplace(action); + I.m_redos.top()->was_saved = !Canvas::I->m_unsaved; + } - I.m_actions.top()->undo(); - I.m_memory -= I.m_actions.top()->memory(); - Canvas::I->m_unsaved = !I.m_actions.top()->was_saved; - I.m_actions.pop(); + if (auto action = std::move(I.m_actions.top())) + { + I.m_actions.pop(); + action->undo(); + I.m_memory -= action->memory(); + Canvas::I->m_unsaved = !action->was_saved; + } //LOG("History: %.2f KB", I.m_memory / 1024.f); App::I->update_memory_usage(I.m_memory); App::I->title_update(); @@ -36,13 +42,19 @@ void ActionManager::redo() if (I.m_redos.empty()) return; - I.m_actions.emplace(I.m_redos.top()->get_redo()); - I.m_actions.top()->was_saved = !Canvas::I->m_unsaved; - I.m_memory += I.m_actions.top()->memory(); + if (auto action = I.m_redos.top()->get_redo()) + { + I.m_actions.emplace(action); + I.m_actions.top()->was_saved = !Canvas::I->m_unsaved; + I.m_memory += I.m_actions.top()->memory(); + } - I.m_redos.top()->undo(); - Canvas::I->m_unsaved = !I.m_redos.top()->was_saved; - I.m_redos.pop(); + if (auto action = std::move(I.m_redos.top())) + { + I.m_redos.pop(); + action->undo(); + Canvas::I->m_unsaved = !action->was_saved; + } //LOG("History: %.2f KB", I.m_memory / 1024.f); App::I->update_memory_usage(I.m_memory); App::I->title_update(); diff --git a/src/canvas.cpp b/src/canvas.cpp index a936aa3..eee3c89 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -117,6 +117,7 @@ void Canvas::clear(const glm::vec4& c/*={0,0,0,1}*/) { auto a = new ActionLayerClear; a->m_layer = m_layers[m_current_layer_idx]; + a->m_frame = layer().m_frame_index; a->m_snap = std::make_shared(a->m_layer->snapshot()); a->m_color = c; ActionManager::add(a); @@ -917,6 +918,7 @@ void Canvas::stroke_commit() // save history action->m_layer_idx = m_current_layer_idx; + action->m_frame_idx = layer().m_frame_index; action->m_canvas = this; //action->m_stroke = std::move(m_current_stroke); ActionManager::add(action); @@ -1680,7 +1682,7 @@ void Canvas::import_equirectangular(std::string file_path, std::shared_ptr layer /*= nullptr*/) +void Canvas::import_equirectangular_thread(std::string file_path, std::shared_ptr layer /*= nullptr*/, int frame /*= -1*/) { Image img; if (!img.load_file(file_path)) @@ -1688,10 +1690,14 @@ void Canvas::import_equirectangular_thread(std::string file_path, std::shared_pt if (!layer) layer = m_layers[m_current_layer_idx]; + + if (frame == -1) + frame = layer->m_frame_index; auto a = new ActionImportEquirect; a->m_layer = layer; - a->m_snap = std::make_shared(layer->snapshot()); + a->m_frame = frame; + a->m_snap = std::make_shared(layer->snapshot(frame)); a->m_path = file_path; ActionManager::add(a); @@ -1719,7 +1725,7 @@ void Canvas::import_equirectangular_thread(std::string file_path, std::shared_pt plane.draw_fill(); tex.unbind(); m_sampler.unbind(); - }); + }, frame, false); plane.destroy(); } else @@ -1740,7 +1746,7 @@ void Canvas::import_equirectangular_thread(std::string file_path, std::shared_pt sphere.draw_fill(); tex.unbind(); m_sampler.unbind(); - }); + }, frame, false); sphere.destroy(); } for (int i = 0; i < 6; i++) @@ -2557,7 +2563,7 @@ Image Canvas::thumbnail_read(std::string file_path) return thumb; } -void Canvas::draw_objects_direct(std::function observer, Layer& layer) +void Canvas::draw_objects_direct(std::function observer, Layer& layer, int frame) { App::I->render_task([&] { @@ -2582,16 +2588,16 @@ void Canvas::draw_objects_direct(std::function observer, Layer& layer) +void Canvas::draw_objects(std::function observer, Layer& layer, int frame, bool save_history) { App::I->render_task([&] { @@ -2632,8 +2638,13 @@ void Canvas::draw_objects(std::functionwas_saved = !m_unsaved; + ActionStroke* action; + + if (save_history) + { + action = new ActionStroke; + action->was_saved = !m_unsaved; + } glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f); for (int i = 0; i < 6; i++) @@ -2646,20 +2657,23 @@ void Canvas::draw_objects(std::function 0 && box_sz.y > 0; - if (has_data) - { - action->m_image[i] = std::make_unique(box_sz.x * box_sz.y * 4); - glReadPixels(bounds.x, bounds.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); - action->m_box[i] = bounds; - } - action->m_old_box[i] = layer.box(i); - action->m_old_dirty[i] = layer.face(i); + if (save_history) + { + // save image before commit + if (has_data) + { + action->m_image[i] = std::make_unique(box_sz.x * box_sz.y * 4); + glReadPixels(bounds.x, bounds.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); + action->m_box[i] = bounds; + } + action->m_old_box[i] = layer.box(i, frame); + action->m_old_dirty[i] = layer.face(i, frame); + } // draw the tmp layer into the actual layer if (has_data) @@ -2673,18 +2687,22 @@ void Canvas::draw_objects(std::functionm_layer_idx = m_current_layer_idx; - action->m_canvas = this; - //action->m_stroke = std::move(m_current_stroke); - ActionManager::add(action); + if (save_history) + { + // save history + action->m_layer_idx = m_current_layer_idx; + action->m_frame_idx = frame; + action->m_canvas = this; + //action->m_stroke = std::move(m_current_stroke); + ActionManager::add(action); + } glDeleteRenderbuffers(1, &rboID); rtt.destroy(); @@ -2697,9 +2715,9 @@ void Canvas::draw_objects(std::function observer) +void Canvas::draw_objects(std::function observer, int frame, bool save_history) { - draw_objects(observer, *m_layers[m_current_layer_idx]); + draw_objects(observer, layer(), frame, save_history); } void Canvas::project2Dpoints(std::vector& vertices) diff --git a/src/canvas.h b/src/canvas.h index 3695c8e..d75d40d 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -214,7 +214,7 @@ public: void snap_history(const std::vector& planes); void clear_context(); void import_equirectangular(std::string file_path, std::shared_ptr layer = nullptr); - void import_equirectangular_thread(std::string file_path, std::shared_ptr layer = nullptr); + void import_equirectangular_thread(std::string file_path, std::shared_ptr layer = nullptr, int frame = -1); void export_equirectangular(std::string file_path, std::function on_complete = nullptr); void export_equirectangular_thread(std::string file_path); void export_layers(std::string path, std::function on_complete = nullptr); @@ -231,9 +231,9 @@ public: void inject_xmp(std::string jpg_path); Image thumbnail_generate(int w, int h); Image thumbnail_read(std::string file_path); - void draw_objects(std::function); - void draw_objects(std::function, Layer& layer); - void draw_objects_direct(std::function, Layer& layer); + void draw_objects(std::function, int frame, bool save_history); + void draw_objects(std::function, Layer& layer, int frame, bool save_history); + void draw_objects_direct(std::function, Layer& layer, int frame); void point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj, glm::vec3 &out_origin, glm::vec3 &out_dir); void point_unproject(glm::vec2 loc, glm::vec3 &out_origin, glm::vec3 &out_dir); diff --git a/src/canvas_actions.cpp b/src/canvas_actions.cpp index 71fabdd..c76f3e9 100644 --- a/src/canvas_actions.cpp +++ b/src/canvas_actions.cpp @@ -8,7 +8,7 @@ void ActionStroke::undo() { if (clear_layer) - m_canvas->m_layers[m_layer_idx]->clear({ 0, 0, 0, 0 }); + m_canvas->m_layers[m_layer_idx]->clear({ 0, 0, 0, 0 }, m_frame_idx); for (int i = 0; i < 6; i++) { // empty data @@ -17,18 +17,18 @@ void ActionStroke::undo() LOG("undo box %d dirty=%s [%d,%d,%d,%d] to dirty=%s [%d,%d,%d,%d]", i, - m_canvas->m_layers[m_layer_idx]->face(i) ? "true" : "false", - (int)m_canvas->m_layers[m_layer_idx]->box(i).x, - (int)m_canvas->m_layers[m_layer_idx]->box(i).y, - (int)m_canvas->m_layers[m_layer_idx]->box(i).z, - (int)m_canvas->m_layers[m_layer_idx]->box(i).w, + m_canvas->m_layers[m_layer_idx]->face(i, m_frame_idx) ? "true" : "false", + (int)m_canvas->m_layers[m_layer_idx]->box(i, m_frame_idx).x, + (int)m_canvas->m_layers[m_layer_idx]->box(i, m_frame_idx).y, + (int)m_canvas->m_layers[m_layer_idx]->box(i, m_frame_idx).z, + (int)m_canvas->m_layers[m_layer_idx]->box(i, m_frame_idx).w, m_old_dirty[i] ? "true" : "false", (int)m_old_box[i].x, (int)m_old_box[i].y, (int)m_old_box[i].z, (int)m_old_box[i].w); - m_canvas->m_layers[m_layer_idx]->box(i) = m_old_box[i]; - m_canvas->m_layers[m_layer_idx]->face(i) = m_old_dirty[i]; + m_canvas->m_layers[m_layer_idx]->box(i, m_frame_idx) = m_old_box[i]; + m_canvas->m_layers[m_layer_idx]->face(i, m_frame_idx) = m_old_dirty[i]; glm::vec2 box_sz = zw(m_box[i]) - xy(m_box[i]); @@ -36,9 +36,9 @@ void ActionStroke::undo() { App::I->render_task([&] { - m_canvas->m_layers[m_layer_idx]->rtt(i).bindTexture(); + m_canvas->m_layers[m_layer_idx]->rtt(i, m_frame_idx).bindTexture(); glTexSubImage2D(GL_TEXTURE_2D, 0, (int)m_box[i].x, (int)m_box[i].y, (int)box_sz.x, (int)box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get()); - m_canvas->m_layers[m_layer_idx]->rtt(i).unbindTexture(); + m_canvas->m_layers[m_layer_idx]->rtt(i, m_frame_idx).unbindTexture(); }); } else @@ -65,7 +65,7 @@ Action* ActionStroke::get_redo() auto& layer = m_canvas->m_layers[m_layer_idx]; for (int i = 0; i < 6; i++) { - if (!layer->face(i) && !m_image[i]) + if (!layer->face(i, m_frame_idx) && !m_image[i]) continue; // no stroke on this face, skip it @@ -79,9 +79,9 @@ Action* ActionStroke::get_redo() action->m_image[i] = std::make_unique(box_sz.x * box_sz.y * 4); App::I->render_task([&] { - layer->rtt(i).bindFramebuffer(); + layer->rtt(i, m_frame_idx).bindFramebuffer(); glReadPixels(box_or.x, box_or.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); - layer->rtt(i).unbindFramebuffer(); + layer->rtt(i, m_frame_idx).unbindFramebuffer(); }); } else @@ -90,11 +90,12 @@ Action* ActionStroke::get_redo() } action->m_box[i] = box; - action->m_old_box[i] = layer->box(i); - action->m_old_dirty[i] = layer->face(i); + action->m_old_box[i] = layer->box(i, m_frame_idx); + action->m_old_dirty[i] = layer->face(i, m_frame_idx); } // save history action->m_layer_idx = m_layer_idx; + action->m_frame_idx = m_frame_idx; action->m_canvas = m_canvas; //action->m_stroke = std::move(m_stroke); action->clear_layer = false; @@ -109,6 +110,7 @@ Action* ActionLayerClear::get_redo() a->m_direction = reverse_direction(); a->m_snap = m_snap; a->m_layer = m_layer; + a->m_frame = m_frame; a->m_color = m_color; return a; } @@ -117,11 +119,11 @@ void ActionLayerClear::undo() { if (m_direction == Direction::Undo) { - m_layer->restore(*m_snap); + m_layer->restore(*m_snap, m_frame); } else { - m_layer->clear(m_color); + m_layer->clear(m_color, m_frame); } } @@ -129,22 +131,27 @@ void ActionLayerClear::undo() Action* ActionImportEquirect::get_redo() { - auto a = new ActionImportEquirect; - a->m_direction = reverse_direction(); - a->m_snap = m_snap; - a->m_layer = m_layer; - a->m_path = m_path; - return a; + if (m_direction == Direction::Undo) + { + auto a = new ActionImportEquirect; + a->m_direction = reverse_direction(); + a->m_snap = m_snap; + a->m_layer = m_layer; + a->m_frame = m_frame; + a->m_path = m_path; + return a; + } + return nullptr; } void ActionImportEquirect::undo() { if (m_direction == Direction::Undo) { - m_layer->restore(*m_snap); + m_layer->restore(*m_snap, m_frame); } else { - Canvas::I->import_equirectangular_thread(m_path, m_layer); + Canvas::I->import_equirectangular_thread(m_path, m_layer, m_frame); } } diff --git a/src/canvas_actions.h b/src/canvas_actions.h index d354b2a..d973fe8 100644 --- a/src/canvas_actions.h +++ b/src/canvas_actions.h @@ -11,6 +11,7 @@ public: glm::ivec4 m_box[6] = SIXPLETTE(glm::ivec4(0)); bool clear_layer = false; int m_layer_idx = 0; + int m_frame_idx = 0; class Canvas* m_canvas; virtual ~ActionStroke() = default; virtual void run() override { } @@ -23,6 +24,7 @@ struct ActionLayerClear : public Action { std::shared_ptr m_snap; std::shared_ptr m_layer; + int m_frame = 0; glm::vec4 m_color; virtual void run() override { } virtual size_t memory() override { return m_snap->memsize(); } @@ -34,6 +36,7 @@ struct ActionImportEquirect : public Action { std::shared_ptr m_snap; std::shared_ptr m_layer; + int m_frame = 0; std::string m_path; virtual void run() override { } virtual size_t memory() override { return m_snap->memsize(); } diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 6e2bba8..26912b6 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -583,7 +583,7 @@ void CanvasModeGrid::commit() m_line.update_vertices(AB); m_line.draw_stroke(); }; - Canvas::I->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2)); + Canvas::I->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->layer().m_frame_index, true); } void CanvasModeGrid::clear() @@ -714,7 +714,7 @@ void CanvasModeMaskFree::on_MouseEvent(MouseEvent* me, glm::vec2& loc) auto v = triangulate(poly_remove_duplicate(m_points2d)); Canvas::I->project2Dpoints(v); m_shape.update_vertices(v.data(), (int)v.size()); - Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask); + Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0); // close the path and reset m_shape to contour rendering m_points.push_back(m_points.back()); @@ -844,7 +844,7 @@ void CanvasModeMaskLine::leave(kCanvasMode next) ShaderManager::u_vec4(kShaderUniform::Col, {1, 1, 1, 1}); m_shape.draw_fill(); }; - Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask); + Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0); //m_points.clear(); // close the path @@ -977,7 +977,7 @@ void CanvasModeFill::leave(kCanvasMode next) ShaderManager::u_vec4(kShaderUniform::Col, {1, 1, 1, 1}); m_shape.draw_fill(); }; - Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask); + Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0); m_points.clear(); Canvas::I->m_smask_active = true; } @@ -1321,6 +1321,7 @@ void CanvasModeTransform::enter(kCanvasMode prev) } action->m_layer_idx = Canvas::I->m_current_layer_idx; + action->m_frame_idx = Canvas::I->layer().m_frame_index; action->m_canvas = Canvas::I; //action->m_stroke = std::move(m_current_stroke); ActionManager::add(action); @@ -1443,6 +1444,7 @@ void CanvasModeTransform::leave(kCanvasMode next) action->m_layer_idx = Canvas::I->m_current_layer_idx; action->m_canvas = Canvas::I; + action->m_frame_idx = Canvas::I->layer().m_frame_index; //action->m_stroke = std::move(m_current_stroke); ActionManager::add(action); layer->optimize(); diff --git a/src/log.cpp b/src/log.cpp index 67c0646..99e002f 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -119,8 +119,7 @@ void LogRemote::log(const char* format, ...) m_tmp.push_back(line); } #if _WIN32 - auto line_console = "DBG: " + line; - OutputDebugStringA(line_console.c_str()); + OutputDebugStringA(("DBG: " + line).c_str()); #endif } void LogRemote::log(const wchar_t* format, ...) diff --git a/src/node_panel_grid.cpp b/src/node_panel_grid.cpp index 6a15668..b6e76c9 100644 --- a/src/node_panel_grid.cpp +++ b/src/node_panel_grid.cpp @@ -139,7 +139,7 @@ void NodePanelGrid::init_controls() { Canvas::I->draw_objects([this](const glm::mat4& camera, const glm::mat4& proj, int i) { draw_heightmap(proj, camera, true); - }); + }, Canvas::I->layer().m_frame_index, true); m_groud_opacity->set_value(0); }; m_hm_texres->on_select = [this](Node*, int index) {