Files
EVEngine/test/editor_animation_clip_editor.cpp

126 lines
5.2 KiB
C++

#include "animation/editor/AnimationClipEditor.h"
#include "animation/AnimClip.h"
#include "animation/AnimPose.h"
#include "animation/AnimSkeleton.h"
#include "editor/EditorWorkspace.h"
#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include <cmath>
using eve::animation_editor::AnimationClipEditor;
using eve::editor::EditorWorkspace;
TEST_CASE("editor.animation.clip_editor_installs_workspace_and_reverses_mask") {
AnimationClipEditor editor("preview.walk");
EditorWorkspace workspace("animation.preview", "Animation Clip Editor");
REQUIRE(editor.configureWorkspace(workspace).ok());
CHECK_EQ(workspace.getPanelCount(), 4);
CHECK_EQ(workspace.getPanelId(0), std::string("animation.skeleton"));
CHECK_EQ(workspace.getPanelCapability(0), std::string("animation.clip"));
CHECK_EQ(workspace.getPanelContext(0), std::string("list"));
CHECK_EQ(workspace.getPanelContext(1), std::string("preview"));
CHECK_EQ(workspace.getPanelContext(2), std::string("inspector"));
CHECK_EQ(workspace.getPanelContext(3), std::string("timeline"));
REQUIRE(editor.setViewport(640.0f, 36.0f, 120.0f).ok());
CHECK_EQ(editor.trackCount(), 6);
CHECK_EQ(editor.boneCount(), 6);
CHECK_EQ(editor.boneParent(3), std::string("Chest"));
CHECK(editor.keyCount() >= 12);
CHECK_EQ(editor.eventCount(), 1);
CHECK(editor.primitiveCount() > 0);
CHECK_EQ(editor.preview().documentRevision, editor.revision());
REQUIRE(editor.seekSeconds(1.0).ok());
CHECK(std::abs(editor.playhead() - 1.0) < 0.0001);
double hipsX = 0.0;
for (const auto& bone : editor.preview().bones)
if (bone.bone == "Hips") hipsX = bone.positionX;
CHECK(std::abs(hipsX - 1.0) < 0.05);
const double before = editor.selectedMaskWeight();
REQUIRE(editor.setMaskWeight(0.25).ok());
CHECK(std::abs(editor.selectedMaskWeight() - 0.25) < 0.0001);
REQUIRE(editor.undo().ok());
CHECK(std::abs(editor.selectedMaskWeight() - before) < 0.0001);
}
TEST_CASE("editor.animation.clip_editor_pointer_selects_bone_and_rejects_invalid_settings") {
AnimationClipEditor editor("preview.walk");
REQUIRE(editor.setViewport(800.0f, 36.0f, 120.0f).ok());
REQUIRE(editor.pointerDown(20.0f, 50.0f).ok());
CHECK_EQ(editor.selectedBone(), std::string("Spine"));
editor.play();
REQUIRE(editor.update(0.2).ok());
CHECK(editor.playhead() > 0.0);
CHECK(editor.isPlaying());
auto rejected = editor.setDuration(0.0);
CHECK(!rejected.ok());
CHECK_EQ(editor.duration(), 2.0);
}
TEST_CASE("editor.animation.clip_editor_keys_edits_and_deletes_joint_transform") {
AnimationClipEditor editor("preview.walk");
REQUIRE(editor.selectBone("Spine").ok());
REQUIRE(editor.seekSeconds(1.0).ok());
const int beforeKeys = editor.keyCount();
REQUIRE(editor.setSelectedPosition(1.25, 2.5, -0.5).ok());
CHECK(editor.hasSelectedKey());
CHECK_EQ(editor.keyCount(), beforeKeys + 1);
CHECK(std::abs(editor.selectedPositionX() - 1.25) < 0.0001);
CHECK(std::abs(editor.selectedPositionY() - 2.5) < 0.0001);
CHECK(std::abs(editor.selectedPositionZ() + 0.5) < 0.0001);
REQUIRE(editor.setSelectedRotation(15.0, 30.0, -20.0).ok());
CHECK(std::abs(editor.selectedRotationX() - 15.0) < 0.01);
CHECK(std::abs(editor.selectedRotationY() - 30.0) < 0.01);
CHECK(std::abs(editor.selectedRotationZ() + 20.0) < 0.01);
REQUIRE(editor.setSelectedScale(1.1, 1.2, 1.3).ok());
CHECK(std::abs(editor.selectedScaleY() - 1.2) < 0.0001);
REQUIRE(editor.moveSelectedKey(1.25).ok());
CHECK(std::abs(editor.selectedKeyTime() - 1.25) < 0.0001);
REQUIRE(editor.deleteSelectedKey().ok());
CHECK(!editor.hasSelectedKey());
CHECK_EQ(editor.keyCount(), beforeKeys);
REQUIRE(editor.undo().ok());
CHECK_EQ(editor.keyCount(), beforeKeys + 1);
}
TEST_CASE("editor.animation.clip_editor_round_trips_real_runtime_skeleton_and_clip") {
eve::animation::AnimSkeleton skeleton;
const int root = skeleton.addBone("Root");
const int hand = skeleton.addBone("Hand", root);
skeleton.setBindPosition(hand, 0.0f, 1.0f, 0.0f);
eve::animation::AnimClip clip("attack");
clip.setDuration(1.0f);
clip.setSampleRate(30.0f);
clip.setLoop(false);
clip.addPositionKey(root, 0.0f, 0.0f, 0.0f, 0.0f);
clip.addPositionKey(root, 1.0f, 1.0f, 0.0f, 0.0f);
clip.addRotationKey(hand, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
clip.addRotationKey(hand, 1.0f, 0.0f, 0.7071067f, 0.0f, 0.7071067f);
AnimationClipEditor editor("runtime.attack");
REQUIRE(editor.loadRuntimeClip(skeleton, clip).ok());
CHECK_EQ(editor.boneCount(), 2);
CHECK_EQ(editor.boneName(1), std::string("Hand"));
CHECK_EQ(editor.boneParent(1), std::string("Root"));
REQUIRE(editor.selectBone("Hand").ok());
REQUIRE(editor.seekSeconds(0.5).ok());
REQUIRE(editor.setSelectedPosition(0.25, 1.25, -0.5).ok());
REQUIRE(editor.writeRuntimeClip(clip, skeleton).ok());
eve::animation::AnimPose pose(2);
clip.sample(0.5f, &pose, &skeleton);
CHECK(std::abs(pose.getLocalPositionX(hand) - 0.25f) < 0.0001f);
CHECK(std::abs(pose.getLocalPositionY(hand) - 1.25f) < 0.0001f);
CHECK(std::abs(pose.getLocalPositionZ(hand) + 0.5f) < 0.0001f);
}