animate.cpp 22 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();

TheNumbat's avatar
TheNumbat committed
413
414
415
    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
416
        }
TheNumbat's avatar
TheNumbat committed
417
        if(item.is<Scene_Light>()) {
TheNumbat's avatar
TheNumbat committed
418
419
            undo.anim_light(item.id(), (float)current_frame);
        }
TheNumbat's avatar
TheNumbat committed
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
        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
435
436
437
        make_spline(item.id(), item.animation());
    };

TheNumbat's avatar
TheNumbat committed
438
439
    if(ImGui::Button("Set")) {
        if(camera_selected) {
TheNumbat's avatar
TheNumbat committed
440
441
            undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
            camera_spline();
TheNumbat's avatar
TheNumbat committed
442
        } else if(select) {
TheNumbat's avatar
TheNumbat committed
443
444
445
            set_item(*select);
        }
    }
TheNumbat's avatar
TheNumbat committed
446

TheNumbat's avatar
TheNumbat committed
447
    ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
448
449
450
451
452
453
454
455
456
457
458
459
    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
460
461
462
        undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
        camera_spline();
        scene.for_items(set_item);
TheNumbat's avatar
TheNumbat committed
463
464
465
466
467
468
469
470
471
472
        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
473
474
    }

475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
    ImGui::SameLine();
    if(ImGui::Button("Move Left") && current_frame > 0) {
        if(camera_selected) {
            undo.anim_clear_camera(anim_camera, (float)current_frame);
            current_frame--;
            undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
            camera_spline();
        } else if(select) {
            clear_item(*select);
            current_frame--;
            set_item(*select);
        }
        frame_changed = true;
    }

    ImGui::SameLine();
    if(ImGui::Button("Move Right") && current_frame < max_frame-1) {
        if(camera_selected) {
            undo.anim_clear_camera(anim_camera, (float)current_frame);
            current_frame++;
            undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
            camera_spline();
        } else if(select) {
            clear_item(*select);
            current_frame++;
            set_item(*select);
        }
        frame_changed = true;
    }

TheNumbat's avatar
TheNumbat committed
505
506
507
    ImGui::Separator();
    ImGui::Dummy({74.0f, 1.0f});
    ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
508
    if(ImGui::SliderInt("Frame", &current_frame, 0, max_frame - 1)) {
TheNumbat's avatar
TheNumbat committed
509
510
        frame_changed = true;
    }
TheNumbat's avatar
TheNumbat committed
511
512
    ImGui::BeginChild("Timeline", {size.x - 20.0f, size.y - 80.0f}, false,
                      ImGuiWindowFlags_HorizontalScrollbar);
TheNumbat's avatar
TheNumbat committed
513
514

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

TheNumbat's avatar
TheNumbat committed
516
    const int name_chars = 12;
TheNumbat's avatar
TheNumbat committed
517
518
519
520
521
522
523
524
525
    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
526
        if(camera_selected)
TheNumbat's avatar
TheNumbat committed
527
528
            ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s",
                               name.c_str());
TheNumbat's avatar
TheNumbat committed
529
530
531
532
533
534
535
536
537
        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
538
        for(float f : keys) {
TheNumbat's avatar
TheNumbat committed
539
            int frame = (int)std::round(f);
TheNumbat's avatar
TheNumbat committed
540
            if(frame >= 0 && frame < max_frame) frames[frame] = true;
TheNumbat's avatar
TheNumbat committed
541
542
        }

TheNumbat's avatar
TheNumbat committed
543
544
        for(int i = 0; i < max_frame; i++) {
            if(i > 0) ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
545
546
547
548
549
            ImGui::PushID(i);

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

TheNumbat's avatar
TheNumbat committed
550
            if(i == current_frame) {
TheNumbat's avatar
TheNumbat committed
551
552
553
554
                ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
                color = true;
            }

TheNumbat's avatar
TheNumbat committed
555
            if(frames[i]) {
TheNumbat's avatar
TheNumbat committed
556
                label = "*";
TheNumbat's avatar
TheNumbat committed
557
                if(i != current_frame) {
TheNumbat's avatar
TheNumbat committed
558
                    color = true;
TheNumbat's avatar
TheNumbat committed
559
560
                    ImGui::PushStyleColor(ImGuiCol_Button,
                                          ImGui::GetColorU32(ImGuiCol_ButtonHovered));
TheNumbat's avatar
TheNumbat committed
561
562
                }
            }
TheNumbat's avatar
TheNumbat committed
563
            if(ImGui::SmallButton(label.c_str())) {
TheNumbat's avatar
TheNumbat committed
564
565
566
567
                current_frame = i;
                frame_changed = true;
                camera_selected = true;
            }
TheNumbat's avatar
TheNumbat committed
568
            if(color) ImGui::PopStyleColor();
TheNumbat's avatar
TheNumbat committed
569
            ImGui::PopID();
TheNumbat's avatar
TheNumbat committed
570
571
572
573
        }
        ImGui::PopID();
    }

TheNumbat's avatar
TheNumbat committed
574
    scene.for_items([&, this](Scene_Item& item) {
TheNumbat's avatar
TheNumbat committed
575
576
577
        frames.clear();
        frames.resize(max_frame);

TheNumbat's avatar
TheNumbat committed
578
        std::string name = const_cast<const Scene_Item&>(item).name();
TheNumbat's avatar
TheNumbat committed
579
        name.resize(name_chars);
TheNumbat's avatar
TheNumbat committed
580

TheNumbat's avatar
TheNumbat committed
581
        ImVec2 size = ImGui::CalcTextSize(name.c_str());
TheNumbat's avatar
TheNumbat committed
582
        if(!camera_selected && select && item.id() == select->id())
TheNumbat's avatar
TheNumbat committed
583
584
            ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s",
                               name.c_str());
TheNumbat's avatar
TheNumbat committed
585
586
587
588
589
590
591
592
593
594
        else
            ImGui::Text("%s", name.c_str());
        ImGui::SameLine();
        ImGui::Dummy({80.0f - size.x, 1.0f});
        ImGui::SameLine();

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

        Anim_Pose animation = item.animation();
        std::set<float> keys = animation.splines.keys();
TheNumbat's avatar
TheNumbat committed
595
        if(item.is<Scene_Light>()) {
TheNumbat's avatar
TheNumbat committed
596
597
598
            std::set<float> more_keys = item.get<Scene_Light>().lanim.splines.keys();
            keys.insert(more_keys.begin(), more_keys.end());
        }
TheNumbat's avatar
TheNumbat committed
599
        if(item.is<Scene_Object>()) {
TheNumbat's avatar
TheNumbat committed
600
601
602
            std::set<float> more_keys = item.get<Scene_Object>().armature.keys();
            keys.insert(more_keys.begin(), more_keys.end());
        }
TheNumbat's avatar
TheNumbat committed
603
604
605
606
        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());
        }
TheNumbat's avatar
TheNumbat committed
607

TheNumbat's avatar
TheNumbat committed
608
        for(float f : keys) {
TheNumbat's avatar
TheNumbat committed
609
            int frame = (int)std::round(f);
TheNumbat's avatar
TheNumbat committed
610
            if(frame >= 0 && frame < max_frame) frames[frame] = true;
TheNumbat's avatar
TheNumbat committed
611
612
        }

TheNumbat's avatar
TheNumbat committed
613
614
        for(int i = 0; i < max_frame; i++) {
            if(i > 0) ImGui::SameLine();
TheNumbat's avatar
TheNumbat committed
615
616
617
618
619
            ImGui::PushID(i);

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

TheNumbat's avatar
TheNumbat committed
620
            if(i == current_frame) {
TheNumbat's avatar
TheNumbat committed
621
622
623
624
                ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
                color = true;
            }

TheNumbat's avatar
TheNumbat committed
625
            if(frames[i]) {
TheNumbat's avatar
TheNumbat committed
626
                label = "*";
TheNumbat's avatar
TheNumbat committed
627
                if(i != current_frame) {
TheNumbat's avatar
TheNumbat committed
628
                    color = true;
TheNumbat's avatar
TheNumbat committed
629
630
                    ImGui::PushStyleColor(ImGuiCol_Button,
                                          ImGui::GetColorU32(ImGuiCol_ButtonHovered));
TheNumbat's avatar
TheNumbat committed
631
632
633
                }
            }

TheNumbat's avatar
TheNumbat committed
634
            if(ImGui::SmallButton(label.c_str())) {
TheNumbat's avatar
TheNumbat committed
635
636
637
638
639
                current_frame = i;
                frame_changed = true;
                camera_selected = false;
                manager.set_select(item.id());
            }
TheNumbat's avatar
TheNumbat committed
640
            if(color) ImGui::PopStyleColor();
TheNumbat's avatar
TheNumbat committed
641
642
            ImGui::PopID();
        }
TheNumbat's avatar
TheNumbat committed
643

TheNumbat's avatar
TheNumbat committed
644
645
646
647
648
649
        live_ids.push_back(item.id());

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

TheNumbat's avatar
TheNumbat committed
651
652
653
654
    ImGui::PopStyleVar();
    ImGui::EndChild();

    std::unordered_map<Scene_ID, GL::Lines> new_cache;
TheNumbat's avatar
TheNumbat committed
655
    for(Scene_ID i : live_ids) {
TheNumbat's avatar
TheNumbat committed
656
        auto entry = spline_cache.find(i);
TheNumbat's avatar
TheNumbat committed
657
        if(entry != spline_cache.end()) {
TheNumbat's avatar
TheNumbat committed
658
659
660
661
662
            new_cache[i] = std::move(entry->second);
        }
    }
    spline_cache = std::move(new_cache);

TheNumbat's avatar
TheNumbat committed
663
664
665
666
667
    if(frame_changed) update(scene);
}

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

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

TheNumbat's avatar
TheNumbat committed
672
673
    current_frame = (int)time;

TheNumbat's avatar
TheNumbat committed
674
    scene.for_items([time](Scene_Item& item) { item.set_time(time); });
TheNumbat's avatar
TheNumbat committed
675
676

    Camera cam = anim_camera.at(time);
TheNumbat's avatar
TheNumbat committed
677
678
    if(anim_camera.splines.any()) {
        ui_camera.load(cam);
TheNumbat's avatar
TheNumbat committed
679
680
681
    } else {
        cam = ui_camera.get();
    }
TheNumbat's avatar
TheNumbat committed
682
683

    simulate.build_scene(scene);
TheNumbat's avatar
TheNumbat committed
684
685
686
    return cam;
}

TheNumbat's avatar
TheNumbat committed
687
688
689
690
691
void Animate::set_max(int frames) {
    max_frame = frames;
    current_frame = std::min(current_frame, max_frame - 1);
}

TheNumbat's avatar
TheNumbat committed
692
693
694
695
696
697
void Animate::set(int n_frames, int fps) {
    max_frame = n_frames;
    frame_rate = fps;
    current_frame = std::min(current_frame, max_frame - 1);
}

TheNumbat's avatar
TheNumbat committed
698
699
700
Anim_Camera& Animate::camera() {
    return anim_camera;
}
TheNumbat's avatar
TheNumbat committed
701

TheNumbat's avatar
TheNumbat committed
702
703
704
const Anim_Camera& Animate::camera() const {
    return anim_camera;
}
TheNumbat's avatar
TheNumbat committed
705

TheNumbat's avatar
TheNumbat committed
706
707
708
float Animate::fps() const {
    return (float)frame_rate;
}
TheNumbat's avatar
TheNumbat committed
709

TheNumbat's avatar
TheNumbat committed
710
711
712
int Animate::n_frames() const {
    return max_frame;
}
TheNumbat's avatar
TheNumbat committed
713

TheNumbat's avatar
TheNumbat committed
714
715
716
std::string Animate::pump_output(Scene& scene) {
    return ui_render.step(*this, scene);
}
TheNumbat's avatar
TheNumbat committed
717

TheNumbat's avatar
TheNumbat committed
718
719
720
void Animate::refresh(Scene& scene) {
    set_time(scene, (float)current_frame);
}
TheNumbat's avatar
TheNumbat committed
721
722
723
724

void Animate::clear() {
    anim_camera.splines.clear();
    joint_select = nullptr;
TheNumbat's avatar
TheNumbat committed
725
726
727
728
    handle_select = nullptr;
}

void Animate::invalidate(Skeleton::IK_Handle* handle) {
TheNumbat's avatar
TheNumbat committed
729
    if(handle_select == handle) handle_select = nullptr;
TheNumbat's avatar
TheNumbat committed
730
731
732
}

void Animate::invalidate(Joint* j) {
TheNumbat's avatar
TheNumbat committed
733
    if(joint_select == j) joint_select = nullptr;
TheNumbat's avatar
TheNumbat committed
734
735
}

TheNumbat's avatar
TheNumbat committed
736
void Animate::update(Scene& scene) {
TheNumbat's avatar
TheNumbat committed
737
738
739

    Uint64 time = SDL_GetPerformanceCounter();

TheNumbat's avatar
TheNumbat committed
740
741
742
    if(playing) {
        if((time - last_frame) * frame_rate / SDL_GetPerformanceFrequency()) {
            if(current_frame == max_frame - 1) {
TheNumbat's avatar
TheNumbat committed
743
744
745
746
747
748
749
750
751
                playing = false;
                current_frame = 0;
            } else {
                current_frame++;
            }
            last_frame = time;
        }
    }

TheNumbat's avatar
TheNumbat committed
752
    if(displayed_frame != current_frame) {
TheNumbat's avatar
TheNumbat committed
753
754
755
756
757
        set_time(scene, (float)current_frame);
        displayed_frame = current_frame;
    }
}

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