mirror of
https://github.com/Nexoniarz/Fry3DX.git
synced 2026-11-03 04:24:26 +00:00
Lighter undo: a step keeps the objects without their shapes, the shapes (points, faces, painting layout) shared with the steps where they're the same (compared, not trusted to a version)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
9918d9a770
commit
93c65638d8
1 changed files with 37 additions and 5 deletions
42
src/app.cpp
42
src/app.cpp
|
|
@ -778,8 +778,16 @@ private:
|
||||||
Scene scene_;
|
Scene scene_;
|
||||||
std::string startPath_, path_;
|
std::string startPath_, path_;
|
||||||
bool dirty_ = false;
|
bool dirty_ = false;
|
||||||
|
// An undo step. Its objects without their shapes (points, faces, painting's layout): those are
|
||||||
|
// kept apart and shared with the steps before and after where they're the same, so a step
|
||||||
|
// that moved one thing doesn't copy every shape in the scene again.
|
||||||
|
struct Shape {
|
||||||
|
std::shared_ptr<const Mesh> mesh;
|
||||||
|
std::shared_ptr<const std::vector<std::vector<glm::vec2>>> uvs;
|
||||||
|
};
|
||||||
struct Snapshot {
|
struct Snapshot {
|
||||||
Scene scene;
|
Scene scene;
|
||||||
|
std::map<uint32_t, Shape> shapes;
|
||||||
std::set<uint32_t> selected;
|
std::set<uint32_t> selected;
|
||||||
uint32_t active;
|
uint32_t active;
|
||||||
Mode mode;
|
Mode mode;
|
||||||
|
|
@ -789,6 +797,27 @@ private:
|
||||||
double at = 0;
|
double at = 0;
|
||||||
};
|
};
|
||||||
std::vector<Snapshot> undo_, redo_;
|
std::vector<Snapshot> undo_, redo_;
|
||||||
|
std::map<uint32_t, Shape> lastShapes_; // (each object's shape as last kept: the next step shares it if it's the same)
|
||||||
|
Snapshot snapshot(std::string label, double at) {
|
||||||
|
Snapshot s;
|
||||||
|
s.scene.look = scene_.look, s.scene.folders = scene_.folders, s.scene.references = scene_.references, s.scene.nextId = scene_.nextId; // (not the scripts: not undone)
|
||||||
|
s.scene.objects.reserve(scene_.objects.size());
|
||||||
|
std::map<uint32_t, Shape> kept;
|
||||||
|
for (Object& o : scene_.objects) {
|
||||||
|
Mesh mesh = std::move(o.mesh);
|
||||||
|
auto uvs = std::move(o.uvs);
|
||||||
|
s.scene.objects.push_back(o); // (all but its shape)
|
||||||
|
o.mesh = std::move(mesh), o.uvs = std::move(uvs);
|
||||||
|
Shape k = lastShapes_.count(o.id) ? lastShapes_[o.id] : Shape{};
|
||||||
|
if (!k.mesh || k.mesh->verts != o.mesh.verts || k.mesh->faces != o.mesh.faces) k.mesh = std::make_shared<const Mesh>(o.mesh);
|
||||||
|
if (!k.uvs || *k.uvs != o.uvs) k.uvs = std::make_shared<const std::vector<std::vector<glm::vec2>>>(o.uvs);
|
||||||
|
s.shapes[o.id] = kept[o.id] = k;
|
||||||
|
}
|
||||||
|
lastShapes_ = std::move(kept); // (gone objects' shapes: only in the steps that have them)
|
||||||
|
s.selected = selected_, s.active = active_, s.mode = mode_, s.verts = selVerts_, s.faces = selFaces_, s.edges = selEdges_;
|
||||||
|
s.label = std::move(label), s.at = at;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
std::vector<Snapshot> redoKept_; // (what redo had before the last undo point: back if that step is dropped)
|
std::vector<Snapshot> redoKept_; // (what redo had before the last undo point: back if that step is dropped)
|
||||||
|
|
||||||
Mode mode_ = Mode::Object;
|
Mode mode_ = Mode::Object;
|
||||||
|
|
@ -1099,7 +1128,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushUndo() {
|
void pushUndo() {
|
||||||
undo_.push_back({scene_, selected_, active_, mode_, selVerts_, selFaces_, selEdges_, "", now()});
|
undo_.push_back(snapshot("", now()));
|
||||||
if (undo_.size() > 200) undo_.erase(undo_.begin());
|
if (undo_.size() > 200) undo_.erase(undo_.begin());
|
||||||
redoKept_ = std::move(redo_), redo_.clear();
|
redoKept_ = std::move(redo_), redo_.clear();
|
||||||
dirty_ = true, ++edits_;
|
dirty_ = true, ++edits_;
|
||||||
|
|
@ -1120,6 +1149,9 @@ private:
|
||||||
std::vector<fry::SceneScript> scripts = std::move(scene_.scripts);
|
std::vector<fry::SceneScript> scripts = std::move(scene_.scripts);
|
||||||
scene_ = s.scene, selected_ = s.selected, active_ = s.active, mode_ = s.mode, followAt_.clear();
|
scene_ = s.scene, selected_ = s.selected, active_ = s.active, mode_ = s.mode, followAt_.clear();
|
||||||
scene_.scripts = std::move(scripts);
|
scene_.scripts = std::move(scripts);
|
||||||
|
for (Object& o : scene_.objects)
|
||||||
|
if (auto it = s.shapes.find(o.id); it != s.shapes.end()) o.mesh = *it->second.mesh, o.uvs = *it->second.uvs;
|
||||||
|
lastShapes_ = s.shapes;
|
||||||
selVerts_ = s.verts, selFaces_ = s.faces, selEdges_ = s.edges;
|
selVerts_ = s.verts, selFaces_ = s.faces, selEdges_ = s.edges;
|
||||||
if (mode_ == Mode::Edit && !find(active_)) mode_ = Mode::Object;
|
if (mode_ == Mode::Edit && !find(active_)) mode_ = Mode::Object;
|
||||||
touchAll();
|
touchAll();
|
||||||
|
|
@ -1127,14 +1159,14 @@ private:
|
||||||
}
|
}
|
||||||
void undo() {
|
void undo() {
|
||||||
if (undo_.empty()) return say("Nothing to undo");
|
if (undo_.empty()) return say("Nothing to undo");
|
||||||
redo_.push_back({scene_, selected_, active_, mode_, selVerts_, selFaces_, selEdges_, undo_.back().label, now()}); // (its name: the step it brings back)
|
redo_.push_back(snapshot(undo_.back().label, now())); // (its name: the step it brings back)
|
||||||
restore(undo_.back());
|
restore(undo_.back());
|
||||||
undo_.pop_back();
|
undo_.pop_back();
|
||||||
redoKept_.clear();
|
redoKept_.clear();
|
||||||
}
|
}
|
||||||
void redo() {
|
void redo() {
|
||||||
if (redo_.empty()) return say("Nothing to redo");
|
if (redo_.empty()) return say("Nothing to redo");
|
||||||
undo_.push_back({scene_, selected_, active_, mode_, selVerts_, selFaces_, selEdges_, redo_.back().label, now() - 10});
|
undo_.push_back(snapshot(redo_.back().label, now() - 10));
|
||||||
restore(redo_.back());
|
restore(redo_.back());
|
||||||
redo_.pop_back();
|
redo_.pop_back();
|
||||||
redoKept_.clear();
|
redoKept_.clear();
|
||||||
|
|
@ -1144,7 +1176,7 @@ private:
|
||||||
scene_ = {}, followAt_.clear();
|
scene_ = {}, followAt_.clear();
|
||||||
script_ = 0, scriptPath_.clear();
|
script_ = 0, scriptPath_.clear();
|
||||||
path_.clear();
|
path_.clear();
|
||||||
undo_.clear(), redo_.clear(), selected_.clear();
|
undo_.clear(), redo_.clear(), selected_.clear(), lastShapes_.clear();
|
||||||
mode_ = Mode::Object, active_ = 0;
|
mode_ = Mode::Object, active_ = 0;
|
||||||
addShape("cube", false);
|
addShape("cube", false);
|
||||||
dirty_ = false;
|
dirty_ = false;
|
||||||
|
|
@ -1316,7 +1348,7 @@ private:
|
||||||
std::erase_if(o.layers, [](const PictureLayer& l) { return !l.image; });
|
std::erase_if(o.layers, [](const PictureLayer& l) { return !l.image; });
|
||||||
}
|
}
|
||||||
path_ = picked;
|
path_ = picked;
|
||||||
undo_.clear(), redo_.clear(), selected_.clear();
|
undo_.clear(), redo_.clear(), selected_.clear(), lastShapes_.clear();
|
||||||
mode_ = Mode::Object, active_ = 0, dirty_ = false, ledit_ = {};
|
mode_ = Mode::Object, active_ = 0, dirty_ = false, ledit_ = {};
|
||||||
touchAll();
|
touchAll();
|
||||||
frameAll();
|
frameAll();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue