undo.cpp 10.8 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3

#include "undo.h"
#include "../gui/animate.h"
TheNumbat's avatar
TheNumbat committed
4
#include "../gui/manager.h"
TheNumbat's avatar
TheNumbat committed
5
6
#include "../gui/rig.h"

TheNumbat's avatar
TheNumbat committed
7
Undo::Undo(Scene &sc, Gui::Manager &man) : scene(sc), gui(man) {}
TheNumbat's avatar
TheNumbat committed
8
9
10
11
12
13

void Undo::reset() {
    undos = {};
    redos = {};
}

TheNumbat's avatar
TheNumbat committed
14
template <typename R, typename U> class Action : public Action_Base {
TheNumbat's avatar
TheNumbat committed
15
public:
TheNumbat's avatar
TheNumbat committed
16
17
    Action(R &&r, U &&u)
        : _undo(std::forward<decltype(u)>(u)), _redo(std::forward<decltype(r)>(r)){};
TheNumbat's avatar
TheNumbat committed
18
19
20
21
22
    ~Action() {}

private:
    U _undo;
    R _redo;
TheNumbat's avatar
TheNumbat committed
23
24
    void undo() { _undo(); }
    void redo() { _redo(); }
TheNumbat's avatar
TheNumbat committed
25
26
};

TheNumbat's avatar
TheNumbat committed
27
28
template <typename R, typename U> void Undo::action(R &&redo, U &&undo) {
    action(std::make_unique<Action<R, U>>(std::move(redo), std::move(undo)));
TheNumbat's avatar
TheNumbat committed
29
30
}

TheNumbat's avatar
TheNumbat committed
31
32
33
void Undo::update_mesh_full(Scene_ID id, Halfedge_Mesh &&old_mesh) {

    Scene_Object &obj = scene.get_obj(id);
TheNumbat's avatar
TheNumbat committed
34
35
36
    Halfedge_Mesh new_mesh;
    obj.copy_mesh(new_mesh);

TheNumbat's avatar
TheNumbat committed
37
38
39
40
41
42
43
44
45
    action(
        [id, this, nm = std::move(new_mesh)]() mutable {
            Scene_Object &obj = scene.get_obj(id);
            obj.set_mesh(nm);
        },
        [id, this, om = std::move(old_mesh)]() mutable {
            Scene_Object &obj = scene.get_obj(id);
            obj.set_mesh(om);
        });
TheNumbat's avatar
TheNumbat committed
46
47
48
}

void Undo::move_root(Scene_ID id, Vec3 old) {
TheNumbat's avatar
TheNumbat committed
49
50

    Scene_Object &obj = scene.get_obj(id);
TheNumbat's avatar
TheNumbat committed
51
52
    Vec3 np = obj.armature.base();

TheNumbat's avatar
TheNumbat committed
53
54
55
56
57
58
59
60
61
62
63
    action(
        [this, id, np]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.armature.base() = np;
            obj.set_skel_dirty();
        },
        [this, id, op = old]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.armature.base() = op;
            obj.set_skel_dirty();
        });
TheNumbat's avatar
TheNumbat committed
64
65
}

TheNumbat's avatar
TheNumbat committed
66
67
68
void Undo::del_bone(Scene_ID id, Joint *j) {

    Scene_Object &obj = scene.get_obj(id);
TheNumbat's avatar
TheNumbat committed
69
70
71
    obj.armature.erase(j);
    obj.set_skel_dirty();

TheNumbat's avatar
TheNumbat committed
72
73
74
75
76
77
78
79
80
81
82
83
    action(
        [this, id, j]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.armature.erase(j);
            gui.get_rig().invalidate(j);
            obj.set_skel_dirty();
        },
        [this, id, j]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.armature.restore(j);
            obj.set_skel_dirty();
        });
TheNumbat's avatar
TheNumbat committed
84
85
}

TheNumbat's avatar
TheNumbat committed
86
87
88
89
90
91
92
93
94
95
96
97
void Undo::move_bone(Scene_ID id, Joint *j, Vec3 old) {
    action(
        [this, id, j, ne = j->extent]() {
            Scene_Object &obj = scene.get_obj(id);
            j->extent = ne;
            obj.set_skel_dirty();
        },
        [this, id, j, oe = old]() {
            Scene_Object &obj = scene.get_obj(id);
            j->extent = oe;
            obj.set_skel_dirty();
        });
TheNumbat's avatar
TheNumbat committed
98
99
}

TheNumbat's avatar
TheNumbat committed
100
101
102
103
104
105
106
107
108
109
110
111
void Undo::pose_bone(Scene_ID id, Joint *j, Vec3 old) {
    action(
        [this, id, j, ne = j->pose]() {
            Scene_Object &obj = scene.get_obj(id);
            j->pose = ne;
            obj.set_pose_dirty();
        },
        [this, id, j, oe = old]() {
            Scene_Object &obj = scene.get_obj(id);
            j->pose = oe;
            obj.set_pose_dirty();
        });
TheNumbat's avatar
TheNumbat committed
112
113
}

TheNumbat's avatar
TheNumbat committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
void Undo::add_bone(Scene_ID id, Joint *j) {

    action(
        [this, id, j]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.armature.restore(j);
            obj.set_skel_dirty();
        },
        [this, id, j]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.armature.erase(j);
            gui.get_rig().invalidate(j);
            obj.set_skel_dirty();
        });
TheNumbat's avatar
TheNumbat committed
128
129
130
131
132
}

void Undo::del_obj(Scene_ID id) {
    scene.erase(id);
    gui.invalidate_obj(id);
TheNumbat's avatar
TheNumbat committed
133
134
135
136
137
138
    action(
        [id, this]() {
            scene.erase(id);
            gui.invalidate_obj(id);
        },
        [id, this]() { scene.restore(id); });
TheNumbat's avatar
TheNumbat committed
139
140
}

TheNumbat's avatar
TheNumbat committed
141
Scene_Object &Undo::add_obj(GL::Mesh &&mesh, std::string name) {
TheNumbat's avatar
TheNumbat committed
142
143
    Scene_ID id = scene.add({}, std::move(mesh), name);
    scene.restore(id);
TheNumbat's avatar
TheNumbat committed
144
145
146
147
148
    action([id, this]() { scene.restore(id); },
           [id, this]() {
               scene.erase(id);
               gui.invalidate_obj(id);
           });
TheNumbat's avatar
TheNumbat committed
149
150
151
    return scene.get_obj(id);
}

TheNumbat's avatar
TheNumbat committed
152
Scene_Object &Undo::add_obj(Halfedge_Mesh &&mesh, std::string name) {
TheNumbat's avatar
TheNumbat committed
153
154
    Scene_ID id = scene.add({}, std::move(mesh), name);
    scene.restore(id);
TheNumbat's avatar
TheNumbat committed
155
156
157
158
159
    action([id, this]() { scene.restore(id); },
           [id, this]() {
               scene.erase(id);
               gui.invalidate_obj(id);
           });
TheNumbat's avatar
TheNumbat committed
160
161
162
    return scene.get_obj(id);
}

TheNumbat's avatar
TheNumbat committed
163
void Undo::add_light(Scene_Light &&light) {
TheNumbat's avatar
TheNumbat committed
164
165
    Scene_ID id = scene.add(std::move(light));
    scene.restore(id);
TheNumbat's avatar
TheNumbat committed
166
167
168
169
170
    action([id, this]() { scene.restore(id); },
           [id, this]() {
               scene.erase(id);
               gui.invalidate_obj(id);
           });
TheNumbat's avatar
TheNumbat committed
171
172
173
174
}

void Undo::update_light(Scene_ID id, Scene_Light::Options old) {

TheNumbat's avatar
TheNumbat committed
175
176
177
178
179
180
181
182
183
184
185
186
187
    Scene_Light &light = scene.get_light(id);

    action(
        [id, this, no = light.opt]() {
            Scene_Light &light = scene.get_light(id);
            light.opt = no;
            light.dirty();
        },
        [id, this, oo = old]() {
            Scene_Light &light = scene.get_light(id);
            light.opt = oo;
            light.dirty();
        });
TheNumbat's avatar
TheNumbat committed
188
189
190
191
}

void Undo::update_material(Scene_ID id, Material::Options old) {

TheNumbat's avatar
TheNumbat committed
192
    Scene_Object &obj = scene.get_obj(id);
TheNumbat's avatar
TheNumbat committed
193

TheNumbat's avatar
TheNumbat committed
194
195
196
197
198
199
200
201
202
    action(
        [id, this, nm = obj.material.opt]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.material.opt = nm;
        },
        [id, this, om = old]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.material.opt = om;
        });
TheNumbat's avatar
TheNumbat committed
203
204
205
206
}

void Undo::update_object(Scene_ID id, Scene_Object::Options old) {

TheNumbat's avatar
TheNumbat committed
207
208
209
    Scene_Object &obj = scene.get_obj(id);

    if (obj.opt.shape_type != PT::Shape_Type::none && old.shape_type == PT::Shape_Type::none) {
TheNumbat's avatar
TheNumbat committed
210
211
212
213

        Halfedge_Mesh old_mesh;
        obj.copy_mesh(old_mesh);

TheNumbat's avatar
TheNumbat committed
214
215
216
217
218
219
220
221
222
223
224
        action(
            [id, this, no = obj.opt]() {
                Scene_Object &obj = scene.get_obj(id);
                obj.opt = no;
                obj.set_mesh_dirty();
            },
            [id, this, oo = old, om = std::move(old_mesh)]() mutable {
                Scene_Object &obj = scene.get_obj(id);
                obj.opt = oo;
                obj.set_mesh(om);
            });
TheNumbat's avatar
TheNumbat committed
225
226
227
228

        return;
    }

TheNumbat's avatar
TheNumbat committed
229
    if (obj.opt.shape_type == PT::Shape_Type::none && old.shape_type != PT::Shape_Type::none) {
TheNumbat's avatar
TheNumbat committed
230

TheNumbat's avatar
TheNumbat committed
231
232
233
234
235
236
237
238
239
240
241
        action(
            [id, this, no = obj.opt, ot = old.shape_type]() {
                Scene_Object &obj = scene.get_obj(id);
                obj.opt = no;
                obj.try_make_editable(ot);
            },
            [id, this, oo = old]() {
                Scene_Object &obj = scene.get_obj(id);
                obj.opt = oo;
                obj.set_mesh_dirty();
            });
TheNumbat's avatar
TheNumbat committed
242
243
244
245

        return;
    }

TheNumbat's avatar
TheNumbat committed
246
247
248
249
250
251
252
253
254
255
256
    action(
        [id, this, no = obj.opt]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.opt = no;
            obj.set_mesh_dirty();
        },
        [id, this, oo = old]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.opt = oo;
            obj.set_mesh_dirty();
        });
TheNumbat's avatar
TheNumbat committed
257
258
259
}

void Undo::update_pose(Scene_ID id, Pose old) {
TheNumbat's avatar
TheNumbat committed
260
261
262
263
264
265
266
267
268
269
270
271

    Scene_Item &item = *scene.get(id);

    action(
        [id, this, np = item.pose()]() {
            Scene_Item &item = *scene.get(id);
            item.pose() = np;
        },
        [id, this, op = old]() {
            Scene_Item &item = *scene.get(id);
            item.pose() = op;
        });
TheNumbat's avatar
TheNumbat committed
272
273
}

TheNumbat's avatar
TheNumbat committed
274
void Undo::update_camera(Gui::Widget_Camera &widget, Camera old) {
TheNumbat's avatar
TheNumbat committed
275
276

    Camera newc = widget.get();
TheNumbat's avatar
TheNumbat committed
277
278
279
    action(
        [&widget, nc = newc]() { widget.load(nc.center(), nc.pos(), nc.get_ar(), nc.get_fov()); },
        [&widget, oc = old]() { widget.load(oc.center(), oc.pos(), oc.get_ar(), oc.get_fov()); });
TheNumbat's avatar
TheNumbat committed
280
281
282
283
}

void Undo::anim_pose_bones(Scene_ID id, float t) {

TheNumbat's avatar
TheNumbat committed
284
285
    Scene_Object &obj = scene.get_obj(id);

TheNumbat's avatar
TheNumbat committed
286
    bool had = obj.anim.splines.has(t) || obj.armature.has_keyframes();
TheNumbat's avatar
TheNumbat committed
287

TheNumbat's avatar
TheNumbat committed
288
289
290
291
292
293
294
295
    Pose old_pose = obj.anim.at(t);
    Pose new_pose = obj.pose;
    auto old_joints = obj.armature.at(t);
    auto new_joints = obj.armature.now();

    obj.anim.set(t, new_pose);
    obj.armature.set(t);

TheNumbat's avatar
TheNumbat committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
    action(
        [=]() {
            Scene_Object &obj = scene.get_obj(id);
            obj.anim.set(t, new_pose);
            obj.armature.set(t, new_joints);
            gui.get_animate().refresh(scene);
        },
        [=]() {
            Scene_Object &obj = scene.get_obj(id);
            if (had) {
                obj.anim.set(t, old_pose);
                obj.armature.set(t, old_joints);
            } else {
                obj.anim.splines.erase(t);
                obj.armature.erase(t);
            }
        });
TheNumbat's avatar
TheNumbat committed
313
314
315
316
}

void Undo::anim_pose(Scene_ID id, float t) {

TheNumbat's avatar
TheNumbat committed
317
318
    Scene_Item &item = *scene.get(id);

TheNumbat's avatar
TheNumbat committed
319
320
321
322
323
324
    bool had = item.animation().splines.has(t);
    Pose old = item.animation().at(t);
    Pose p = item.pose();

    item.animation().set(t, p);

TheNumbat's avatar
TheNumbat committed
325
326
327
328
329
330
331
332
333
334
335
336
337
    action(
        [=]() {
            Scene_Item &item = *scene.get(id);
            item.animation().set(t, p);
            gui.get_animate().refresh(scene);
        },
        [=]() {
            Scene_Item &item = *scene.get(id);
            if (had)
                item.animation().set(t, old);
            else
                item.animation().splines.erase(t);
        });
TheNumbat's avatar
TheNumbat committed
338
339
}

TheNumbat's avatar
TheNumbat committed
340
void Undo::anim_camera(Gui::Anim_Camera &anim, float t, const Camera &cam) {
TheNumbat's avatar
TheNumbat committed
341
342
343
344
345
346
347

    bool had = anim.splines.has(t);
    Camera oldc = anim.at(t);
    Camera newc = cam;

    anim.set(t, newc);

TheNumbat's avatar
TheNumbat committed
348
349
350
351
352
353
354
355
356
357
358
    action(
        [=, &anim]() {
            anim.set(t, newc);
            gui.get_animate().refresh(scene);
        },
        [=, &anim]() {
            if (had)
                anim.set(t, oldc);
            else
                anim.splines.erase(t);
        });
TheNumbat's avatar
TheNumbat committed
359
360
361
362
}

void Undo::anim_light(Scene_ID id, float t) {

TheNumbat's avatar
TheNumbat committed
363
364
    Scene_Light &item = scene.get_light(id);

TheNumbat's avatar
TheNumbat committed
365
366
    bool had_l = item.lanim.splines.has(t);
    bool had_p = item.anim.splines.has(t);
TheNumbat's avatar
TheNumbat committed
367

TheNumbat's avatar
TheNumbat committed
368
369
370
371
372
373
374
375
376
377
    Pose old_pose = item.anim.at(t);
    Pose new_pose = item.pose;

    Scene_Light::Options old_l;
    item.lanim.at(t, old_l);
    Scene_Light::Options new_l = item.opt;

    item.anim.set(t, new_pose);
    item.lanim.set(t, new_l);

TheNumbat's avatar
TheNumbat committed
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
    action(
        [=]() {
            Scene_Light &item = scene.get_light(id);
            item.lanim.set(t, new_l);
            item.anim.set(t, new_pose);
            gui.get_animate().refresh(scene);
        },
        [=]() {
            Scene_Light &item = scene.get_light(id);
            if (had_l)
                item.lanim.set(t, old_l);
            else
                item.lanim.splines.erase(t);
            if (had_p)
                item.anim.set(t, old_pose);
            else
                item.anim.splines.erase(t);
            item.dirty();
        });
TheNumbat's avatar
TheNumbat committed
397
398
}

TheNumbat's avatar
TheNumbat committed
399
void Undo::action(std::unique_ptr<Action_Base> &&action) {
TheNumbat's avatar
TheNumbat committed
400
401
402
403
404
    redos = {};
    undos.push(std::move(action));
}

void Undo::undo() {
TheNumbat's avatar
TheNumbat committed
405
406
    if (undos.empty())
        return;
TheNumbat's avatar
TheNumbat committed
407
408
409
410
411
412
    undos.top()->undo();
    redos.push(std::move(undos.top()));
    undos.pop();
}

void Undo::redo() {
TheNumbat's avatar
TheNumbat committed
413
414
    if (redos.empty())
        return;
TheNumbat's avatar
TheNumbat committed
415
416
417
418
    redos.top()->redo();
    undos.push(std::move(redos.top()));
    redos.pop();
}