undo.h 2.61 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

#pragma once

#include <memory>
#include <stack>

#include "scene.h"
#include "../gui/widgets.h"

namespace Gui { class Manager; class Anim_Camera; class Rig; }

class Action_Base {
    virtual void undo() = 0;
    virtual void redo() = 0;
    friend class Undo;
public:
    virtual ~Action_Base() = default;
};

template<typename T>
class MeshOp : public Action_Base {
    void undo() {
        Scene_Object& obj = scene.get_obj(id);
        obj.set_mesh(mesh);
    }
    void redo() {
        Scene_Object& obj = scene.get_obj(id);
        auto sel = obj.set_mesh(mesh, eid);
        op(obj.get_mesh(), sel);
    }
    Scene& scene;
    Scene_ID id;
    unsigned int eid;
    T op;
    Halfedge_Mesh mesh;
    
public:
    MeshOp(Scene& s, Scene_ID i, unsigned int e, Halfedge_Mesh&& m, T&& t) : 
        scene(s), id(i), eid(e), op(t), mesh(std::move(m)) {}
    ~MeshOp() = default;
};

class Undo {
public:
    Undo(Scene& scene, Gui::Manager& man);

    // These could just take Scene_Object&& but this was easier
    Scene_Object& add_obj(GL::Mesh&& mesh, std::string name);
    Scene_Object& add_obj(Halfedge_Mesh&& mesh, std::string name);
    void add_light(Scene_Light&& mesh);

    void del_obj(Scene_ID id);
    void update_pose(Scene_ID id, Pose old);

    void del_bone(Scene_ID id, Joint* j);
    void add_bone(Scene_ID id, Joint* j);
    void move_bone(Scene_ID id, Joint* j, Vec3 old);
    void pose_bone(Scene_ID id, Joint* j, Vec3 old);
    void move_root(Scene_ID id, Vec3 old);

    void update_light(Scene_ID id, Scene_Light::Options old);
    void update_object(Scene_ID id, Scene_Object::Options old);
    void update_material(Scene_ID id, Material::Options old);
    void update_camera(Gui::Widget_Camera& widget, Camera old);

    template<typename T> 
    void update_mesh(Scene_ID id, Halfedge_Mesh&& old, unsigned int e_id, T&& op) {
        std::stack<std::unique_ptr<Action_Base>> empty;
        redos.swap(empty);
        undos.push(std::make_unique<MeshOp<T>>(scene, id, e_id, std::move(old), std::move(op)));
    }
    void update_mesh_full(Scene_ID id, Halfedge_Mesh&& old_mesh);

    void anim_pose(Scene_ID id, float t);
    void anim_pose_bones(Scene_ID id, float t);
    void anim_camera(Gui::Anim_Camera& anim, float t, const Camera& cam);
    void anim_light(Scene_ID id, float t);

    void undo();
    void redo();
    void reset();

private:
    Scene& scene;
    Gui::Manager& gui;

    template<typename R, typename U> 
    void action(R&& redo, U&& undo);
    void action(std::unique_ptr<Action_Base>&& action);
    
    std::stack<std::unique_ptr<Action_Base>> undos;
    std::stack<std::unique_ptr<Action_Base>> redos;
};