animate.cpp 22.6 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3

#include "animate.h"
#include "../scene/renderer.h"
TheNumbat's avatar
TheNumbat committed
4
#include "manager.h"
TheNumbat's avatar
TheNumbat committed
5
6
7
8
9
10
11

#include <tuple>

namespace Gui {

Camera Anim_Camera::at(float t) const {
    Camera ret(dim);
TheNumbat's avatar
TheNumbat committed
12
    auto [p, r, f, a, ap, d] = splines.at(t);
TheNumbat's avatar
TheNumbat committed
13
14
15
16
    Vec3 dir = r.rotate(Vec3{0.0f, 0.0f, -1.0f});
    ret.look_at(p + dir, p);
    ret.set_fov(f);
    ret.set_ar(a);
TheNumbat's avatar
TheNumbat committed
17
18
    ret.set_ap(ap);
    ret.set_dist(d);
TheNumbat's avatar
TheNumbat committed
19
20
21
    return ret;
}

TheNumbat's avatar
TheNumbat committed
22
void Anim_Camera::set(float t, const Camera& cam) {
TheNumbat's avatar
TheNumbat committed
23
    splines.set(t, cam.pos(), Quat::euler(Mat4::rotate_z_to(cam.center() - cam.pos()).to_euler()),
TheNumbat's avatar
TheNumbat committed
24
                cam.get_fov(), cam.get_ar(), cam.get_ap(), cam.get_dist());
TheNumbat's avatar
TheNumbat committed
25
26
}

TheNumbat's avatar
TheNumbat committed
27
28
29
void Animate::update_dim(Vec2 dim) {
    ui_camera.dim(dim);
}
TheNumbat's avatar
TheNumbat committed
30

TheNumbat's avatar
TheNumbat committed
31
bool Animate::keydown(Widgets& widgets, Undo& undo, Scene_ID sel, SDL_Keysym key) {
TheNumbat's avatar
TheNumbat committed
32

TheNumbat's avatar
TheNumbat committed
33
    if(key.sym == SDLK_SPACE) {
TheNumbat's avatar
TheNumbat committed
34
35
36
37
38
39
40
41
        playing = !playing;
        last_frame = SDL_GetPerformanceCounter();
        return true;
    }

    return false;
}

TheNumbat's avatar
TheNumbat committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Camera Animate::current_camera() const {
    return ui_camera.get();
}

void Animate::load_cam(Vec3 pos, Vec3 center, float ar, float hfov, float ap, float dist) {

    if(ar == 0.0f) ar = ui_render.wh_ar();

    float fov = 2.0f * std::atan((1.0f / ar) * std::tan(hfov / 2.0f));
    fov = Degrees(fov);

    Camera c(Vec2{ar, 1.0f});
    c.look_at(center, pos);
    c.set_ar(ar);
    c.set_fov(fov);
    c.set_ap(ap);
    c.set_dist(dist);
    ui_camera.load(c);
}

void Animate::render(Scene& scene, Scene_Maybe obj_opt, Widgets& widgets, Camera& user_cam) {
TheNumbat's avatar
TheNumbat committed
63
64

    Mat4 view = user_cam.get_view();
TheNumbat's avatar
TheNumbat committed
65
    auto& R = Renderer::get();
TheNumbat's avatar
TheNumbat committed
66
67
68

    ui_camera.render(view);

TheNumbat's avatar
TheNumbat committed
69
70
    if(visualize_splines)
        for(auto& e : spline_cache) R.lines(e.second, view);
TheNumbat's avatar
TheNumbat committed
71

TheNumbat's avatar
TheNumbat committed
72
73
    if(!obj_opt.has_value()) return;
    Scene_Item& item = obj_opt.value();
TheNumbat's avatar
TheNumbat committed
74

TheNumbat's avatar
TheNumbat committed
75
76
77
    if(item.is<Scene_Light>()) {
        Scene_Light& light = item.get<Scene_Light>();
        if(light.is_env()) return;
TheNumbat's avatar
TheNumbat committed
78
79
    }

TheNumbat's avatar
TheNumbat committed
80
    Pose& pose = item.pose();
TheNumbat's avatar
TheNumbat committed
81
82
    item.render(view);

TheNumbat's avatar
TheNumbat committed
83
    if(item.is<Scene_Object>() && item.get<Scene_Object>().armature.has_bones()) {
TheNumbat's avatar
TheNumbat committed
84

TheNumbat's avatar
TheNumbat committed
85
        Scene_Object& obj = item.get<Scene_Object>();
TheNumbat's avatar
TheNumbat committed
86
        joint_id_offset = scene.used_ids();
TheNumbat's avatar
TheNumbat committed
87
        obj.armature.render(view * obj.pose.transform(), joint_select, handle_select, false, true,
TheNumbat's avatar
TheNumbat committed
88
89
                            joint_id_offset);

TheNumbat's avatar
TheNumbat committed
90
        if(!joint_select && !handle_select) {
TheNumbat's avatar
TheNumbat committed
91
92
93
            R.begin_outline();
            BBox box = obj.bbox();
            obj.render(view, false, true);
TheNumbat's avatar
TheNumbat committed
94
            obj.armature.outline(view, obj.pose.transform(), false, true, box, joint_id_offset);
TheNumbat's avatar
TheNumbat committed
95
            R.end_outline(view, box);
TheNumbat's avatar
TheNumbat committed
96
        } else if(handle_select) {
TheNumbat's avatar
TheNumbat committed
97
            widgets.active = Widget_Type::move;
TheNumbat's avatar
TheNumbat committed
98
99
100
101
102
103
104
105
        } else {
            widgets.active = Widget_Type::rotate;
        }

    } else {
        R.outline(view, item);
    }

TheNumbat's avatar
TheNumbat committed
106
    if(handle_select) {
TheNumbat's avatar
TheNumbat committed
107

TheNumbat's avatar
TheNumbat committed
108
109
110
111
        Scene_Object& obj = item.get<Scene_Object>();
        Vec3 wpos = pose.transform() * (handle_select->target + obj.armature.base());
        float scale = std::min((user_cam.pos() - wpos).norm() / 5.5f, 10.0f);
        widgets.render(view, wpos, scale);
TheNumbat's avatar
TheNumbat committed
112

TheNumbat's avatar
TheNumbat committed
113
    } else if(joint_select) {
TheNumbat's avatar
TheNumbat committed
114

TheNumbat's avatar
TheNumbat committed
115
116
117
118
        Scene_Object& obj = item.get<Scene_Object>();
        Vec3 wpos = pose.transform() * obj.armature.posed_base_of(joint_select);
        float scale = std::min((user_cam.pos() - wpos).norm() / 5.5f, 10.0f);
        widgets.render(view, wpos, scale);
TheNumbat's avatar
TheNumbat committed
119

TheNumbat's avatar
TheNumbat committed
120
    } else {
TheNumbat's avatar
TheNumbat committed
121
122

        float scale = std::min((user_cam.pos() - pose.pos).norm() / 5.5f, 10.0f);
TheNumbat's avatar
TheNumbat committed
123
124
        widgets.render(view, pose.pos, scale);
    }
TheNumbat's avatar
TheNumbat committed
125
126
}

TheNumbat's avatar
TheNumbat committed
127
void Animate::make_spline(Scene_ID id, const Anim_Pose& pose) {
TheNumbat's avatar
TheNumbat committed
128

TheNumbat's avatar
TheNumbat committed
129
    if(!pose.splines.any()) return;
TheNumbat's avatar
TheNumbat committed
130
131

    auto entry = spline_cache.find(id);
TheNumbat's avatar
TheNumbat committed
132
    if(entry == spline_cache.end()) {
TheNumbat's avatar
TheNumbat committed
133
134
135
        std::tie(entry, std::ignore) = spline_cache.insert({id, GL::Lines()});
    }

TheNumbat's avatar
TheNumbat committed
136
    GL::Lines& lines = entry->second;
TheNumbat's avatar
TheNumbat committed
137
138
139
    lines.clear();

    Vec3 prev = pose.at(0.0f).pos;
TheNumbat's avatar
TheNumbat committed
140
    for(int i = 1; i < max_frame; i++) {
TheNumbat's avatar
TheNumbat committed
141

TheNumbat's avatar
TheNumbat committed
142
143
144
145
146
147
148
149
150
151
152
        float f = (float)i;
        float c = (float)(i % 20) / 19.0f;
        Vec3 cur = pose.at(f).pos;
        lines.add(prev, cur, Vec3{c, c, 1.0f});
        prev = cur;
    }
}

void Animate::camera_spline() {

    auto entry = spline_cache.find(0);
TheNumbat's avatar
TheNumbat committed
153
    if(entry == spline_cache.end()) {
TheNumbat's avatar
TheNumbat committed
154
155
156
        std::tie(entry, std::ignore) = spline_cache.insert({0, GL::Lines()});
    }

TheNumbat's avatar
TheNumbat committed
157
    GL::Lines& lines = entry->second;
TheNumbat's avatar
TheNumbat committed
158
159
160
    lines.clear();

    Vec3 prev = anim_camera.at(0.0f).pos();
TheNumbat's avatar
TheNumbat committed
161
    for(int i = 1; i < max_frame; i++) {
TheNumbat's avatar
TheNumbat committed
162
163
164
165
166
167
168
169
        float f = (float)i;
        float c = (float)(i % 20) / 19.0f;
        Vec3 cur = anim_camera.at(f).pos();
        lines.add(prev, cur, Vec3{c, c, 1.0f});
        prev = cur;
    }
}

TheNumbat's avatar
TheNumbat committed
170
171
172
173
174
175
void Animate::UIsidebar(Manager& manager, Undo& undo, Scene_Maybe obj_opt, Camera& user_cam) {

    if(!obj_opt.has_value()) {
        handle_select = nullptr;
        joint_select = nullptr;
    }
TheNumbat's avatar
TheNumbat committed
176

TheNumbat's avatar
TheNumbat committed
177
    if(handle_select) {
TheNumbat's avatar
TheNumbat committed
178
179
180
181
182

        Scene_ID id = obj_opt.value().get().id();

        ImGui::Text("Edit IK Handle");
        ImGui::DragFloat3("Pos", handle_select->target.data, 0.1f, 0.0f, 0.0f, "%.2f");
TheNumbat's avatar
TheNumbat committed
183
184
        if(ImGui::IsItemActivated()) old_euler = handle_select->target;
        if(ImGui::IsItemDeactivatedAfterEdit() && old_euler != handle_select->target) {
TheNumbat's avatar
TheNumbat committed
185
186
187
188
189
            undo.move_handle(id, handle_select, old_euler);
        }
        ImGui::Checkbox("Enable", &handle_select->enabled);
        ImGui::Separator();

TheNumbat's avatar
TheNumbat committed
190
    } else if(joint_select) {
TheNumbat's avatar
TheNumbat committed
191
192
193
194

        Scene_Item& item = obj_opt.value().get();
        Scene_ID id = item.id();

TheNumbat's avatar
TheNumbat committed
195
        ImGui::Text("Edit Joint");
TheNumbat's avatar
TheNumbat committed
196
197

        if(ImGui::DragFloat3("Pose", joint_select->pose.data, 1.0f, 0.0f, 0.0f, "%.2f"))
TheNumbat's avatar
TheNumbat committed
198
            obj_opt.value().get().get<Scene_Object>().set_pose_dirty();
TheNumbat's avatar
TheNumbat committed
199
200
        if(ImGui::IsItemActivated()) old_euler = joint_select->pose;
        if(ImGui::IsItemDeactivatedAfterEdit() && old_euler != joint_select->pose) {
TheNumbat's avatar
TheNumbat committed
201
            joint_select->pose = joint_select->pose.range(0.0f, 360.0f);
TheNumbat's avatar
TheNumbat committed
202
            undo.pose_bone(id, joint_select, old_euler);
TheNumbat's avatar
TheNumbat committed
203
204
205
206
        }
        ImGui::Separator();
    }

TheNumbat's avatar
TheNumbat committed
207
    if(obj_opt.has_value()) {
TheNumbat's avatar
TheNumbat committed
208
        Scene_Item& item = obj_opt.value().get();
TheNumbat's avatar
TheNumbat committed
209
        if(item.is<Scene_Object>()) {
TheNumbat's avatar
TheNumbat committed
210
            Scene_Object& obj = item.get<Scene_Object>();
TheNumbat's avatar
TheNumbat committed
211
212
            if(obj.armature.has_bones()) {
                if(obj.armature.do_ik()) obj.set_pose_dirty();
TheNumbat's avatar
TheNumbat committed
213
214
215
216
            }
        }
    }

TheNumbat's avatar
TheNumbat committed
217
    if(ui_camera.UI(undo, user_cam)) {
TheNumbat's avatar
TheNumbat committed
218
        camera_selected = true;
TheNumbat's avatar
TheNumbat committed
219
        if(obj_opt.has_value()) prev_selected = obj_opt.value().get().id();
TheNumbat's avatar
TheNumbat committed
220
221
222
    }
}

TheNumbat's avatar
TheNumbat committed
223
224
225
226
void Animate::end_transform(Undo& undo, Scene_Item& obj) {
    if(handle_select) {
        undo.move_handle(obj.id(), handle_select, old_euler);
    } else if(joint_select) {
TheNumbat's avatar
TheNumbat committed
227
228
229
230
231
        undo.pose_bone(obj.id(), joint_select, old_euler);
    } else {
        undo.update_pose(obj.id(), old_pose);
    }
    old_pose = {};
TheNumbat's avatar
TheNumbat committed
232
    old_euler = {};
TheNumbat's avatar
TheNumbat committed
233
    old_T = Mat4::I;
TheNumbat's avatar
TheNumbat committed
234
235
}

TheNumbat's avatar
TheNumbat committed
236
237
238
239
240
Vec3 Animate::selected_pos(Scene_Item& item) {
    if(handle_select) {
        return item.pose().transform() *
               (handle_select->target + item.get<Scene_Object>().armature.base());
    } else if(joint_select) {
TheNumbat's avatar
TheNumbat committed
241
242
        return item.pose().transform() *
               item.get<Scene_Object>().armature.posed_base_of(joint_select);
TheNumbat's avatar
TheNumbat committed
243
244
245
246
    }
    return item.pose().pos;
}

TheNumbat's avatar
TheNumbat committed
247
248
249
250
251
252
253
254
255
void Animate::apply_transform(Widgets& widgets, Scene_Item& item) {
    if(handle_select) {

        Scene_Object& obj = item.get<Scene_Object>();
        Vec3 p = old_T * widgets.apply_action(old_pose).pos;
        handle_select->target = p - obj.armature.base();

    } else if(joint_select) {
        Scene_Object& obj = item.get<Scene_Object>();
TheNumbat's avatar
TheNumbat committed
256
        Vec3 euler = widgets.apply_action(old_pose).euler;
TheNumbat's avatar
TheNumbat committed
257
        joint_select->pose = (old_T * Mat4::euler(euler)).to_euler();
TheNumbat's avatar
TheNumbat committed
258
259
        obj.set_pose_dirty();
    } else {
TheNumbat's avatar
TheNumbat committed
260
261
262
263
        item.pose() = widgets.apply_action(old_pose);
    }
}

TheNumbat's avatar
TheNumbat committed
264
bool Animate::select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID id, Vec3 cam,
TheNumbat's avatar
TheNumbat committed
265
                     Vec2 spos, Vec3 dir) {
TheNumbat's avatar
TheNumbat committed
266

TheNumbat's avatar
TheNumbat committed
267
    if(widgets.want_drag()) {
TheNumbat's avatar
TheNumbat committed
268

TheNumbat's avatar
TheNumbat committed
269
        if(handle_select) {
TheNumbat's avatar
TheNumbat committed
270

TheNumbat's avatar
TheNumbat committed
271
272
273
            Scene_Object& obj = scene.get_obj(selected);
            Vec3 base = obj.pose.transform() * (handle_select->target + obj.armature.base());
            widgets.start_drag(base, cam, spos, dir);
TheNumbat's avatar
TheNumbat committed
274
            old_pose = {};
TheNumbat's avatar
TheNumbat committed
275
276
277
            old_pose.pos = base;
            old_euler = handle_select->target;
            old_T = obj.pose.transform().inverse();
TheNumbat's avatar
TheNumbat committed
278

TheNumbat's avatar
TheNumbat committed
279
        } else if(joint_select) {
TheNumbat's avatar
TheNumbat committed
280

TheNumbat's avatar
TheNumbat committed
281
            Scene_Object& obj = scene.get_obj(selected);
TheNumbat's avatar
TheNumbat committed
282
            Vec3 base = obj.pose.transform() * obj.armature.posed_base_of(joint_select);
TheNumbat's avatar
TheNumbat committed
283
            widgets.start_drag(base, cam, spos, dir);
TheNumbat's avatar
TheNumbat committed
284

TheNumbat's avatar
TheNumbat committed
285
286
287
288
            Mat4 j_to_p = obj.pose.transform() * obj.armature.joint_to_posed(joint_select);
            old_euler = joint_select->pose;
            old_pose.euler = j_to_p.to_euler();
            j_to_p = j_to_p * Mat4::euler(old_euler).inverse();
TheNumbat's avatar
TheNumbat committed
289
            old_T = j_to_p.inverse();
TheNumbat's avatar
TheNumbat committed
290
291
292

        } else {

TheNumbat's avatar
TheNumbat committed
293
294
            Scene_Item& item = scene.get(selected).value();
            Pose& pose = item.pose();
TheNumbat's avatar
TheNumbat committed
295
296
297
298
299
            widgets.start_drag(pose.pos, cam, spos, dir);
            old_pose = pose;
        }

        return false;
TheNumbat's avatar
TheNumbat committed
300
301
    }

TheNumbat's avatar
TheNumbat committed
302
    Scene_Maybe mb = scene.get(selected);
TheNumbat's avatar
TheNumbat committed
303
    if(mb.has_value()) {
TheNumbat's avatar
TheNumbat committed
304

TheNumbat's avatar
TheNumbat committed
305
306
        Scene_Item& item = mb.value().get();
        if(item.is<Scene_Object>()) {
TheNumbat's avatar
TheNumbat committed
307

TheNumbat's avatar
TheNumbat committed
308
309
            Scene_Object& obj = item.get<Scene_Object>();
            if(id >= joint_id_offset && obj.armature.has_bones()) {
TheNumbat's avatar
TheNumbat committed
310
311
312

                Scene_ID j_id = id - joint_id_offset;
                joint_select = obj.armature.get_joint(j_id);
TheNumbat's avatar
TheNumbat committed
313
                handle_select = obj.armature.get_handle(j_id);
TheNumbat's avatar
TheNumbat committed
314
                if(joint_select) {
TheNumbat's avatar
TheNumbat committed
315
                    widgets.active = Widget_Type::rotate;
TheNumbat's avatar
TheNumbat committed
316
317
                } else if(handle_select) {
                    widgets.active = Widget_Type::move;
TheNumbat's avatar
TheNumbat committed
318
319
320
321
322
                }
                return false;
            }
        }
    }
TheNumbat's avatar
TheNumbat committed
323

TheNumbat's avatar
TheNumbat committed
324
325
    if(id >= n_Widget_IDs) {
        if(id == selected) {
TheNumbat's avatar
TheNumbat committed
326
            joint_select = nullptr;
TheNumbat's avatar
TheNumbat committed
327
            handle_select = nullptr;
TheNumbat's avatar
TheNumbat committed
328
329
330
331
332
        }
        return true;
    }

    joint_select = nullptr;
TheNumbat's avatar
TheNumbat committed
333
    handle_select = nullptr;
TheNumbat's avatar
TheNumbat committed
334
335
336
    return false;
}

TheNumbat's avatar
TheNumbat committed
337
338
void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe obj,
                       Camera& user_cam) {
TheNumbat's avatar
TheNumbat committed
339
340
341

    // NOTE(max): this is pretty messy
    //      Would be good to add the ability to set per-component keyframes
TheNumbat's avatar
TheNumbat committed
342
    //      ^ I started with that but it was hard to make work with assimp and
TheNumbat's avatar
TheNumbat committed
343
344
345
346
347
348
    //        generally made everything a lot messier.

    ImVec2 size = ImGui::GetWindowSize();

    ImGui::Columns(2);
    ImGui::SetColumnWidth(0, 150.0f);
TheNumbat's avatar
TheNumbat committed
349

TheNumbat's avatar
TheNumbat committed
350
351
    if(!playing) {
        if(ImGui::Button("Play")) {
TheNumbat's avatar
TheNumbat committed
352
353
354
355
            playing = true;
            last_frame = SDL_GetPerformanceCounter();
        }
    } else {
TheNumbat's avatar
TheNumbat committed
356
        if(ImGui::Button("Stop")) {
TheNumbat's avatar
TheNumbat committed
357
358
359
360
361
            playing = false;
        }
    }

    ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
362
    if(ImGui::Button("Render")) {
TheNumbat's avatar
TheNumbat committed
363
364
365
366
367
368
369
        ui_render.open();
    }
    ui_render.animate(scene, ui_camera, user_cam, max_frame);

    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0.0f, 0.0f});
    ImGui::Dummy({1.0f, 4.0f});
    ImGui::PopStyleVar();
TheNumbat's avatar
TheNumbat committed
370

TheNumbat's avatar
TheNumbat committed
371
    if(ImGui::Button("Add Frames")) {
TheNumbat's avatar
TheNumbat committed
372
373
        max_frame += 3 * frame_rate;
    }
TheNumbat's avatar
TheNumbat committed
374
375
376
377
378
379
380
381
382

    auto crop_item = [&, this](Scene_Item& item) {
        undo.anim_crop(item.id(), (float)max_frame);
        make_spline(item.id(), item.animation());
    };

    if(ImGui::Button("Crop End")) {
        size_t n = undo.n_actions();
        undo.set_max_frame(*this, max_frame, current_frame + 1);
TheNumbat's avatar
TheNumbat committed
383
384
        max_frame = current_frame + 1;
        current_frame = std::min(current_frame, max_frame - 1);
TheNumbat's avatar
TheNumbat committed
385
386
387
        undo.anim_crop_camera(anim_camera, (float)max_frame);
        scene.for_items(crop_item);
        undo.bundle_last(undo.n_actions() - n);
TheNumbat's avatar
TheNumbat committed
388
389
        set_time(scene, (float)current_frame);
    }
TheNumbat's avatar
TheNumbat committed
390

TheNumbat's avatar
TheNumbat committed
391
392
393
394
395
396
397
    ImGui::SliderInt("Rate", &frame_rate, 1, 240);
    frame_rate = clamp(frame_rate, 1, 240);

    ImGui::Checkbox("Draw Splines", &visualize_splines);

    ImGui::NextColumn();

TheNumbat's avatar
TheNumbat committed
398
399
400
    Scene_Item* select = nullptr;
    if(obj.has_value()) {
        Scene_Item& item = obj.value();
TheNumbat's avatar
TheNumbat committed
401
        select = &item;
TheNumbat's avatar
TheNumbat committed
402
        if(item.id() != prev_selected) {
TheNumbat's avatar
TheNumbat committed
403
404
405
406
407
408
409
410
411
412
            camera_selected = false;
            prev_selected = item.id();
        }
    }

    bool frame_changed = false;

    ImGui::Text("Keyframe:");
    ImGui::SameLine();

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
    auto all_keys = [](Scene_Item& item) {
        Anim_Pose animation = item.animation();
        std::set<float> keys = animation.splines.keys();
        if(item.is<Scene_Light>()) {
            std::set<float> more_keys = item.get<Scene_Light>().lanim.splines.keys();
            keys.insert(more_keys.begin(), more_keys.end());
        }
        if(item.is<Scene_Object>()) {
            std::set<float> more_keys = item.get<Scene_Object>().armature.keys();
            keys.insert(more_keys.begin(), more_keys.end());
        }
        if(item.is<Scene_Particles>()) {
            std::set<float> more_keys = item.get<Scene_Particles>().panim.splines.keys();
            keys.insert(more_keys.begin(), more_keys.end());
        }
        return keys;
    };

TheNumbat's avatar
TheNumbat committed
431
432
433
    auto set_item = [&, this](Scene_Item& item) {
        if(item.is<Scene_Object>()) {
            undo.anim_object(item.id(), (float)current_frame);
TheNumbat's avatar
TheNumbat committed
434
        }
TheNumbat's avatar
TheNumbat committed
435
        if(item.is<Scene_Light>()) {
TheNumbat's avatar
TheNumbat committed
436
437
            undo.anim_light(item.id(), (float)current_frame);
        }
TheNumbat's avatar
TheNumbat committed
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
        if(item.is<Scene_Particles>()) {
            undo.anim_particles(item.id(), (float)current_frame);
        }
        make_spline(item.id(), item.animation());
    };
    auto clear_item = [&, this](Scene_Item& item) {
        if(item.is<Scene_Object>()) {
            undo.anim_clear_object(item.id(), (float)current_frame);
        }
        if(item.is<Scene_Light>()) {
            undo.anim_clear_light(item.id(), (float)current_frame);
        }
        if(item.is<Scene_Particles>()) {
            undo.anim_clear_particles(item.id(), (float)current_frame);
        }
TheNumbat's avatar
TheNumbat committed
453
454
455
        make_spline(item.id(), item.animation());
    };

TheNumbat's avatar
TheNumbat committed
456
457
    if(ImGui::Button("Set")) {
        if(camera_selected) {
TheNumbat's avatar
TheNumbat committed
458
459
            undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
            camera_spline();
TheNumbat's avatar
TheNumbat committed
460
        } else if(select) {
TheNumbat's avatar
TheNumbat committed
461
462
463
            set_item(*select);
        }
    }
TheNumbat's avatar
TheNumbat committed
464

TheNumbat's avatar
TheNumbat committed
465
    ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
466
467
468
469
470
471
472
473
474
475
476
477
    if(ImGui::Button("Clear")) {
        if(camera_selected) {
            undo.anim_clear_camera(anim_camera, (float)current_frame);
            camera_spline();
        } else if(select) {
            clear_item(*select);
        }
    }

    ImGui::SameLine();
    if(ImGui::Button("Set All")) {
        size_t n = undo.n_actions();
TheNumbat's avatar
TheNumbat committed
478
479
480
        undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
        camera_spline();
        scene.for_items(set_item);
TheNumbat's avatar
TheNumbat committed
481
482
483
484
485
486
487
488
489
490
        undo.bundle_last(undo.n_actions() - n);
    }

    ImGui::SameLine();
    if(ImGui::Button("Clear All")) {
        size_t n = undo.n_actions();
        undo.anim_clear_camera(anim_camera, (float)current_frame);
        camera_spline();
        scene.for_items(clear_item);
        undo.bundle_last(undo.n_actions() - n);
TheNumbat's avatar
TheNumbat committed
491
492
    }

493
494
    ImGui::SameLine();
    if(ImGui::Button("Move Left") && current_frame > 0) {
495
        if(camera_selected && anim_camera.splines.has((float)current_frame)) {
496
497
498
499
            undo.anim_clear_camera(anim_camera, (float)current_frame);
            current_frame--;
            undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
            camera_spline();
500
501
            undo.bundle_last(2);
        } else if(select && all_keys(*select).count((float)current_frame)) {
502
503
504
            clear_item(*select);
            current_frame--;
            set_item(*select);
505
            undo.bundle_last(2);
506
507
508
509
510
511
        }
        frame_changed = true;
    }

    ImGui::SameLine();
    if(ImGui::Button("Move Right") && current_frame < max_frame-1) {
512
        if(camera_selected && anim_camera.splines.has((float)current_frame)) {
513
514
515
516
            undo.anim_clear_camera(anim_camera, (float)current_frame);
            current_frame++;
            undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
            camera_spline();
517
518
            undo.bundle_last(2);
        } else if(select && all_keys(*select).count((float)current_frame)) {
519
520
521
            clear_item(*select);
            current_frame++;
            set_item(*select);
522
            undo.bundle_last(2);
523
524
525
526
        }
        frame_changed = true;
    }

TheNumbat's avatar
TheNumbat committed
527
528
529
    ImGui::Separator();
    ImGui::Dummy({74.0f, 1.0f});
    ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
530
    if(ImGui::SliderInt("Frame", &current_frame, 0, max_frame - 1)) {
TheNumbat's avatar
TheNumbat committed
531
532
        frame_changed = true;
    }
TheNumbat's avatar
TheNumbat committed
533
534
    ImGui::BeginChild("Timeline", {size.x - 20.0f, size.y - 80.0f}, false,
                      ImGuiWindowFlags_HorizontalScrollbar);
TheNumbat's avatar
TheNumbat committed
535
536

    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0.0f, 0.0f});
TheNumbat's avatar
TheNumbat committed
537

TheNumbat's avatar
TheNumbat committed
538
    const int name_chars = 12;
TheNumbat's avatar
TheNumbat committed
539
540
541
542
543
544
545
546
547
    std::vector<bool> frames;
    std::vector<Scene_ID> live_ids;

    {
        frames.clear();
        frames.resize(max_frame);

        std::string name = "Camera";
        ImVec2 sz = ImGui::CalcTextSize(name.c_str());
TheNumbat's avatar
TheNumbat committed
548
        if(camera_selected)
TheNumbat's avatar
TheNumbat committed
549
550
            ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s",
                               name.c_str());
TheNumbat's avatar
TheNumbat committed
551
552
553
554
555
556
557
558
559
        else
            ImGui::Text("%s", name.c_str());
        ImGui::SameLine();
        ImGui::Dummy({80.0f - sz.x, 1.0f});
        ImGui::SameLine();
        ImGui::PushID("##CAMERA_");

        std::set<float> keys = anim_camera.splines.keys();

TheNumbat's avatar
TheNumbat committed
560
        for(float f : keys) {
TheNumbat's avatar
TheNumbat committed
561
            int frame = (int)std::round(f);
TheNumbat's avatar
TheNumbat committed
562
            if(frame >= 0 && frame < max_frame) frames[frame] = true;
TheNumbat's avatar
TheNumbat committed
563
564
        }

TheNumbat's avatar
TheNumbat committed
565
566
        for(int i = 0; i < max_frame; i++) {
            if(i > 0) ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
567
568
569
570
571
            ImGui::PushID(i);

            bool color = false;
            std::string label = "_";

TheNumbat's avatar
TheNumbat committed
572
            if(i == current_frame) {
TheNumbat's avatar
TheNumbat committed
573
574
575
576
                ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
                color = true;
            }

TheNumbat's avatar
TheNumbat committed
577
            if(frames[i]) {
TheNumbat's avatar
TheNumbat committed
578
                label = "*";
TheNumbat's avatar
TheNumbat committed
579
                if(i != current_frame) {
TheNumbat's avatar
TheNumbat committed
580
                    color = true;
TheNumbat's avatar
TheNumbat committed
581
582
                    ImGui::PushStyleColor(ImGuiCol_Button,
                                          ImGui::GetColorU32(ImGuiCol_ButtonHovered));
TheNumbat's avatar
TheNumbat committed
583
584
                }
            }
TheNumbat's avatar
TheNumbat committed
585
            if(ImGui::SmallButton(label.c_str())) {
TheNumbat's avatar
TheNumbat committed
586
587
588
589
                current_frame = i;
                frame_changed = true;
                camera_selected = true;
            }
TheNumbat's avatar
TheNumbat committed
590
            if(color) ImGui::PopStyleColor();
TheNumbat's avatar
TheNumbat committed
591
            ImGui::PopID();
TheNumbat's avatar
TheNumbat committed
592
593
594
595
        }
        ImGui::PopID();
    }

TheNumbat's avatar
TheNumbat committed
596
    scene.for_items([&, this](Scene_Item& item) {
TheNumbat's avatar
TheNumbat committed
597
598
599
        frames.clear();
        frames.resize(max_frame);

TheNumbat's avatar
TheNumbat committed
600
        std::string name = const_cast<const Scene_Item&>(item).name();
TheNumbat's avatar
TheNumbat committed
601
        name.resize(name_chars);
TheNumbat's avatar
TheNumbat committed
602

TheNumbat's avatar
TheNumbat committed
603
        ImVec2 size = ImGui::CalcTextSize(name.c_str());
TheNumbat's avatar
TheNumbat committed
604
        if(!camera_selected && select && item.id() == select->id())
TheNumbat's avatar
TheNumbat committed
605
606
            ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s",
                               name.c_str());
TheNumbat's avatar
TheNumbat committed
607
608
609
610
611
612
613
614
        else
            ImGui::Text("%s", name.c_str());
        ImGui::SameLine();
        ImGui::Dummy({80.0f - size.x, 1.0f});
        ImGui::SameLine();

        ImGui::PushID(item.id());

615
        auto keys = all_keys(item);
TheNumbat's avatar
TheNumbat committed
616
        for(float f : keys) {
TheNumbat's avatar
TheNumbat committed
617
            int frame = (int)std::round(f);
TheNumbat's avatar
TheNumbat committed
618
            if(frame >= 0 && frame < max_frame) frames[frame] = true;
TheNumbat's avatar
TheNumbat committed
619
620
        }

TheNumbat's avatar
TheNumbat committed
621
622
        for(int i = 0; i < max_frame; i++) {
            if(i > 0) ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
623
624
625
626
627
            ImGui::PushID(i);

            bool color = false;
            std::string label = "_";

TheNumbat's avatar
TheNumbat committed
628
            if(i == current_frame) {
TheNumbat's avatar
TheNumbat committed
629
630
631
632
                ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
                color = true;
            }

TheNumbat's avatar
TheNumbat committed
633
            if(frames[i]) {
TheNumbat's avatar
TheNumbat committed
634
                label = "*";
TheNumbat's avatar
TheNumbat committed
635
                if(i != current_frame) {
TheNumbat's avatar
TheNumbat committed
636
                    color = true;
TheNumbat's avatar
TheNumbat committed
637
638
                    ImGui::PushStyleColor(ImGuiCol_Button,
                                          ImGui::GetColorU32(ImGuiCol_ButtonHovered));
TheNumbat's avatar
TheNumbat committed
639
640
641
                }
            }

TheNumbat's avatar
TheNumbat committed
642
            if(ImGui::SmallButton(label.c_str())) {
TheNumbat's avatar
TheNumbat committed
643
644
645
646
647
                current_frame = i;
                frame_changed = true;
                camera_selected = false;
                manager.set_select(item.id());
            }
TheNumbat's avatar
TheNumbat committed
648
            if(color) ImGui::PopStyleColor();
TheNumbat's avatar
TheNumbat committed
649
650
            ImGui::PopID();
        }
TheNumbat's avatar
TheNumbat committed
651

TheNumbat's avatar
TheNumbat committed
652
653
654
655
656
657
        live_ids.push_back(item.id());

        ImGui::SameLine();
        ImGui::Dummy({142.0f, 1.0f});
        ImGui::PopID();
    });
TheNumbat's avatar
TheNumbat committed
658

TheNumbat's avatar
TheNumbat committed
659
660
661
662
    ImGui::PopStyleVar();
    ImGui::EndChild();

    std::unordered_map<Scene_ID, GL::Lines> new_cache;
TheNumbat's avatar
TheNumbat committed
663
    for(Scene_ID i : live_ids) {
TheNumbat's avatar
TheNumbat committed
664
        auto entry = spline_cache.find(i);
TheNumbat's avatar
TheNumbat committed
665
        if(entry != spline_cache.end()) {
TheNumbat's avatar
TheNumbat committed
666
667
668
669
670
            new_cache[i] = std::move(entry->second);
        }
    }
    spline_cache = std::move(new_cache);

TheNumbat's avatar
TheNumbat committed
671
672
673
674
675
    if(frame_changed) update(scene);
}

void Animate::step_sim(Scene& scene) {
    simulate.step(scene, 1.0f / frame_rate);
TheNumbat's avatar
TheNumbat committed
676
677
}

TheNumbat's avatar
TheNumbat committed
678
Camera Animate::set_time(Scene& scene, float time) {
TheNumbat's avatar
TheNumbat committed
679

TheNumbat's avatar
TheNumbat committed
680
681
    current_frame = (int)time;

TheNumbat's avatar
TheNumbat committed
682
    scene.for_items([time](Scene_Item& item) { item.set_time(time); });
TheNumbat's avatar
TheNumbat committed
683
684

    Camera cam = anim_camera.at(time);
TheNumbat's avatar
TheNumbat committed
685
686
    if(anim_camera.splines.any()) {
        ui_camera.load(cam);
TheNumbat's avatar
TheNumbat committed
687
688
689
    } else {
        cam = ui_camera.get();
    }
TheNumbat's avatar
TheNumbat committed
690
691

    simulate.build_scene(scene);
TheNumbat's avatar
TheNumbat committed
692
693
694
    return cam;
}

TheNumbat's avatar
TheNumbat committed
695
696
697
698
699
void Animate::set_max(int frames) {
    max_frame = frames;
    current_frame = std::min(current_frame, max_frame - 1);
}

TheNumbat's avatar
TheNumbat committed
700
701
702
703
704
705
706
707
void Animate::set(int n_frames, int fps, bool replace) {
    if(replace) {
        max_frame = n_frames;
        frame_rate = fps;
    } else {
        max_frame = std::max(n_frames, max_frame);
        frame_rate = std::min(frame_rate, fps);
    }
TheNumbat's avatar
TheNumbat committed
708
709
710
    current_frame = std::min(current_frame, max_frame - 1);
}

TheNumbat's avatar
TheNumbat committed
711
712
713
Anim_Camera& Animate::camera() {
    return anim_camera;
}
TheNumbat's avatar
TheNumbat committed
714

TheNumbat's avatar
TheNumbat committed
715
716
717
const Anim_Camera& Animate::camera() const {
    return anim_camera;
}
TheNumbat's avatar
TheNumbat committed
718

TheNumbat's avatar
TheNumbat committed
719
720
721
float Animate::fps() const {
    return (float)frame_rate;
}
TheNumbat's avatar
TheNumbat committed
722

TheNumbat's avatar
TheNumbat committed
723
724
725
int Animate::n_frames() const {
    return max_frame;
}
TheNumbat's avatar
TheNumbat committed
726

TheNumbat's avatar
TheNumbat committed
727
728
729
std::string Animate::pump_output(Scene& scene) {
    return ui_render.step(*this, scene);
}
TheNumbat's avatar
TheNumbat committed
730

TheNumbat's avatar
TheNumbat committed
731
732
733
void Animate::refresh(Scene& scene) {
    set_time(scene, (float)current_frame);
}
TheNumbat's avatar
TheNumbat committed
734
735
736
737

void Animate::clear() {
    anim_camera.splines.clear();
    joint_select = nullptr;
TheNumbat's avatar
TheNumbat committed
738
739
740
741
    handle_select = nullptr;
}

void Animate::invalidate(Skeleton::IK_Handle* handle) {
TheNumbat's avatar
TheNumbat committed
742
    if(handle_select == handle) handle_select = nullptr;
TheNumbat's avatar
TheNumbat committed
743
744
745
}

void Animate::invalidate(Joint* j) {
TheNumbat's avatar
TheNumbat committed
746
    if(joint_select == j) joint_select = nullptr;
TheNumbat's avatar
TheNumbat committed
747
748
}

TheNumbat's avatar
TheNumbat committed
749
void Animate::update(Scene& scene) {
TheNumbat's avatar
TheNumbat committed
750
751
752

    Uint64 time = SDL_GetPerformanceCounter();

TheNumbat's avatar
TheNumbat committed
753
754
755
    if(playing) {
        if((time - last_frame) * frame_rate / SDL_GetPerformanceFrequency()) {
            if(current_frame == max_frame - 1) {
TheNumbat's avatar
TheNumbat committed
756
757
758
759
760
761
762
763
764
                playing = false;
                current_frame = 0;
            } else {
                current_frame++;
            }
            last_frame = time;
        }
    }

TheNumbat's avatar
TheNumbat committed
765
    if(displayed_frame != current_frame) {
TheNumbat's avatar
TheNumbat committed
766
767
768
769
770
        set_time(scene, (float)current_frame);
        displayed_frame = current_frame;
    }
}

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