rig.cpp 7.33 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3

#include "rig.h"
#include "../scene/renderer.h"
TheNumbat's avatar
TheNumbat committed
4
#include "manager.h"
TheNumbat's avatar
TheNumbat committed
5
6
7

namespace Gui {

TheNumbat's avatar
TheNumbat committed
8
bool Rig::keydown(Widgets &widgets, Undo &undo, SDL_Keysym key) {
TheNumbat's avatar
TheNumbat committed
9

TheNumbat's avatar
TheNumbat committed
10
11
    if (!my_obj)
        return false;
TheNumbat's avatar
TheNumbat committed
12
13

#ifdef __APPLE__
TheNumbat's avatar
TheNumbat committed
14
    if (key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
TheNumbat's avatar
TheNumbat committed
15
#else
TheNumbat's avatar
TheNumbat committed
16
    if (key.sym == SDLK_DELETE && (selected || handle)) {
TheNumbat's avatar
TheNumbat committed
17
#endif
TheNumbat's avatar
TheNumbat committed
18
19
20
21
22
23
24
25
26
        if (selected) {
            undo.del_bone(my_obj->id(), selected);
            selected = nullptr;
            return true;
        } else if(handle) {
            undo.del_handle(my_obj->id(), handle);
            handle = nullptr;
            return true;
        }
TheNumbat's avatar
TheNumbat committed
27
    }
TheNumbat's avatar
TheNumbat committed
28
29
30
    return false;
}

TheNumbat's avatar
TheNumbat committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void Rig::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam) {

    if (!obj_opt.has_value())
        return;

    Scene_Item &item = obj_opt.value();
    if (!item.is<Scene_Object>())
        return;

    Scene_Object &obj = item.get<Scene_Object>();
    if (obj.opt.shape_type != PT::Shape_Type::none)
        return;

    if (my_obj != &obj) {
        my_obj = &obj;
        selected = nullptr;
TheNumbat's avatar
TheNumbat committed
47
        handle = nullptr;
TheNumbat's avatar
TheNumbat committed
48
49
50
51
52
53
54
    }
    if (my_obj->rig_dirty) {
        mesh_bvh.build(obj.mesh());
        my_obj->rig_dirty = false;
    }

    Mat4 view = cam.get_view();
TheNumbat's avatar
TheNumbat committed
55
    obj.render(view, false, false, false, false);
TheNumbat's avatar
TheNumbat committed
56
    obj.armature.render(view, selected, handle, root_selected, false);
TheNumbat's avatar
TheNumbat committed
57

TheNumbat's avatar
TheNumbat committed
58
    if (selected || handle || root_selected) {
TheNumbat's avatar
TheNumbat committed
59
60
61
62
63
64

        widgets.active = Widget_Type::move;
        Vec3 pos;

        if (selected)
            pos = obj.armature.end_of(selected);
TheNumbat's avatar
TheNumbat committed
65
66
        else if (handle)
            pos = handle->target + obj.armature.base();
TheNumbat's avatar
TheNumbat committed
67
68
69
70
71
72
        else
            pos = obj.armature.base();

        float scale = std::min((cam.pos() - pos).norm() / 5.5f, 10.0f);
        widgets.render(view, pos, scale);
    }
TheNumbat's avatar
TheNumbat committed
73
74
}

TheNumbat's avatar
TheNumbat committed
75
76
77
78
79
void Rig::invalidate(Joint *j) {
    if (selected == j)
        selected = nullptr;
    if (new_joint == j)
        new_joint = nullptr;
TheNumbat's avatar
TheNumbat committed
80
81
}

TheNumbat's avatar
TheNumbat committed
82
83
84
85
86
void Rig::invalidate(Skeleton::IK_Handle *j) {
    if (handle == j)
        handle = nullptr;
}

TheNumbat's avatar
TheNumbat committed
87
88
void Rig::end_transform(Widgets &widgets, Undo &undo, Scene_Object &obj) {
    if (root_selected)
TheNumbat's avatar
TheNumbat committed
89
90
        undo.move_root(obj.id(), old_pos);
    else if (selected)
TheNumbat's avatar
TheNumbat committed
91
        undo.move_bone(obj.id(), selected, old_ext);
TheNumbat's avatar
TheNumbat committed
92
93
    else if (handle) 
        undo.move_handle(obj.id(), handle, old_pos - my_obj->armature.base());
TheNumbat's avatar
TheNumbat committed
94
    obj.set_skel_dirty();
TheNumbat's avatar
TheNumbat committed
95
96
}

TheNumbat's avatar
TheNumbat committed
97
98
99
100
101
102
103
104
void Rig::apply_transform(Widgets &widgets) {
    if (root_selected) {
        my_obj->armature.base() = widgets.apply_action(Pose::moved(old_pos)).pos;
        my_obj->set_skel_dirty();
    } else if (selected) {
        Vec3 new_pos = widgets.apply_action(Pose::moved(old_pos)).pos;
        selected->extent = new_pos - old_base;
        my_obj->set_skel_dirty();
TheNumbat's avatar
TheNumbat committed
105
106
107
108
    } else if (handle) {
        Vec3 new_pos = widgets.apply_action(Pose::moved(old_pos)).pos;
        handle->target = new_pos - my_obj->armature.base();
        my_obj->set_skel_dirty();
TheNumbat's avatar
TheNumbat committed
109
    }
TheNumbat's avatar
TheNumbat committed
110
111
112
}

Vec3 Rig::selected_pos() {
TheNumbat's avatar
TheNumbat committed
113
114
    if (root_selected) {
        return my_obj->armature.base();
TheNumbat's avatar
TheNumbat committed
115
    } else if (selected) {
TheNumbat's avatar
TheNumbat committed
116
        return my_obj->armature.end_of(selected);
TheNumbat's avatar
TheNumbat committed
117
118
    } else if (handle) {
        return handle->target + my_obj->armature.base();
TheNumbat's avatar
TheNumbat committed
119
    }
TheNumbat's avatar
TheNumbat committed
120
121
    assert(false);
    return Vec3();
TheNumbat's avatar
TheNumbat committed
122
123
}

TheNumbat's avatar
TheNumbat committed
124
125
126
127
128
void Rig::select(Scene &scene, Widgets &widgets, Undo &undo, Scene_ID id, Vec3 cam, Vec2 spos,
                 Vec3 dir) {

    if (!my_obj)
        return;
TheNumbat's avatar
TheNumbat committed
129

TheNumbat's avatar
TheNumbat committed
130
    if (creating_bone) {
TheNumbat's avatar
TheNumbat committed
131

TheNumbat's avatar
TheNumbat committed
132
        undo.add_bone(my_obj->id(), new_joint);
TheNumbat's avatar
TheNumbat committed
133

TheNumbat's avatar
TheNumbat committed
134
135
        selected = new_joint;
        new_joint = nullptr;
TheNumbat's avatar
TheNumbat committed
136
        handle = nullptr;
TheNumbat's avatar
TheNumbat committed
137

TheNumbat's avatar
TheNumbat committed
138
139
        creating_bone = false;
        root_selected = false;
TheNumbat's avatar
TheNumbat committed
140

TheNumbat's avatar
TheNumbat committed
141
142
143
144
    } else if (widgets.want_drag()) {

        if (root_selected) {
            old_pos = my_obj->armature.base();
TheNumbat's avatar
TheNumbat committed
145
        } else if (selected) {
TheNumbat's avatar
TheNumbat committed
146
147
148
            old_pos = my_obj->armature.end_of(selected);
            old_base = my_obj->armature.base_of(selected);
            old_ext = selected->extent;
TheNumbat's avatar
TheNumbat committed
149
150
        } else if (handle) {
            old_pos = handle->target + my_obj->armature.base();
TheNumbat's avatar
TheNumbat committed
151
152
        }
        widgets.start_drag(old_pos, cam, spos, dir);
TheNumbat's avatar
TheNumbat committed
153
154

    } else if (!id || id >= n_Widget_IDs) {
TheNumbat's avatar
TheNumbat committed
155
156

        selected = my_obj->armature.get_joint(id);
TheNumbat's avatar
TheNumbat committed
157
        handle = my_obj->armature.get_handle(id);
TheNumbat's avatar
TheNumbat committed
158
        root_selected = my_obj->armature.is_root_id(id);
TheNumbat's avatar
TheNumbat committed
159
160
161
162
    }
}

void Rig::clear() {
TheNumbat's avatar
TheNumbat committed
163
164
    my_obj = nullptr;
    selected = nullptr;
TheNumbat's avatar
TheNumbat committed
165
    handle = nullptr;
TheNumbat's avatar
TheNumbat committed
166
167
}

TheNumbat's avatar
TheNumbat committed
168
169
170
171
void Rig::clear_select() { 
    selected = nullptr; 
    handle = nullptr;
}
TheNumbat's avatar
TheNumbat committed
172
173
174

void Rig::hover(Vec3 cam, Vec2 spos, Vec3 dir) {

TheNumbat's avatar
TheNumbat committed
175
176
177
178
    if (creating_bone) {

        assert(new_joint);
        assert(my_obj);
TheNumbat's avatar
TheNumbat committed
179

TheNumbat's avatar
TheNumbat committed
180
181
182
183
        Ray f(cam, dir);
        PT::Trace hit1 = mesh_bvh.hit(f);
        if (!hit1.hit)
            return;
TheNumbat's avatar
TheNumbat committed
184

TheNumbat's avatar
TheNumbat committed
185
186
        Ray s(hit1.position + dir * EPS_F, dir);
        PT::Trace hit2 = mesh_bvh.hit(s);
TheNumbat's avatar
TheNumbat committed
187

TheNumbat's avatar
TheNumbat committed
188
189
190
        Vec3 pos = hit1.position;
        if (hit2.hit)
            pos = 0.5f * (hit1.position + hit2.position);
TheNumbat's avatar
TheNumbat committed
191

TheNumbat's avatar
TheNumbat committed
192
193
194
        new_joint->extent = pos - old_base;
        my_obj->set_skel_dirty();
    }
TheNumbat's avatar
TheNumbat committed
195
196
}

TheNumbat's avatar
TheNumbat committed
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
Mode Rig::UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe obj_opt) {

    if (!my_obj)
        return Mode::rig;

    if (!obj_opt.has_value())
        return Mode::rig;

    Scene_Item &item = obj_opt.value();
    if (!item.is<Scene_Object>())
        return Mode::rig;

    Scene_Object &obj = item.get<Scene_Object>();
    if (obj.opt.shape_type != PT::Shape_Type::none)
        return Mode::rig;

    if (my_obj != &obj) {
        my_obj = &obj;
        selected = nullptr;
TheNumbat's avatar
TheNumbat committed
216
        handle = nullptr;
TheNumbat's avatar
TheNumbat committed
217
218
219
220
221
222
223
224
225
226
227
228
229
    }
    if (my_obj->rig_dirty) {
        mesh_bvh.build(obj.mesh());
        my_obj->rig_dirty = false;
    }

    ImGui::Text("Edit Skeleton");

    if (creating_bone) {
        if (ImGui::Button("Cancel")) {
            creating_bone = false;
            my_obj->armature.erase(new_joint);
            new_joint = nullptr;
TheNumbat's avatar
TheNumbat committed
230
            handle = nullptr;
TheNumbat's avatar
TheNumbat committed
231
232
233
234
235
            my_obj->set_skel_dirty();
        }
    } else if (ImGui::Button("New Bone")) {

        creating_bone = true;
TheNumbat's avatar
TheNumbat committed
236
        handle = nullptr;
TheNumbat's avatar
TheNumbat committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

        if (!selected || root_selected) {
            new_joint = my_obj->armature.add_root(Vec3{0.0f});
            old_base = my_obj->armature.base();
        } else {
            new_joint = my_obj->armature.add_child(selected, Vec3{0.0f});
            old_base = my_obj->armature.end_of(selected);
        }
        my_obj->set_skel_dirty();
    }

    if (selected) {

        ImGui::Separator();
        ImGui::Text("Edit Bone");

        ImGui::DragFloat3("Extent", selected->extent.data, 0.1f);
        ImGui::DragFloat("Radius", &selected->radius, 0.05f, 0.0f,
                         std::numeric_limits<float>::max());

        ImGui::DragFloat3("Pose", selected->pose.data, 0.1f);

TheNumbat's avatar
TheNumbat committed
259
260
261
262
263
264
        if (ImGui::Button("Add IK")) {
            handle = my_obj->armature.add_handle(my_obj->armature.end_of(selected), selected);
            undo.add_handle(my_obj->id(), handle);
            selected = nullptr;
        }
        ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
265
266
267
268
        if (ImGui::Button("Delete [del]")) {
            undo.del_bone(my_obj->id(), selected);
            selected = nullptr;
        }
TheNumbat's avatar
TheNumbat committed
269
270
271
272
273
274
275
276
277
278
279
280

    } else if (handle) {
        ImGui::Separator();
        ImGui::Text("Edit Handle");

        ImGui::DragFloat3("Target", handle->target.data, 0.1f);
        ImGui::Checkbox("Enable", &handle->enabled);

        if (ImGui::Button("Delete [del]")) {
            undo.del_handle(my_obj->id(), handle);
            handle = nullptr;
        }
TheNumbat's avatar
TheNumbat committed
281
    }
TheNumbat's avatar
TheNumbat committed
282
283
284
285

    return Mode::rig;
}

TheNumbat's avatar
TheNumbat committed
286
} // namespace Gui