editor: animation loop closing

This commit is contained in:
Turánszki János
2022-08-12 19:45:19 +02:00
parent 9747b59f5e
commit f55e6f79fc
2 changed files with 181 additions and 99 deletions
+180 -99
View File
@@ -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<AnimationComponent::AnimationChannel::Path> 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<float>::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<AnimationComponent::AnimationChannel::Path> 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();
+1
View File
@@ -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