Skip to content

Commit

Permalink
TinyGltfImporter: initial animation data import.
Browse files Browse the repository at this point in the history
  • Loading branch information
mosra committed Aug 2, 2018
1 parent d73b9f9 commit b4bc480
Show file tree
Hide file tree
Showing 14 changed files with 687 additions and 4 deletions.
2 changes: 2 additions & 0 deletions doc/changelog-plugins.dox
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ namespace Magnum {

@subsection changelog-plugins-latest-new New features

- Initial support for animation data import in
@ref Trade::TinyGltfImporter "TinyGltfImporter"
- Minimal support for the [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness)
extension in @ref Trade::TinyGltfImporter "TinyGltfImporter"
- The top-level `tinygltf::Model` structure is now exposed through
Expand Down
6 changes: 6 additions & 0 deletions src/MagnumPlugins/TinyGltfImporter/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ corrade_add_test(TinyGltfImporterTest
FILES
empty.gltf
empty.glb
animation.gltf
animation.glb
animation.bin
animation-embedded.gltf
animation-embedded.glb
animation-wrong.gltf
camera.gltf
camera.glb
# external-data.* packed via a resource
Expand Down
206 changes: 206 additions & 0 deletions src/MagnumPlugins/TinyGltfImporter/Test/TinyGltfImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <Magnum/Math/Quaternion.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Trade/AbstractMaterialData.h>
#include <Magnum/Trade/AnimationData.h>
#include <Magnum/Trade/CameraData.h>
#include <Magnum/Trade/ImageData.h>
#include <Magnum/Trade/LightData.h>
Expand All @@ -58,6 +59,14 @@ struct TinyGltfImporterTest: TestSuite::Tester {
void openError();
void openFileError();

void animation();
void animationWrongTimeType();
void animationWrongInterpolationType();
void animationWrongTranslationType();
void animationWrongRotationType();
void animationWrongScalingType();
void animationUnsupportedPath();

void camera();

void light();
Expand Down Expand Up @@ -144,6 +153,16 @@ TinyGltfImporterTest::TinyGltfImporterTest() {
&TinyGltfImporterTest::openFileError},
Containers::arraySize(OpenErrorData));

addInstancedTests({&TinyGltfImporterTest::animation},
Containers::arraySize(MultiFileData));

addTests({&TinyGltfImporterTest::animationWrongTimeType,
&TinyGltfImporterTest::animationWrongInterpolationType,
&TinyGltfImporterTest::animationWrongTranslationType,
&TinyGltfImporterTest::animationWrongRotationType,
&TinyGltfImporterTest::animationWrongScalingType,
&TinyGltfImporterTest::animationUnsupportedPath});

addInstancedTests({&TinyGltfImporterTest::camera,

&TinyGltfImporterTest::light,
Expand Down Expand Up @@ -234,6 +253,193 @@ void TinyGltfImporterTest::openFileError() {
CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::openFile(): cannot open file nope" + std::string{data.suffix} + "\n");
}

void TinyGltfImporterTest::animation() {
auto&& data = MultiFileData[testCaseInstanceId()];
setTestCaseDescription(data.name);

std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation" + std::string{data.suffix})));

CORRADE_COMPARE(importer->animationCount(), 2);

/* Empty animation */
{
CORRADE_COMPARE(importer->animationName(0), "empty");
CORRADE_COMPARE(importer->animationForName("empty"), 0);

auto animation = importer->animation(0);
CORRADE_VERIFY(animation);
CORRADE_VERIFY(animation->data().empty());
CORRADE_COMPARE(animation->trackCount(), 0);

/* Translation/rotation/scaling animation */
} {
CORRADE_COMPARE(importer->animationName(1), "TRS animation");
CORRADE_COMPARE(importer->animationForName("TRS animation"), 1);

auto animation = importer->animation(1);
CORRADE_VERIFY(animation);
CORRADE_VERIFY(animation->importerState());
/* Two rotation keys, four translation and scaling keys with common
time track */
CORRADE_COMPARE(animation->data().size(),
2*(sizeof(Float) + sizeof(Quaternion)) +
4*(sizeof(Float) + 2*sizeof(Vector3)));
CORRADE_COMPARE(animation->trackCount(), 3);

/* Rotation, linearly interpolated */
CORRADE_COMPARE(animation->trackType(0), AnimationTrackType::Quaternion);
CORRADE_COMPARE(animation->trackResultType(0), AnimationTrackType::Quaternion);
CORRADE_COMPARE(animation->trackTarget(0), AnimationTrackTarget::Rotation3D);
CORRADE_COMPARE(animation->trackTargetId(0), 1337);
Animation::TrackView<Float, Quaternion> rotation = animation->track<Quaternion>(0);
CORRADE_COMPARE(rotation.interpolation(), Animation::Interpolation::Linear);
CORRADE_COMPARE(rotation.before(), Animation::Extrapolation::Constant);
CORRADE_COMPARE(rotation.after(), Animation::Extrapolation::Constant);
const Float rotationKeys[]{
1.25f,
2.50f
};
const Quaternion rotationValues[]{
Quaternion::rotation(0.0_degf, Vector3::xAxis()),
Quaternion::rotation(180.0_degf, Vector3::xAxis())
};
CORRADE_COMPARE_AS(rotation.keys(), (Containers::StridedArrayView<const Float>{rotationKeys}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(rotation.values(), (Containers::StridedArrayView<const Quaternion>{rotationValues}), TestSuite::Compare::Container);
CORRADE_COMPARE(rotation.at(1.875f), Quaternion::rotation(90.0_degf, Vector3::xAxis()));

const Float translationScalingKeys[]{
0.0f,
1.25f,
2.5f,
3.75f
};

/* Translation, constant interpolated, sharing keys with scaling */
CORRADE_COMPARE(animation->trackType(1), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackResultType(1), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackTarget(1), AnimationTrackTarget::Translation3D);
CORRADE_COMPARE(animation->trackTargetId(1), 42);
Animation::TrackView<Float, Vector3> translation = animation->track<Vector3>(1);
CORRADE_COMPARE(translation.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(translation.before(), Animation::Extrapolation::Constant);
CORRADE_COMPARE(translation.after(), Animation::Extrapolation::Constant);
const Vector3 translationData[]{
Vector3::yAxis(0.0f),
Vector3::yAxis(2.5f),
Vector3::yAxis(2.5f),
Vector3::yAxis(0.0f)
};
CORRADE_COMPARE_AS(translation.keys(), (Containers::StridedArrayView<const Float>{translationScalingKeys}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(translation.values(), (Containers::StridedArrayView<const Vector3>{translationData}), TestSuite::Compare::Container);
CORRADE_COMPARE(translation.at(1.5f), Vector3::yAxis(2.5f));

/* Scaling, linearly interpolated, sharing keys with translation */
CORRADE_COMPARE(animation->trackType(2), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackResultType(2), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackTarget(2), AnimationTrackTarget::Scaling3D);
CORRADE_COMPARE(animation->trackTargetId(2), 12);
Animation::TrackView<Float, Vector3> scaling = animation->track<Vector3>(2);
CORRADE_COMPARE(scaling.interpolation(), Animation::Interpolation::Linear);
CORRADE_COMPARE(scaling.before(), Animation::Extrapolation::Constant);
CORRADE_COMPARE(scaling.after(), Animation::Extrapolation::Constant);
const Vector3 scalingData[]{
Vector3{1.0f},
Vector3::zScale(5.0f),
Vector3::zScale(6.0f),
Vector3(1.0f),
};
CORRADE_COMPARE_AS(scaling.keys(), (Containers::StridedArrayView<const Float>{translationScalingKeys}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scaling.values(), (Containers::StridedArrayView<const Vector3>{scalingData}), TestSuite::Compare::Container);
CORRADE_COMPARE(scaling.at(1.5f), Vector3::zScale(5.2f));
}
}

void TinyGltfImporterTest::animationWrongTimeType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(0), "wrong time type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(0));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): time track has unexpected type 4/5126\n");
}

void TinyGltfImporterTest::animationWrongInterpolationType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(1), "wrong interpolation type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(1));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): unsupported interpolation QUADRATIC\n");
}

void TinyGltfImporterTest::animationWrongTranslationType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(2), "wrong translation type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(2));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): translation track has unexpected type 4/5126\n");
}

void TinyGltfImporterTest::animationWrongRotationType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(3), "wrong rotation type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(3));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): rotation track has unexpected type 65/5126\n");
}

void TinyGltfImporterTest::animationWrongScalingType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(4), "wrong scaling type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(4));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): scaling track has unexpected type 4/5126\n");
}

void TinyGltfImporterTest::animationUnsupportedPath() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(5), "unsupported path");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(5));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): unsupported track target color\n");
}

void TinyGltfImporterTest::camera() {
auto&& data = SingleFileData[testCaseInstanceId()];
setTestCaseDescription(data.name);
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"asset":{"version":"2.0"},"animations":[{"name":"empty","channels":[],"samplers":[]},{"name":"TRS animation","channels":[{"sampler":0,"target":{"node":1337,"path":"rotation"}},{"sampler":1,"target":{"node":42,"path":"translation"}},{"sampler":2,"target":{"node":12,"path":"scale"}}],"samplers":[{"input":0,"interpolation":"LINEAR","output":1},{"input":2,"interpolation":"STEP","output":3},{"input":2,"interpolation":"LINEAR","output":4}]}],"accessors":[{"bufferView":0,"byteOffset":0,"componentType":5126,"count":2,"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5126,"count":2,"type":"VEC4"},{"bufferView":0,"byteOffset":8,"componentType":5126,"count":4,"type":"SCALAR"},{"bufferView":2,"byteOffset":0,"componentType":5126,"count":4,"type":"VEC3"},{"bufferView":3,"byteOffset":0,"componentType":5126,"count":4,"type":"VEC3"}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":24},{"buffer":0,"byteOffset":24,"byteLength":32},{"buffer":0,"byteOffset":56,"byteLength":48},{"buffer":0,"byteOffset":104,"byteLength":48}],"buffers":[{"byteLength":152,"uri":"data:application/octet-stream;base64,AACgPwAAIEAAAAAAAACgPwAAIEAAAHBAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AACAPwAAoEAAAIA/AACAPwAAwEAAAIA/AACAPwAAgD8="}]}
Loading

0 comments on commit b4bc480

Please sign in to comment.