From f55e6f79fc11da8b48bd82b01f06a247e5d0e05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Fri, 12 Aug 2022 19:45:19 +0200 Subject: [PATCH] editor: animation loop closing --- Editor/AnimationWindow.cpp | 279 ++++++++++++++++++++++++------------- Editor/IconDefinitions.h | 1 + 2 files changed, 181 insertions(+), 99 deletions(-) diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index 338dd323c..253965761 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -78,6 +78,7 @@ void AnimationWindow::Create(EditorComponent* _editor) animation->SetLooped(args.bValue); } }); + loopedCheckBox.SetCheckText(ICON_LOOP); AddWidget(&loopedCheckBox); playButton.Create("Play"); @@ -196,6 +197,7 @@ void AnimationWindow::Create(EditorComponent* _editor) recordCombo.AddItem("Rotation " ICON_ROTATE); recordCombo.AddItem("Scale " ICON_SCALE); recordCombo.AddItem("Morph weights " ICON_MESH); + recordCombo.AddItem("Close loop " ICON_LOOP); recordCombo.OnSelect([&](wi::gui::EventArgs args) { if (args.iValue == 0) return; @@ -207,138 +209,73 @@ void AnimationWindow::Create(EditorComponent* _editor) { const float current_time = animation->timer; - wi::vector paths; - - switch (args.iValue) + if (args.iValue == 6) { - default: - case 1: - paths.push_back(AnimationComponent::AnimationChannel::Path::TRANSLATION); - paths.push_back(AnimationComponent::AnimationChannel::Path::ROTATION); - paths.push_back(AnimationComponent::AnimationChannel::Path::SCALE); - break; - case 2: - paths.push_back(AnimationComponent::AnimationChannel::Path::TRANSLATION); - break; - case 3: - paths.push_back(AnimationComponent::AnimationChannel::Path::ROTATION); - break; - case 4: - paths.push_back(AnimationComponent::AnimationChannel::Path::SCALE); - break; - case 5: - paths.push_back(AnimationComponent::AnimationChannel::Path::WEIGHTS); - break; - } - - for (auto path : paths) - { - for (auto& selected : editor->translator.selected) + // Close loop: + for (auto& channel : animation->channels) { - int channelIndex = -1; - for (int i = 0; i < (int)animation->channels.size(); ++i) - { - // Search for channel for this path and target: - auto& channel = animation->channels[i]; - if (channel.path == path && channel.target == selected.entity) - { - channelIndex = i; - break; - } - } - if (channelIndex < 0) - { - // No channel found for this path and target, create it: - channelIndex = (int)animation->channels.size(); - auto& channel = animation->channels.emplace_back(); - channel.samplerIndex = (int)animation->samplers.size(); - channel.target = selected.entity; - channel.path = path; - auto& sam = animation->samplers.emplace_back(); - Entity animation_data_entity = CreateEntity(); - scene.animation_datas.Create(animation_data_entity); - sam.data = animation_data_entity; - } - auto& channel = animation->channels[channelIndex]; - - AnimationDataComponent* animation_data = scene.animation_datas.GetComponent(animation->samplers[channel.samplerIndex].data); + auto& sam = animation->samplers[channel.samplerIndex]; + AnimationDataComponent* animation_data = scene.animation_datas.GetComponent(sam.data); if (animation_data != nullptr) { + // Search for leftmost keyframe: + int keyFirst = 0; + float timeFirst = std::numeric_limits::max(); + for (int k = 0; k < (int)animation_data->keyframe_times.size(); ++k) + { + const float time = animation_data->keyframe_times[k]; + if (time < timeFirst) + { + timeFirst = time; + keyFirst = k; + } + } + + // Duplicate first frame to current position: animation_data->keyframe_times.push_back(current_time); switch (channel.path) { case wi::scene::AnimationComponent::AnimationChannel::TRANSLATION: { - const TransformComponent* transform = scene.transforms.GetComponent(channel.target); - if (transform != nullptr) - { - animation_data->keyframe_data.push_back(transform->translation_local.x); - animation_data->keyframe_data.push_back(transform->translation_local.y); - animation_data->keyframe_data.push_back(transform->translation_local.z); - } - else - { - animation_data->keyframe_times.pop_back(); - animation->channels.pop_back(); - } + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 0]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 1]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 2]); } break; case wi::scene::AnimationComponent::AnimationChannel::ROTATION: { - const TransformComponent* transform = scene.transforms.GetComponent(channel.target); - if (transform != nullptr) - { - animation_data->keyframe_data.push_back(transform->rotation_local.x); - animation_data->keyframe_data.push_back(transform->rotation_local.y); - animation_data->keyframe_data.push_back(transform->rotation_local.z); - animation_data->keyframe_data.push_back(transform->rotation_local.w); - } - else - { - animation_data->keyframe_times.pop_back(); - animation->channels.pop_back(); - } + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 0]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 1]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 2]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 4 + 3]); } break; case wi::scene::AnimationComponent::AnimationChannel::SCALE: { - const TransformComponent* transform = scene.transforms.GetComponent(channel.target); - if (transform != nullptr) - { - animation_data->keyframe_data.push_back(transform->scale_local.x); - animation_data->keyframe_data.push_back(transform->scale_local.y); - animation_data->keyframe_data.push_back(transform->scale_local.z); - } - else - { - animation_data->keyframe_times.pop_back(); - animation->channels.pop_back(); - } + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 0]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 1]); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * 3 + 2]); } break; case wi::scene::AnimationComponent::AnimationChannel::WEIGHTS: { const MeshComponent* mesh = scene.meshes.GetComponent(channel.target); - if (mesh == nullptr && scene.objects.Contains(selected.entity)) + if (mesh == nullptr && scene.objects.Contains(channel.target)) { // Also try query mesh of selected object: - ObjectComponent* object = scene.objects.GetComponent(selected.entity); + ObjectComponent* object = scene.objects.GetComponent(channel.target); mesh = scene.meshes.GetComponent(object->meshID); - channel.target = selected.entity; } if (mesh != nullptr && !mesh->targets.empty()) { + int idx = 0; for (const MeshComponent::MeshMorphTarget& morph : mesh->targets) { - animation_data->keyframe_data.push_back(morph.weight); + animation_data->keyframe_data.push_back(animation_data->keyframe_data[keyFirst * mesh->targets.size() + idx]); + idx++; } } - else - { - animation_data->keyframe_times.pop_back(); - animation->channels.pop_back(); - } } break; default: @@ -347,6 +284,150 @@ void AnimationWindow::Create(EditorComponent* _editor) } } } + else + { + // Add keyframe type: + wi::vector paths; + + switch (args.iValue) + { + default: + case 1: + paths.push_back(AnimationComponent::AnimationChannel::Path::TRANSLATION); + paths.push_back(AnimationComponent::AnimationChannel::Path::ROTATION); + paths.push_back(AnimationComponent::AnimationChannel::Path::SCALE); + break; + case 2: + paths.push_back(AnimationComponent::AnimationChannel::Path::TRANSLATION); + break; + case 3: + paths.push_back(AnimationComponent::AnimationChannel::Path::ROTATION); + break; + case 4: + paths.push_back(AnimationComponent::AnimationChannel::Path::SCALE); + break; + case 5: + paths.push_back(AnimationComponent::AnimationChannel::Path::WEIGHTS); + break; + } + + for (auto path : paths) + { + for (auto& selected : editor->translator.selected) + { + int channelIndex = -1; + for (int i = 0; i < (int)animation->channels.size(); ++i) + { + // Search for channel for this path and target: + auto& channel = animation->channels[i]; + if (channel.path == path && channel.target == selected.entity) + { + channelIndex = i; + break; + } + } + if (channelIndex < 0) + { + // No channel found for this path and target, create it: + channelIndex = (int)animation->channels.size(); + auto& channel = animation->channels.emplace_back(); + channel.samplerIndex = (int)animation->samplers.size(); + channel.target = selected.entity; + channel.path = path; + auto& sam = animation->samplers.emplace_back(); + Entity animation_data_entity = CreateEntity(); + scene.animation_datas.Create(animation_data_entity); + sam.data = animation_data_entity; + } + auto& channel = animation->channels[channelIndex]; + + AnimationDataComponent* animation_data = scene.animation_datas.GetComponent(animation->samplers[channel.samplerIndex].data); + if (animation_data != nullptr) + { + animation_data->keyframe_times.push_back(current_time); + + switch (channel.path) + { + case wi::scene::AnimationComponent::AnimationChannel::TRANSLATION: + { + const TransformComponent* transform = scene.transforms.GetComponent(channel.target); + if (transform != nullptr) + { + animation_data->keyframe_data.push_back(transform->translation_local.x); + animation_data->keyframe_data.push_back(transform->translation_local.y); + animation_data->keyframe_data.push_back(transform->translation_local.z); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::ROTATION: + { + const TransformComponent* transform = scene.transforms.GetComponent(channel.target); + if (transform != nullptr) + { + animation_data->keyframe_data.push_back(transform->rotation_local.x); + animation_data->keyframe_data.push_back(transform->rotation_local.y); + animation_data->keyframe_data.push_back(transform->rotation_local.z); + animation_data->keyframe_data.push_back(transform->rotation_local.w); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::SCALE: + { + const TransformComponent* transform = scene.transforms.GetComponent(channel.target); + if (transform != nullptr) + { + animation_data->keyframe_data.push_back(transform->scale_local.x); + animation_data->keyframe_data.push_back(transform->scale_local.y); + animation_data->keyframe_data.push_back(transform->scale_local.z); + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + case wi::scene::AnimationComponent::AnimationChannel::WEIGHTS: + { + const MeshComponent* mesh = scene.meshes.GetComponent(channel.target); + if (mesh == nullptr && scene.objects.Contains(selected.entity)) + { + // Also try query mesh of selected object: + ObjectComponent* object = scene.objects.GetComponent(selected.entity); + mesh = scene.meshes.GetComponent(object->meshID); + channel.target = selected.entity; + } + if (mesh != nullptr && !mesh->targets.empty()) + { + for (const MeshComponent::MeshMorphTarget& morph : mesh->targets) + { + animation_data->keyframe_data.push_back(morph.weight); + } + } + else + { + animation_data->keyframe_times.pop_back(); + animation->channels.pop_back(); + } + } + break; + default: + break; + } + } + } + } + } } recordCombo.SetSelectedWithoutCallback(0); RefreshKeyframesList(); diff --git a/Editor/IconDefinitions.h b/Editor/IconDefinitions.h index 1faab282f..71c8bb0be 100644 --- a/Editor/IconDefinitions.h +++ b/Editor/IconDefinitions.h @@ -45,3 +45,4 @@ #define ICON_CIRCLE ICON_FA_CIRCLE #define ICON_SQUARE ICON_FA_SQUARE_FULL #define ICON_CUBE ICON_FA_CUBE +#define ICON_LOOP ICON_FA_REPEAT