Commit a38a7d8d authored by Florian Oetke's avatar Florian Oetke
Browse files

animation ui

parent 87bf558b
......@@ -18,7 +18,7 @@ build_gcc:
- cmake -G Ninja -DCMAKE_INSTALL_PREFIX:PATH=../bin -DCMAKE_BUILD_TYPE=Release -DMIRRAGE_EXPORT_EXECUTABLE=ON ..
- cmake --build . --target src/install
- cmake --build . --target test
- wget -N -Omodel_data.tar.xz https://github.com/lowkey42/mirrage/releases/download/v0.2/model_data.tar.xz || true
- wget -N https://github.com/lowkey42/mirrage/releases/download/v0.2/model_data.tar.xz || true
- cd bin/bin
- tar xf ../../model_data.tar.xz
artifacts:
......@@ -42,7 +42,7 @@ build_clang:
- cmake -G Ninja -DCMAKE_INSTALL_PREFIX:PATH=../bin -DCMAKE_BUILD_TYPE=Release -DMIRRAGE_EXPORT_EXECUTABLE=ON ..
- cmake --build . --target src/install
- cmake --build . --target test
- wget -N -Omodel_data.tar.xz https://github.com/lowkey42/mirrage/releases/download/v0.2/model_data.tar.xz || true
- wget -N https://github.com/lowkey42/mirrage/releases/download/v0.2/model_data.tar.xz || true
- cd bin/bin
- tar xf ../../model_data.tar.xz
artifacts:
......
......@@ -72,12 +72,13 @@ namespace mirrage {
, _window_fullscreen(engine.window().fullscreen() != graphic::Fullscreen::no)
{
auto monk = _meta_system.entities().emplace("monk");
monk.get<Transform_comp>().process([](auto& transform) {
_animation_test = _meta_system.entities().emplace("monk");
_animation_test.get<Transform_comp>().process([](auto& transform) {
transform.position = {-8, 0, -0.5f};
transform.orientation = glm::quatLookAt(glm::vec3{-1, 0, 0}, glm::vec3{0, 1, 0});
});
monk.get<renderer::Animation_comp>().process([](auto& anim) { anim.animation("dance"_strid); });
_animation_test.get<renderer::Animation_comp>().process(
[](auto& anim) { anim.animation("dance"_strid); });
auto chest = _meta_system.entities().emplace("chest");
......@@ -716,17 +717,22 @@ namespace mirrage {
void Test_screen::_draw_animation_window()
{
auto anim_mb = _animation_test.get<renderer::Animation_comp>();
if(anim_mb.is_nothing())
return;
auto& anim = anim_mb.get_or_throw();
auto ctx = _gui.ctx();
if(nk_begin_titled(ctx,
"Animation",
"Animation",
_gui.centered_right(300, 500),
NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_TITLE | NK_WINDOW_MINIMIZABLE)) {
// TODO
nk_layout_row_dynamic(ctx, 20, 2);
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "Preset", NK_TEXT_LEFT);
nk_label(ctx, "Animation", NK_TEXT_LEFT);
auto animations_strs = std::array<const char*, 9>{
{"[None]", "Attack", "Dance", "Die", "Flee", "Idle", "Sad", "Sleep", "Walk"}};
auto animations_ids = std::array<util::Str_id, 9>{{""_strid,
......@@ -740,24 +746,54 @@ namespace mirrage {
"walk"_strid}};
(void) animations_ids;
auto curr_animation_id = 0; // TODO: get
auto curr_animation_id = anim.animation_id().get_or(""_strid);
auto curr_idx =
std::distance(animations_ids.begin(),
std::find(animations_ids.begin(), animations_ids.end(), curr_animation_id));
auto new_idx = nk_combo(ctx,
animations_strs.data(),
animations_strs.size(),
int(curr_idx),
14,
nk_vec2(100.f, 200));
auto new_animation_id = nk_combo(ctx,
animations_strs.data(),
animations_strs.size(),
curr_animation_id,
14,
nk_vec2(100.f, 200));
if(new_idx != curr_idx) {
anim.animation(animations_ids.at(std::size_t(new_idx)));
}
if(auto curr_animation = anim.animation(); curr_animation) {
auto duration = curr_animation->duration();
(void) new_animation_id;
nk_label(ctx, "Time", NK_TEXT_LEFT);
auto new_time = nk_slide_float(ctx, 0.f, anim.time(), duration, 0.01f);
if(std::abs(new_time - anim.time()) > 0.00001f)
anim.time(new_time);
nk_label(ctx,
(util::to_string(new_time) + " / " + util::to_string(duration)).c_str(),
NK_TEXT_LEFT);
// TODO: set
auto speed = anim.speed();
nk_property_float(ctx, "Speed", 0.f, &speed, 5.f, 0.01f, 0.2f);
anim.speed(speed);
// TODO: rest only if there is an animation playing
// TODO: time slider
//nk_slide_float()
// TODO: play/pause/reverse buttons
if(anim.paused())
anim.pause(!nk_button_label(ctx, "Continue"));
else
anim.pause(nk_button_label(ctx, "Pause"));
if(anim.reversed())
anim.reverse(!nk_button_label(ctx, "Reverse (->)"));
else
anim.reverse(nk_button_label(ctx, "Reverse (<-)"));
if(anim.looped())
anim.loop(!nk_button_label(ctx, "Once"));
else
anim.loop(nk_button_label(ctx, "Repeat"));
}
}
nk_end(ctx);
......
......@@ -44,6 +44,7 @@ namespace mirrage {
ecs::Entity_facet _camera;
ecs::Entity_facet _sun;
ecs::Entity_facet _animation_test;
float _sun_elevation = 0.92f;
float _sun_azimuth = 1.22f;
......
......@@ -40,15 +40,30 @@ namespace mirrage::renderer {
Animation_comp() = default;
Animation_comp(ecs::Entity_handle owner, ecs::Entity_manager& em) : Component(owner, em) {}
void animation(util::Str_id); ///< play preloaded; for small or frequently used animations
void animation(asset::AID); ///< load + play; for large one-time animations
/// play preloaded; for small or frequently used animations
void animation(util::Str_id, bool loop = true);
/// load + play; for large one-time animations
void animation(asset::Ptr<Animation>, bool loop = true);
auto animation() { return _current_animation; }
auto animation_id() const { return _current_animation_id; }
auto time() const { return _time; }
void time(float time) { _time = time; }
// TODO: pause, stop, speed, ...
auto speed() const { return _speed; }
void speed(float s);
auto reversed() const { return _reversed; }
void reverse(bool r = true) { _reversed = r; }
auto paused() const { return _paused; }
void pause(bool p = true) { _paused = p; }
auto looped() const { return _looped; }
void loop(bool l = true) { _looped = l; }
void step_time(util::Time delta_time);
private:
friend class Animation_pass;
......@@ -58,11 +73,16 @@ namespace mirrage::renderer {
std::unordered_map<util::Str_id, asset::Ptr<Animation>> _preloaded_animations;
asset::Ptr<Animation> _current_animation;
util::maybe<util::Str_id> _current_animation_id;
std::vector<Animation_key> _animation_keys;
float _time = 0.f;
bool _dirty = false;
float _time = 0.f;
float _speed = 1.f;
bool _reversed = false;
bool _paused = false;
bool _looped = true;
bool _dirty = false;
};
} // namespace mirrage::renderer
......@@ -139,10 +139,11 @@ namespace mirrage::renderer {
/// O(1) if the given index is already near the solution
/// O(log log N) if the data is nearly uniformly distributed
/// O(N) else (worst case)
auto binary_search(gsl::span<const float> container, float value, std::int32_t i)
auto binary_search(gsl::span<const float> container, float value, std::int32_t i) -> std::int32_t
{
auto high = std::int32_t(container.size() - 2);
auto low = std::int32_t(0);
i = std::min(high, std::max(low, i));
do {
if(container[i] > value) {
......@@ -159,7 +160,7 @@ namespace mirrage::renderer {
} while(high > low);
return std::min(low, std::int32_t(container.size()) - 1);
return low;
}
/// finds the first keyframe and returns the interpolation factor
......@@ -197,7 +198,8 @@ namespace mirrage::renderer {
}
index = binary_search(times, time, index);
index = std::clamp(
binary_search(times, time, index), std::int32_t(0), std::int32_t(times.size() - 2));
return (time - times[index]) / (times[index + 1] - times[index]);
}
......
......@@ -28,17 +28,63 @@ namespace mirrage::renderer {
sf2::vmember("animations", preload));
}
void Animation_comp::animation(util::Str_id id)
void Animation_comp::animation(util::Str_id id, bool loop)
{
util::find_maybe(_preloaded_animations, id).process([&](auto& new_anim) {
if(new_anim != _current_animation) {
_current_animation = new_anim;
if(auto anim = util::find_maybe(_preloaded_animations, id); anim.is_some()) {
_current_animation_id = id;
animation(anim.get_or_throw(), loop);
} else if(_current_animation) {
animation(asset::Ptr<Animation>{});
}
}
void Animation_comp::animation(asset::Ptr<Animation> anim, bool loop)
{
_looped = loop;
if(anim) {
if(anim != _current_animation) {
_current_animation = anim;
_time = 0.f;
_speed = 1.f;
_reversed = false;
_paused = false;
_animation_keys.clear();
}
});
} else if(_current_animation) {
_current_animation_id = util::nothing;
_current_animation = {};
_time = 0.f;
_animation_keys.clear();
}
}
void Animation_comp::animation(asset::AID)
void Animation_comp::speed(float s)
{
// TODO
_speed = std::abs(s);
_dirty = true;
}
void Animation_comp::step_time(util::Time delta_time)
{
if(_paused || !_current_animation)
return;
auto step = delta_time.value() * _speed * (_reversed ? -1.f : 1.f);
_time += step;
auto duration = _current_animation->duration();
if(_looped) {
_time = std::fmod(_time, duration);
if(_time < 0.f)
_time = duration + _time;
} else {
_time = glm::clamp(_time, 0.f, duration);
}
_dirty = true;
}
} // namespace mirrage::renderer
......@@ -23,10 +23,7 @@ namespace mirrage::renderer {
{
for(auto& anim : _ecs.list<Animation_comp>()) {
// TODO: transitions and stuff
if(anim.animation()) {
anim._time = std::fmod(anim._time + time.value(), anim.animation()->duration());
anim._dirty = true;
}
anim.step_time(time);
}
}
......
......@@ -92,13 +92,18 @@ namespace mirrage::renderer {
const auto sub_sphere_radius = sub_radius * scale;
auto mask = std::uint32_t(0);
for(auto i = 0u; i < viewers.size(); i++) {
auto bit = std::uint32_t(1) << i;
if((main_mask & bit) != 0
&& is_visible(viewers[i], sub_sphere_center, sub_sphere_radius)) {
mask |= bit;
if(!model.model()->rigged()) {
for(auto i = 0u; i < viewers.size(); i++) {
auto bit = std::uint32_t(1) << i;
if((main_mask & bit) != 0
&& is_visible(viewers[i], sub_sphere_center, sub_sphere_radius)) {
mask |= bit;
}
}
} else {
mask = main_mask;
}
if(mask != 0) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment